Line data Source code
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 :
69 : static const bool kLogThreading = false;
70 :
71 : using ::v8::Array;
72 : using ::v8::Boolean;
73 : using ::v8::BooleanObject;
74 : using ::v8::Context;
75 : using ::v8::Extension;
76 : using ::v8::Function;
77 : using ::v8::FunctionTemplate;
78 : using ::v8::HandleScope;
79 : using ::v8::Local;
80 : using ::v8::Maybe;
81 : using ::v8::Message;
82 : using ::v8::MessageCallback;
83 : using ::v8::Module;
84 : using ::v8::Name;
85 : using ::v8::None;
86 : using ::v8::Object;
87 : using ::v8::ObjectTemplate;
88 : using ::v8::Persistent;
89 : using ::v8::PropertyAttribute;
90 : using ::v8::Script;
91 : using ::v8::StackTrace;
92 : using ::v8::String;
93 : using ::v8::Symbol;
94 : using ::v8::TryCatch;
95 : using ::v8::Undefined;
96 : using ::v8::V8;
97 : using ::v8::Value;
98 :
99 :
100 : #define THREADED_PROFILED_TEST(Name) \
101 : static void Test##Name(); \
102 : TEST(Name##WithProfiler) { \
103 : RunWithProfiler(&Test##Name); \
104 : } \
105 : THREADED_TEST(Name)
106 :
107 30 : void RunWithProfiler(void (*test)()) {
108 30 : LocalContext env;
109 60 : v8::HandleScope scope(env->GetIsolate());
110 30 : v8::Local<v8::String> profile_name = v8_str("my_profile1");
111 30 : v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
112 30 : cpu_profiler->StartProfiling(profile_name);
113 30 : (*test)();
114 30 : reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
115 60 : cpu_profiler->Dispose();
116 30 : }
117 :
118 :
119 : static int signature_callback_count;
120 : static Local<Value> signature_expected_receiver;
121 3900 : static void IncrementingSignatureCallback(
122 28080 : const v8::FunctionCallbackInfo<v8::Value>& args) {
123 3900 : ApiTestFuzzer::Fuzz();
124 3900 : signature_callback_count++;
125 11700 : CHECK(signature_expected_receiver->Equals(
126 : args.GetIsolate()->GetCurrentContext(),
127 : args.Holder())
128 : .FromJust());
129 11700 : CHECK(signature_expected_receiver->Equals(
130 : args.GetIsolate()->GetCurrentContext(),
131 : args.This())
132 : .FromJust());
133 : v8::Local<v8::Array> result =
134 3900 : v8::Array::New(args.GetIsolate(), args.Length());
135 10920 : for (int i = 0; i < args.Length(); i++) {
136 6240 : CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
137 : v8::Integer::New(args.GetIsolate(), i), args[i])
138 : .FromJust());
139 : }
140 : args.GetReturnValue().Set(result);
141 3900 : }
142 :
143 :
144 205 : static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
145 : info.GetReturnValue().Set(42);
146 205 : }
147 :
148 :
149 : // Tests that call v8::V8::Dispose() cannot be threaded.
150 25880 : UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
151 5 : CHECK(v8::V8::Initialize());
152 5 : CHECK(v8::V8::Dispose());
153 5 : }
154 :
155 :
156 : // Tests that call v8::V8::Dispose() cannot be threaded.
157 25880 : UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
158 5 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
159 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
160 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
161 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
162 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
163 5 : }
164 :
165 : // Tests that Smi::kZero is set up properly.
166 25885 : UNINITIALIZED_TEST(SmiZero) { CHECK_EQ(i::Smi::kZero, i::Smi::kZero); }
167 :
168 25881 : THREADED_TEST(Handles) {
169 6 : v8::HandleScope scope(CcTest::isolate());
170 : Local<Context> local_env;
171 : {
172 6 : LocalContext env;
173 6 : local_env = env.local();
174 : }
175 :
176 : // Local context should still be live.
177 6 : CHECK(!local_env.IsEmpty());
178 6 : local_env->Enter();
179 :
180 6 : v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
181 6 : CHECK(!undef.IsEmpty());
182 6 : CHECK(undef->IsUndefined());
183 :
184 : const char* source = "1 + 2 + 3";
185 6 : Local<Script> script = v8_compile(source);
186 6 : CHECK_EQ(6, v8_run_int32value(script));
187 :
188 6 : local_env->Exit();
189 6 : }
190 :
191 :
192 25881 : THREADED_TEST(IsolateOfContext) {
193 6 : v8::HandleScope scope(CcTest::isolate());
194 6 : v8::Local<Context> env = Context::New(CcTest::isolate());
195 :
196 6 : CHECK(!env->GetIsolate()->InContext());
197 6 : CHECK(env->GetIsolate() == CcTest::isolate());
198 6 : env->Enter();
199 6 : CHECK(env->GetIsolate()->InContext());
200 6 : CHECK(env->GetIsolate() == CcTest::isolate());
201 6 : env->Exit();
202 6 : CHECK(!env->GetIsolate()->InContext());
203 6 : CHECK(env->GetIsolate() == CcTest::isolate());
204 6 : }
205 :
206 420 : static void TestSignatureLooped(const char* operation, Local<Value> receiver,
207 : v8::Isolate* isolate) {
208 : i::ScopedVector<char> source(200);
209 : i::SNPrintF(source,
210 : "for (var i = 0; i < 10; i++) {"
211 : " %s"
212 : "}",
213 420 : operation);
214 420 : signature_callback_count = 0;
215 420 : signature_expected_receiver = receiver;
216 : bool expected_to_throw = receiver.IsEmpty();
217 840 : v8::TryCatch try_catch(isolate);
218 : CompileRun(source.start());
219 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
220 420 : if (!expected_to_throw) {
221 300 : CHECK_EQ(10, signature_callback_count);
222 : } else {
223 600 : CHECK(v8_str("TypeError: Illegal invocation")
224 : ->Equals(isolate->GetCurrentContext(),
225 : try_catch.Exception()
226 : ->ToString(isolate->GetCurrentContext())
227 : .ToLocalChecked())
228 : .FromJust());
229 : }
230 420 : }
231 :
232 420 : static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
233 : v8::Isolate* isolate) {
234 : i::ScopedVector<char> source(200);
235 : i::SNPrintF(source,
236 : "function test() {"
237 : " %s"
238 : "}"
239 : "try { test() } catch(e) {}"
240 : "try { test() } catch(e) {}"
241 : "%%OptimizeFunctionOnNextCall(test);"
242 : "test()",
243 420 : operation);
244 420 : signature_callback_count = 0;
245 420 : signature_expected_receiver = receiver;
246 : bool expected_to_throw = receiver.IsEmpty();
247 840 : v8::TryCatch try_catch(isolate);
248 : CompileRun(source.start());
249 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
250 420 : if (!expected_to_throw) {
251 300 : CHECK_EQ(3, signature_callback_count);
252 : } else {
253 600 : CHECK(v8_str("TypeError: Illegal invocation")
254 : ->Equals(isolate->GetCurrentContext(),
255 : try_catch.Exception()
256 : ->ToString(isolate->GetCurrentContext())
257 : .ToLocalChecked())
258 : .FromJust());
259 : }
260 420 : }
261 :
262 420 : static void TestSignature(const char* operation, Local<Value> receiver,
263 : v8::Isolate* isolate) {
264 420 : TestSignatureLooped(operation, receiver, isolate);
265 420 : TestSignatureOptimized(operation, receiver, isolate);
266 420 : }
267 :
268 25881 : THREADED_TEST(ReceiverSignature) {
269 6 : i::FLAG_allow_natives_syntax = true;
270 6 : LocalContext env;
271 6 : v8::Isolate* isolate = env->GetIsolate();
272 12 : v8::HandleScope scope(isolate);
273 : // Setup templates.
274 6 : v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
275 6 : v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
276 : v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
277 6 : isolate, IncrementingSignatureCallback, Local<Value>(), sig);
278 : v8::Local<v8::FunctionTemplate> callback =
279 6 : v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
280 6 : v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
281 6 : sub_fun->Inherit(fun);
282 : v8::Local<v8::FunctionTemplate> direct_sub_fun =
283 6 : v8::FunctionTemplate::New(isolate);
284 6 : direct_sub_fun->Inherit(fun);
285 : v8::Local<v8::FunctionTemplate> unrel_fun =
286 6 : v8::FunctionTemplate::New(isolate);
287 : // Install properties.
288 6 : v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
289 12 : fun_proto->Set(v8_str("prop_sig"), callback_sig);
290 12 : fun_proto->Set(v8_str("prop"), callback);
291 : fun_proto->SetAccessorProperty(
292 12 : v8_str("accessor_sig"), callback_sig, callback_sig);
293 12 : fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
294 : // Instantiate templates.
295 : Local<Value> fun_instance =
296 18 : fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
297 : Local<Value> sub_fun_instance =
298 18 : sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
299 : // Instance template with properties.
300 : v8::Local<v8::ObjectTemplate> direct_instance_templ =
301 6 : direct_sub_fun->InstanceTemplate();
302 12 : direct_instance_templ->Set(v8_str("prop_sig"), callback_sig);
303 12 : direct_instance_templ->Set(v8_str("prop"), callback);
304 : direct_instance_templ->SetAccessorProperty(v8_str("accessor_sig"),
305 12 : callback_sig, callback_sig);
306 : direct_instance_templ->SetAccessorProperty(v8_str("accessor"), callback,
307 12 : callback);
308 : Local<Value> direct_instance =
309 6 : direct_instance_templ->NewInstance(env.local()).ToLocalChecked();
310 : // Setup global variables.
311 36 : CHECK(env->Global()
312 : ->Set(env.local(), v8_str("Fun"),
313 : fun->GetFunction(env.local()).ToLocalChecked())
314 : .FromJust());
315 42 : CHECK(env->Global()
316 : ->Set(env.local(), v8_str("UnrelFun"),
317 : unrel_fun->GetFunction(env.local()).ToLocalChecked())
318 : .FromJust());
319 30 : CHECK(env->Global()
320 : ->Set(env.local(), v8_str("fun_instance"), fun_instance)
321 : .FromJust());
322 30 : CHECK(env->Global()
323 : ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
324 : .FromJust());
325 30 : CHECK(env->Global()
326 : ->Set(env.local(), v8_str("direct_instance"), direct_instance)
327 : .FromJust());
328 : CompileRun(
329 : "var accessor_sig_key = 'accessor_sig';"
330 : "var accessor_key = 'accessor';"
331 : "var prop_sig_key = 'prop_sig';"
332 : "var prop_key = 'prop';"
333 : ""
334 : "function copy_props(obj) {"
335 : " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
336 : " var source = Fun.prototype;"
337 : " for (var i in keys) {"
338 : " var key = keys[i];"
339 : " var desc = Object.getOwnPropertyDescriptor(source, key);"
340 : " Object.defineProperty(obj, key, desc);"
341 : " }"
342 : "}"
343 : ""
344 : "var plain = {};"
345 : "copy_props(plain);"
346 : "var unrelated = new UnrelFun();"
347 : "copy_props(unrelated);"
348 : "var inherited = { __proto__: fun_instance };"
349 : "var inherited_direct = { __proto__: direct_instance };");
350 : // Test with and without ICs
351 : const char* test_objects[] = {
352 : "fun_instance", "sub_fun_instance", "direct_instance", "plain",
353 6 : "unrelated", "inherited", "inherited_direct"};
354 : unsigned bad_signature_start_offset = 3;
355 48 : for (unsigned i = 0; i < arraysize(test_objects); i++) {
356 : i::ScopedVector<char> source(200);
357 : i::SNPrintF(
358 42 : source, "var test_object = %s; test_object", test_objects[i]);
359 42 : Local<Value> test_object = CompileRun(source.start());
360 42 : TestSignature("test_object.prop();", test_object, isolate);
361 42 : TestSignature("test_object.accessor;", test_object, isolate);
362 42 : TestSignature("test_object[accessor_key];", test_object, isolate);
363 42 : TestSignature("test_object.accessor = 1;", test_object, isolate);
364 42 : TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
365 42 : if (i >= bad_signature_start_offset) test_object = Local<Value>();
366 42 : TestSignature("test_object.prop_sig();", test_object, isolate);
367 42 : TestSignature("test_object.accessor_sig;", test_object, isolate);
368 42 : TestSignature("test_object[accessor_sig_key];", test_object, isolate);
369 42 : TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
370 42 : TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
371 6 : }
372 6 : }
373 :
374 :
375 25881 : THREADED_TEST(HulIgennem) {
376 6 : LocalContext env;
377 6 : v8::Isolate* isolate = env->GetIsolate();
378 12 : v8::HandleScope scope(isolate);
379 : v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
380 6 : Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
381 6 : char* value = i::NewArray<char>(undef_str->Utf8Length(isolate) + 1);
382 6 : undef_str->WriteUtf8(isolate, value);
383 6 : CHECK_EQ(0, strcmp(value, "undefined"));
384 6 : i::DeleteArray(value);
385 6 : }
386 :
387 :
388 25881 : THREADED_TEST(Access) {
389 6 : LocalContext env;
390 6 : v8::Isolate* isolate = env->GetIsolate();
391 12 : v8::HandleScope scope(isolate);
392 6 : Local<v8::Object> obj = v8::Object::New(isolate);
393 : Local<Value> foo_before =
394 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
395 6 : CHECK(foo_before->IsUndefined());
396 6 : Local<String> bar_str = v8_str("bar");
397 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
398 : Local<Value> foo_after =
399 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
400 6 : CHECK(!foo_after->IsUndefined());
401 6 : CHECK(foo_after->IsString());
402 12 : CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
403 :
404 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).ToChecked());
405 : bool result;
406 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).To(&result));
407 12 : CHECK(result);
408 6 : }
409 :
410 :
411 25881 : THREADED_TEST(AccessElement) {
412 6 : LocalContext env;
413 12 : v8::HandleScope scope(env->GetIsolate());
414 6 : Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
415 6 : Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
416 6 : CHECK(before->IsUndefined());
417 6 : Local<String> bar_str = v8_str("bar");
418 12 : CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
419 6 : Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
420 6 : CHECK(!after->IsUndefined());
421 6 : CHECK(after->IsString());
422 12 : CHECK(bar_str->Equals(env.local(), after).FromJust());
423 :
424 : Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
425 24 : CHECK(v8_str("a")
426 : ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
427 : .FromJust());
428 24 : CHECK(v8_str("b")
429 : ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
430 6 : .FromJust());
431 6 : }
432 :
433 :
434 25881 : THREADED_TEST(Script) {
435 6 : LocalContext env;
436 12 : v8::HandleScope scope(env->GetIsolate());
437 : const char* source = "1 + 2 + 3";
438 6 : Local<Script> script = v8_compile(source);
439 12 : CHECK_EQ(6, v8_run_int32value(script));
440 6 : }
441 :
442 :
443 : class TestResource: public String::ExternalStringResource {
444 : public:
445 : explicit TestResource(uint16_t* data, int* counter = nullptr,
446 : bool owning_data = true)
447 17941 : : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
448 3064640 : while (data[length_]) ++length_;
449 : }
450 :
451 35876 : ~TestResource() override {
452 17941 : if (owning_data_) i::DeleteArray(data_);
453 17941 : if (counter_ != nullptr) ++*counter_;
454 35876 : }
455 :
456 56653 : const uint16_t* data() const override { return data_; }
457 :
458 71698 : size_t length() const override { return length_; }
459 :
460 : private:
461 : uint16_t* data_;
462 : size_t length_;
463 : int* counter_;
464 : bool owning_data_;
465 : };
466 :
467 :
468 : class TestOneByteResource : public String::ExternalOneByteStringResource {
469 : public:
470 : explicit TestOneByteResource(const char* data, int* counter = nullptr,
471 : size_t offset = 0)
472 : : orig_data_(data),
473 10 : data_(data + offset),
474 69 : length_(strlen(data) - offset),
475 148 : counter_(counter) {}
476 :
477 128 : ~TestOneByteResource() override {
478 69 : i::DeleteArray(orig_data_);
479 69 : if (counter_ != nullptr) ++*counter_;
480 128 : }
481 :
482 194 : const char* data() const override { return data_; }
483 :
484 183 : size_t length() const override { return length_; }
485 :
486 : private:
487 : const char* orig_data_;
488 : const char* data_;
489 : size_t length_;
490 : int* counter_;
491 : };
492 :
493 :
494 25881 : THREADED_TEST(ScriptUsingStringResource) {
495 6 : int dispose_count = 0;
496 : const char* c_source = "1 + 2 * 3";
497 6 : uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
498 : {
499 6 : LocalContext env;
500 12 : v8::HandleScope scope(env->GetIsolate());
501 6 : TestResource* resource = new TestResource(two_byte_source, &dispose_count);
502 : Local<String> source =
503 6 : String::NewExternalTwoByte(env->GetIsolate(), resource)
504 6 : .ToLocalChecked();
505 6 : Local<Script> script = v8_compile(source);
506 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
507 6 : CHECK(value->IsNumber());
508 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
509 6 : CHECK(source->IsExternal());
510 6 : CHECK_EQ(resource,
511 : static_cast<TestResource*>(source->GetExternalStringResource()));
512 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
513 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
514 : source->GetExternalStringResourceBase(&encoding));
515 6 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
516 6 : CcTest::CollectAllGarbage();
517 12 : CHECK_EQ(0, dispose_count);
518 : }
519 6 : CcTest::i_isolate()->compilation_cache()->Clear();
520 6 : CcTest::CollectAllAvailableGarbage();
521 6 : CHECK_EQ(1, dispose_count);
522 6 : }
523 :
524 :
525 25881 : THREADED_TEST(ScriptUsingOneByteStringResource) {
526 6 : int dispose_count = 0;
527 : const char* c_source = "1 + 2 * 3";
528 : {
529 6 : LocalContext env;
530 12 : v8::HandleScope scope(env->GetIsolate());
531 : TestOneByteResource* resource =
532 6 : new TestOneByteResource(i::StrDup(c_source), &dispose_count);
533 : Local<String> source =
534 6 : String::NewExternalOneByte(env->GetIsolate(), resource)
535 6 : .ToLocalChecked();
536 6 : CHECK(source->IsExternalOneByte());
537 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
538 : source->GetExternalOneByteStringResource());
539 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
540 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
541 : source->GetExternalStringResourceBase(&encoding));
542 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
543 6 : Local<Script> script = v8_compile(source);
544 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
545 6 : CHECK(value->IsNumber());
546 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
547 6 : CcTest::CollectAllGarbage();
548 12 : CHECK_EQ(0, dispose_count);
549 : }
550 6 : CcTest::i_isolate()->compilation_cache()->Clear();
551 6 : CcTest::CollectAllAvailableGarbage();
552 6 : CHECK_EQ(1, dispose_count);
553 6 : }
554 :
555 :
556 25881 : THREADED_TEST(ScriptMakingExternalString) {
557 6 : int dispose_count = 0;
558 6 : uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
559 : {
560 6 : LocalContext env;
561 12 : v8::HandleScope scope(env->GetIsolate());
562 : Local<String> source =
563 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
564 6 : v8::NewStringType::kNormal)
565 6 : .ToLocalChecked();
566 : // Trigger GCs so that the newly allocated string moves to old gen.
567 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
568 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
569 6 : CHECK(!source->IsExternal());
570 6 : CHECK(!source->IsExternalOneByte());
571 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
572 6 : CHECK(!source->GetExternalStringResourceBase(&encoding));
573 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
574 : bool success = source->MakeExternal(new TestResource(two_byte_source,
575 12 : &dispose_count));
576 6 : CHECK(success);
577 6 : Local<Script> script = v8_compile(source);
578 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
579 6 : CHECK(value->IsNumber());
580 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
581 6 : CcTest::CollectAllGarbage();
582 12 : CHECK_EQ(0, dispose_count);
583 : }
584 6 : CcTest::i_isolate()->compilation_cache()->Clear();
585 6 : CcTest::CollectAllGarbage();
586 6 : CHECK_EQ(1, dispose_count);
587 6 : }
588 :
589 :
590 25881 : THREADED_TEST(ScriptMakingExternalOneByteString) {
591 6 : int dispose_count = 0;
592 : const char* c_source = "1 + 2 * 3";
593 : {
594 6 : LocalContext env;
595 12 : v8::HandleScope scope(env->GetIsolate());
596 6 : Local<String> source = v8_str(c_source);
597 : // Trigger GCs so that the newly allocated string moves to old gen.
598 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
599 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
600 : bool success = source->MakeExternal(
601 12 : new TestOneByteResource(i::StrDup(c_source), &dispose_count));
602 6 : CHECK(success);
603 6 : Local<Script> script = v8_compile(source);
604 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
605 6 : CHECK(value->IsNumber());
606 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
607 6 : CcTest::CollectAllGarbage();
608 12 : CHECK_EQ(0, dispose_count);
609 : }
610 6 : CcTest::i_isolate()->compilation_cache()->Clear();
611 6 : CcTest::CollectAllGarbage();
612 6 : CHECK_EQ(1, dispose_count);
613 6 : }
614 :
615 :
616 25880 : TEST(MakingExternalStringConditions) {
617 5 : LocalContext env;
618 10 : v8::HandleScope scope(env->GetIsolate());
619 :
620 : // Free some space in the new space so that we can check freshness.
621 5 : CcTest::CollectGarbage(i::NEW_SPACE);
622 5 : CcTest::CollectGarbage(i::NEW_SPACE);
623 :
624 5 : uint16_t* two_byte_string = AsciiToTwoByteString("s1");
625 : Local<String> local_string =
626 : String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
627 5 : v8::NewStringType::kNormal)
628 5 : .ToLocalChecked();
629 : i::DeleteArray(two_byte_string);
630 :
631 : // We should refuse to externalize new space strings.
632 5 : CHECK(!local_string->CanMakeExternal());
633 : // Trigger GCs so that the newly allocated string moves to old gen.
634 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
635 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
636 : // Old space strings should be accepted.
637 10 : CHECK(local_string->CanMakeExternal());
638 5 : }
639 :
640 :
641 25880 : TEST(MakingExternalOneByteStringConditions) {
642 5 : LocalContext env;
643 10 : v8::HandleScope scope(env->GetIsolate());
644 :
645 : // Free some space in the new space so that we can check freshness.
646 5 : CcTest::CollectGarbage(i::NEW_SPACE);
647 5 : CcTest::CollectGarbage(i::NEW_SPACE);
648 :
649 5 : Local<String> local_string = v8_str("s1");
650 : // We should refuse to externalize new space strings.
651 5 : CHECK(!local_string->CanMakeExternal());
652 : // Trigger GCs so that the newly allocated string moves to old gen.
653 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
654 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
655 : // Old space strings should be accepted.
656 10 : CHECK(local_string->CanMakeExternal());
657 5 : }
658 :
659 :
660 25880 : TEST(MakingExternalUnalignedOneByteString) {
661 5 : LocalContext env;
662 10 : v8::HandleScope scope(env->GetIsolate());
663 :
664 : CompileRun("function cons(a, b) { return a + b; }"
665 : "function slice(a) { return a.substring(1); }");
666 : // Create a cons string that will land in old pointer space.
667 : Local<String> cons = Local<String>::Cast(CompileRun(
668 : "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
669 : // Create a sliced string that will land in old pointer space.
670 : Local<String> slice = Local<String>::Cast(CompileRun(
671 : "slice('abcdefghijklmnopqrstuvwxyz');"));
672 :
673 : // Trigger GCs so that the newly allocated string moves to old gen.
674 5 : i::heap::SimulateFullSpace(CcTest::heap()->old_space());
675 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
676 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
677 :
678 : // Turn into external string with unaligned resource data.
679 : const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
680 : bool success = cons->MakeExternal(
681 10 : new TestOneByteResource(i::StrDup(c_cons), nullptr, 1));
682 5 : CHECK(success);
683 : const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
684 : success = slice->MakeExternal(
685 10 : new TestOneByteResource(i::StrDup(c_slice), nullptr, 1));
686 5 : CHECK(success);
687 :
688 : // Trigger GCs and force evacuation.
689 5 : CcTest::CollectAllGarbage();
690 : CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask,
691 10 : i::GarbageCollectionReason::kTesting);
692 5 : }
693 :
694 25881 : THREADED_TEST(UsingExternalString) {
695 : i::Factory* factory = CcTest::i_isolate()->factory();
696 : {
697 6 : v8::HandleScope scope(CcTest::isolate());
698 6 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
699 : Local<String> string =
700 : String::NewExternalTwoByte(CcTest::isolate(),
701 12 : new TestResource(two_byte_string))
702 6 : .ToLocalChecked();
703 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
704 : // Trigger GCs so that the newly allocated string moves to old gen.
705 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
706 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
707 : i::Handle<i::String> isymbol =
708 6 : factory->InternalizeString(istring);
709 12 : CHECK(isymbol->IsInternalizedString());
710 : }
711 6 : CcTest::CollectAllGarbage();
712 6 : CcTest::CollectAllGarbage();
713 6 : }
714 :
715 :
716 25881 : THREADED_TEST(UsingExternalOneByteString) {
717 : i::Factory* factory = CcTest::i_isolate()->factory();
718 : {
719 6 : v8::HandleScope scope(CcTest::isolate());
720 : const char* one_byte_string = "test string";
721 : Local<String> string =
722 : String::NewExternalOneByte(
723 : CcTest::isolate(),
724 12 : new TestOneByteResource(i::StrDup(one_byte_string)))
725 6 : .ToLocalChecked();
726 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
727 : // Trigger GCs so that the newly allocated string moves to old gen.
728 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
729 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
730 : i::Handle<i::String> isymbol =
731 6 : factory->InternalizeString(istring);
732 12 : CHECK(isymbol->IsInternalizedString());
733 : }
734 6 : CcTest::CollectAllGarbage();
735 6 : CcTest::CollectAllGarbage();
736 6 : }
737 :
738 :
739 6 : class RandomLengthResource : public v8::String::ExternalStringResource {
740 : public:
741 6 : explicit RandomLengthResource(int length) : length_(length) {}
742 6 : const uint16_t* data() const override { return string_; }
743 6 : size_t length() const override { return length_; }
744 :
745 : private:
746 : uint16_t string_[10];
747 : int length_;
748 : };
749 :
750 :
751 16 : class RandomLengthOneByteResource
752 : : public v8::String::ExternalOneByteStringResource {
753 : public:
754 11 : explicit RandomLengthOneByteResource(int length) : length_(length) {}
755 16 : const char* data() const override { return string_; }
756 26 : size_t length() const override { return length_; }
757 :
758 : private:
759 : char string_[10];
760 : int length_;
761 : };
762 :
763 :
764 25881 : THREADED_TEST(NewExternalForVeryLongString) {
765 6 : auto isolate = CcTest::isolate();
766 : {
767 6 : v8::HandleScope scope(isolate);
768 12 : v8::TryCatch try_catch(isolate);
769 : RandomLengthOneByteResource r(1 << 30);
770 : v8::MaybeLocal<v8::String> maybe_str =
771 6 : v8::String::NewExternalOneByte(isolate, &r);
772 6 : CHECK(maybe_str.IsEmpty());
773 12 : CHECK(!try_catch.HasCaught());
774 : }
775 :
776 : {
777 6 : v8::HandleScope scope(isolate);
778 12 : v8::TryCatch try_catch(isolate);
779 : RandomLengthResource r(1 << 30);
780 : v8::MaybeLocal<v8::String> maybe_str =
781 6 : v8::String::NewExternalTwoByte(isolate, &r);
782 6 : CHECK(maybe_str.IsEmpty());
783 12 : CHECK(!try_catch.HasCaught());
784 : }
785 6 : }
786 :
787 25880 : TEST(ScavengeExternalString) {
788 : ManualGCScope manual_gc_scope;
789 5 : i::FLAG_stress_compaction = false;
790 5 : i::FLAG_gc_global = false;
791 5 : int dispose_count = 0;
792 : bool in_young_generation = false;
793 : {
794 5 : v8::HandleScope scope(CcTest::isolate());
795 5 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
796 : Local<String> string =
797 : String::NewExternalTwoByte(
798 : CcTest::isolate(),
799 10 : new TestResource(two_byte_string, &dispose_count))
800 5 : .ToLocalChecked();
801 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
802 5 : CcTest::CollectGarbage(i::NEW_SPACE);
803 : in_young_generation = i::Heap::InYoungGeneration(*istring);
804 10 : CHECK_IMPLIES(!in_young_generation,
805 : CcTest::heap()->old_space()->Contains(*istring));
806 5 : CHECK_EQ(0, dispose_count);
807 : }
808 5 : CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
809 5 : CHECK_EQ(1, dispose_count);
810 5 : }
811 :
812 25880 : TEST(ScavengeExternalOneByteString) {
813 : ManualGCScope manual_gc_scope;
814 5 : i::FLAG_stress_compaction = false;
815 5 : i::FLAG_gc_global = false;
816 5 : int dispose_count = 0;
817 : bool in_young_generation = false;
818 : {
819 5 : v8::HandleScope scope(CcTest::isolate());
820 : const char* one_byte_string = "test string";
821 : Local<String> string =
822 : String::NewExternalOneByte(
823 : CcTest::isolate(),
824 10 : new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
825 5 : .ToLocalChecked();
826 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
827 5 : CcTest::CollectGarbage(i::NEW_SPACE);
828 : in_young_generation = i::Heap::InYoungGeneration(*istring);
829 10 : CHECK_IMPLIES(!in_young_generation,
830 : CcTest::heap()->old_space()->Contains(*istring));
831 5 : CHECK_EQ(0, dispose_count);
832 : }
833 5 : CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
834 5 : CHECK_EQ(1, dispose_count);
835 5 : }
836 :
837 :
838 10 : class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
839 : public:
840 : // Only used by non-threaded tests, so it can use static fields.
841 : static int dispose_calls;
842 : static int dispose_count;
843 :
844 : TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
845 10 : : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
846 :
847 10 : void Dispose() override {
848 10 : ++dispose_calls;
849 10 : if (dispose_) delete this;
850 10 : }
851 : private:
852 : bool dispose_;
853 : };
854 :
855 :
856 : int TestOneByteResourceWithDisposeControl::dispose_count = 0;
857 : int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
858 :
859 :
860 25880 : TEST(ExternalStringWithDisposeHandling) {
861 : const char* c_source = "1 + 2 * 3";
862 :
863 : // Use a stack allocated external string resource allocated object.
864 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
865 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
866 5 : TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
867 : {
868 5 : LocalContext env;
869 10 : v8::HandleScope scope(env->GetIsolate());
870 : Local<String> source =
871 5 : String::NewExternalOneByte(env->GetIsolate(), &res_stack)
872 10 : .ToLocalChecked();
873 5 : Local<Script> script = v8_compile(source);
874 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
875 5 : CHECK(value->IsNumber());
876 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
877 5 : CcTest::CollectAllAvailableGarbage();
878 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
879 : }
880 5 : CcTest::i_isolate()->compilation_cache()->Clear();
881 5 : CcTest::CollectAllAvailableGarbage();
882 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
883 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
884 :
885 : // Use a heap allocated external string resource allocated object.
886 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
887 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
888 : TestOneByteResource* res_heap =
889 5 : new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
890 : {
891 5 : LocalContext env;
892 10 : v8::HandleScope scope(env->GetIsolate());
893 : Local<String> source =
894 5 : String::NewExternalOneByte(env->GetIsolate(), res_heap)
895 10 : .ToLocalChecked();
896 5 : Local<Script> script = v8_compile(source);
897 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
898 5 : CHECK(value->IsNumber());
899 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
900 5 : CcTest::CollectAllAvailableGarbage();
901 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
902 : }
903 5 : CcTest::i_isolate()->compilation_cache()->Clear();
904 5 : CcTest::CollectAllAvailableGarbage();
905 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
906 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
907 5 : }
908 :
909 :
910 25881 : THREADED_TEST(StringConcat) {
911 : {
912 6 : LocalContext env;
913 6 : v8::Isolate* isolate = env->GetIsolate();
914 12 : v8::HandleScope scope(isolate);
915 : const char* one_byte_string_1 = "function a_times_t";
916 : const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
917 : const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
918 : const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
919 : const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
920 : const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
921 : const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
922 6 : Local<String> left = v8_str(one_byte_string_1);
923 :
924 6 : uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
925 : Local<String> right =
926 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
927 6 : v8::NewStringType::kNormal)
928 12 : .ToLocalChecked();
929 : i::DeleteArray(two_byte_source);
930 :
931 6 : Local<String> source = String::Concat(isolate, left, right);
932 : right = String::NewExternalOneByte(
933 : env->GetIsolate(),
934 12 : new TestOneByteResource(i::StrDup(one_byte_extern_1)))
935 12 : .ToLocalChecked();
936 6 : source = String::Concat(isolate, source, right);
937 : right = String::NewExternalTwoByte(
938 : env->GetIsolate(),
939 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
940 12 : .ToLocalChecked();
941 6 : source = String::Concat(isolate, source, right);
942 6 : right = v8_str(one_byte_string_2);
943 6 : source = String::Concat(isolate, source, right);
944 :
945 6 : two_byte_source = AsciiToTwoByteString(two_byte_string_2);
946 : right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
947 6 : v8::NewStringType::kNormal)
948 12 : .ToLocalChecked();
949 : i::DeleteArray(two_byte_source);
950 :
951 6 : source = String::Concat(isolate, source, right);
952 : right = String::NewExternalTwoByte(
953 : env->GetIsolate(),
954 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
955 12 : .ToLocalChecked();
956 6 : source = String::Concat(isolate, source, right);
957 6 : Local<Script> script = v8_compile(source);
958 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
959 6 : CHECK(value->IsNumber());
960 18 : CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
961 : }
962 6 : CcTest::i_isolate()->compilation_cache()->Clear();
963 6 : CcTest::CollectAllGarbage();
964 6 : CcTest::CollectAllGarbage();
965 6 : }
966 :
967 :
968 25881 : THREADED_TEST(GlobalProperties) {
969 6 : LocalContext env;
970 12 : v8::HandleScope scope(env->GetIsolate());
971 6 : v8::Local<v8::Object> global = env->Global();
972 18 : CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
973 18 : Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
974 18 : CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
975 6 : }
976 :
977 :
978 1980 : static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
979 : i::Address callback) {
980 660 : ApiTestFuzzer::Fuzz();
981 660 : CheckReturnValue(info, callback);
982 660 : info.GetReturnValue().Set(v8_str("bad value"));
983 660 : info.GetReturnValue().Set(v8_num(102));
984 660 : }
985 :
986 :
987 330 : static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
988 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
989 : }
990 :
991 :
992 330 : static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
993 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
994 : }
995 :
996 22 : static void construct_callback(
997 154 : const v8::FunctionCallbackInfo<Value>& info) {
998 22 : ApiTestFuzzer::Fuzz();
999 22 : CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1000 88 : CHECK(
1001 : info.This()
1002 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
1003 : .FromJust());
1004 88 : CHECK(
1005 : info.This()
1006 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
1007 : .FromJust());
1008 22 : info.GetReturnValue().Set(v8_str("bad value"));
1009 : info.GetReturnValue().Set(info.This());
1010 22 : }
1011 :
1012 :
1013 330 : static void Return239Callback(
1014 : Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1015 330 : ApiTestFuzzer::Fuzz();
1016 330 : CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1017 330 : info.GetReturnValue().Set(v8_str("bad value"));
1018 330 : info.GetReturnValue().Set(v8_num(239));
1019 330 : }
1020 :
1021 :
1022 : template<typename Handler>
1023 11 : static void TestFunctionTemplateInitializer(Handler handler,
1024 : Handler handler_2) {
1025 : // Test constructor calls.
1026 : {
1027 11 : LocalContext env;
1028 11 : v8::Isolate* isolate = env->GetIsolate();
1029 22 : v8::HandleScope scope(isolate);
1030 :
1031 : Local<v8::FunctionTemplate> fun_templ =
1032 11 : v8::FunctionTemplate::New(isolate, handler);
1033 22 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1034 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1035 11 : Local<Script> script = v8_compile("obj()");
1036 341 : for (int i = 0; i < 30; i++) {
1037 330 : CHECK_EQ(102, v8_run_int32value(script));
1038 11 : }
1039 : }
1040 : // Use SetCallHandler to initialize a function template, should work like
1041 : // the previous one.
1042 : {
1043 11 : LocalContext env;
1044 11 : v8::Isolate* isolate = env->GetIsolate();
1045 22 : v8::HandleScope scope(isolate);
1046 :
1047 11 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1048 11 : fun_templ->SetCallHandler(handler_2);
1049 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1050 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1051 11 : Local<Script> script = v8_compile("obj()");
1052 341 : for (int i = 0; i < 30; i++) {
1053 330 : CHECK_EQ(102, v8_run_int32value(script));
1054 11 : }
1055 : }
1056 11 : }
1057 :
1058 :
1059 : template<typename Constructor, typename Accessor>
1060 11 : static void TestFunctionTemplateAccessor(Constructor constructor,
1061 : Accessor accessor) {
1062 11 : LocalContext env;
1063 22 : v8::HandleScope scope(env->GetIsolate());
1064 :
1065 : Local<v8::FunctionTemplate> fun_templ =
1066 11 : v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1067 11 : fun_templ->SetClassName(v8_str("funky"));
1068 22 : fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1069 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1070 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1071 : Local<Value> result =
1072 33 : v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1073 33 : CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1074 : CompileRun("var obj_instance = new obj();");
1075 : Local<Script> script;
1076 11 : script = v8_compile("obj_instance.x");
1077 341 : for (int i = 0; i < 30; i++) {
1078 330 : CHECK_EQ(1, v8_run_int32value(script));
1079 : }
1080 11 : script = v8_compile("obj_instance.m");
1081 341 : for (int i = 0; i < 30; i++) {
1082 330 : CHECK_EQ(239, v8_run_int32value(script));
1083 11 : }
1084 11 : }
1085 :
1086 :
1087 51766 : THREADED_PROFILED_TEST(FunctionTemplate) {
1088 11 : TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1089 11 : TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1090 11 : }
1091 :
1092 18 : static void FunctionCallbackForProxyTest(
1093 36 : const v8::FunctionCallbackInfo<Value>& info) {
1094 : info.GetReturnValue().Set(info.This());
1095 18 : }
1096 :
1097 25881 : THREADED_TEST(FunctionTemplateWithProxy) {
1098 6 : LocalContext env;
1099 6 : v8::Isolate* isolate = env->GetIsolate();
1100 12 : v8::HandleScope scope(isolate);
1101 :
1102 : v8::Local<v8::FunctionTemplate> function_template =
1103 6 : v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
1104 : v8::Local<v8::Function> function =
1105 12 : function_template->GetFunction(env.local()).ToLocalChecked();
1106 30 : CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
1107 : v8::Local<v8::Value> proxy =
1108 : CompileRun("var proxy = new Proxy({}, {}); proxy");
1109 6 : CHECK(proxy->IsProxy());
1110 :
1111 : v8::Local<v8::Value> result = CompileRun("f(proxy)");
1112 18 : CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());
1113 :
1114 : result = CompileRun("f.call(proxy)");
1115 12 : CHECK(result->Equals(env.local(), proxy).FromJust());
1116 :
1117 : result = CompileRun("Reflect.apply(f, proxy, [1])");
1118 18 : CHECK(result->Equals(env.local(), proxy).FromJust());
1119 6 : }
1120 :
1121 1980 : static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1122 660 : ApiTestFuzzer::Fuzz();
1123 660 : CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1124 660 : info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1125 660 : }
1126 :
1127 :
1128 : template<typename Callback>
1129 11 : static void TestSimpleCallback(Callback callback) {
1130 11 : LocalContext env;
1131 11 : v8::Isolate* isolate = env->GetIsolate();
1132 22 : v8::HandleScope scope(isolate);
1133 :
1134 : v8::Local<v8::ObjectTemplate> object_template =
1135 11 : v8::ObjectTemplate::New(isolate);
1136 22 : object_template->Set(isolate, "callback",
1137 : v8::FunctionTemplate::New(isolate, callback));
1138 : v8::Local<v8::Object> object =
1139 11 : object_template->NewInstance(env.local()).ToLocalChecked();
1140 55 : CHECK((*env)
1141 : ->Global()
1142 : ->Set(env.local(), v8_str("callback_object"), object)
1143 : .FromJust());
1144 : v8::Local<v8::Script> script;
1145 11 : script = v8_compile("callback_object.callback(17)");
1146 341 : for (int i = 0; i < 30; i++) {
1147 330 : CHECK_EQ(51424, v8_run_int32value(script));
1148 : }
1149 11 : script = v8_compile("callback_object.callback(17, 24)");
1150 341 : for (int i = 0; i < 30; i++) {
1151 330 : CHECK_EQ(51425, v8_run_int32value(script));
1152 11 : }
1153 11 : }
1154 :
1155 :
1156 51766 : THREADED_PROFILED_TEST(SimpleCallback) {
1157 11 : TestSimpleCallback(SimpleCallback);
1158 11 : }
1159 :
1160 :
1161 : template<typename T>
1162 : void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1163 :
1164 : // constant return values
1165 : static int32_t fast_return_value_int32 = 471;
1166 : static uint32_t fast_return_value_uint32 = 571;
1167 : static const double kFastReturnValueDouble = 2.7;
1168 : // variable return values
1169 : static bool fast_return_value_bool = false;
1170 : enum ReturnValueOddball {
1171 : kNullReturnValue,
1172 : kUndefinedReturnValue,
1173 : kEmptyStringReturnValue
1174 : };
1175 : static ReturnValueOddball fast_return_value_void;
1176 : static bool fast_return_value_object_is_empty = false;
1177 :
1178 : // Helper function to avoid compiler error: insufficient contextual information
1179 : // to determine type when applying FUNCTION_ADDR to a template function.
1180 : static i::Address address_of(v8::FunctionCallback callback) {
1181 396 : return FUNCTION_ADDR(callback);
1182 : }
1183 :
1184 : template<>
1185 165 : void FastReturnValueCallback<int32_t>(
1186 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1187 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1188 165 : info.GetReturnValue().Set(fast_return_value_int32);
1189 165 : }
1190 :
1191 : template<>
1192 165 : void FastReturnValueCallback<uint32_t>(
1193 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1194 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1195 165 : info.GetReturnValue().Set(fast_return_value_uint32);
1196 165 : }
1197 :
1198 : template<>
1199 11 : void FastReturnValueCallback<double>(
1200 11 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1201 11 : CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1202 : info.GetReturnValue().Set(kFastReturnValueDouble);
1203 11 : }
1204 :
1205 : template<>
1206 22 : void FastReturnValueCallback<bool>(
1207 22 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1208 22 : CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1209 22 : info.GetReturnValue().Set(fast_return_value_bool);
1210 22 : }
1211 :
1212 : template<>
1213 33 : void FastReturnValueCallback<void>(
1214 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1215 33 : CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1216 33 : switch (fast_return_value_void) {
1217 : case kNullReturnValue:
1218 : info.GetReturnValue().SetNull();
1219 11 : break;
1220 : case kUndefinedReturnValue:
1221 : info.GetReturnValue().SetUndefined();
1222 11 : break;
1223 : case kEmptyStringReturnValue:
1224 : info.GetReturnValue().SetEmptyString();
1225 11 : break;
1226 : }
1227 33 : }
1228 :
1229 : template<>
1230 22 : void FastReturnValueCallback<Object>(
1231 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1232 : v8::Local<v8::Object> object;
1233 22 : if (!fast_return_value_object_is_empty) {
1234 11 : object = Object::New(info.GetIsolate());
1235 : }
1236 : info.GetReturnValue().Set(object);
1237 22 : }
1238 :
1239 : template <typename T>
1240 418 : Local<Value> TestFastReturnValues() {
1241 418 : LocalContext env;
1242 418 : v8::Isolate* isolate = env->GetIsolate();
1243 418 : v8::EscapableHandleScope scope(isolate);
1244 : v8::Local<v8::ObjectTemplate> object_template =
1245 418 : v8::ObjectTemplate::New(isolate);
1246 : v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1247 : object_template->Set(isolate, "callback",
1248 836 : v8::FunctionTemplate::New(isolate, callback));
1249 : v8::Local<v8::Object> object =
1250 418 : object_template->NewInstance(env.local()).ToLocalChecked();
1251 2090 : CHECK((*env)
1252 : ->Global()
1253 : ->Set(env.local(), v8_str("callback_object"), object)
1254 : .FromJust());
1255 418 : return scope.Escape(CompileRun("callback_object.callback()"));
1256 : }
1257 :
1258 :
1259 51766 : THREADED_PROFILED_TEST(FastReturnValues) {
1260 11 : LocalContext env;
1261 11 : v8::Isolate* isolate = env->GetIsolate();
1262 22 : v8::HandleScope scope(isolate);
1263 : v8::Local<v8::Value> value;
1264 : // check int32_t and uint32_t
1265 : int32_t int_values[] = {
1266 : 0, 234, -723,
1267 : i::Smi::kMinValue, i::Smi::kMaxValue
1268 11 : };
1269 66 : for (size_t i = 0; i < arraysize(int_values); i++) {
1270 165 : for (int modifier = -1; modifier <= 1; modifier++) {
1271 165 : int int_value = v8::base::AddWithWraparound(int_values[i], modifier);
1272 : // check int32_t
1273 165 : fast_return_value_int32 = int_value;
1274 165 : value = TestFastReturnValues<int32_t>();
1275 165 : CHECK(value->IsInt32());
1276 330 : CHECK_EQ(fast_return_value_int32,
1277 : value->Int32Value(env.local()).FromJust());
1278 : // check uint32_t
1279 165 : fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1280 165 : value = TestFastReturnValues<uint32_t>();
1281 165 : CHECK(value->IsUint32());
1282 330 : CHECK_EQ(fast_return_value_uint32,
1283 : value->Uint32Value(env.local()).FromJust());
1284 : }
1285 : }
1286 : // check double
1287 11 : value = TestFastReturnValues<double>();
1288 11 : CHECK(value->IsNumber());
1289 22 : CHECK_EQ(kFastReturnValueDouble,
1290 : value->ToNumber(env.local()).ToLocalChecked()->Value());
1291 : // check bool values
1292 22 : for (int i = 0; i < 2; i++) {
1293 22 : fast_return_value_bool = i == 0;
1294 22 : value = TestFastReturnValues<bool>();
1295 22 : CHECK(value->IsBoolean());
1296 22 : CHECK_EQ(fast_return_value_bool, value->BooleanValue(isolate));
1297 : }
1298 : // check oddballs
1299 : ReturnValueOddball oddballs[] = {
1300 : kNullReturnValue,
1301 : kUndefinedReturnValue,
1302 : kEmptyStringReturnValue
1303 11 : };
1304 44 : for (size_t i = 0; i < arraysize(oddballs); i++) {
1305 33 : fast_return_value_void = oddballs[i];
1306 33 : value = TestFastReturnValues<void>();
1307 33 : switch (fast_return_value_void) {
1308 : case kNullReturnValue:
1309 11 : CHECK(value->IsNull());
1310 : break;
1311 : case kUndefinedReturnValue:
1312 11 : CHECK(value->IsUndefined());
1313 : break;
1314 : case kEmptyStringReturnValue:
1315 11 : CHECK(value->IsString());
1316 11 : CHECK_EQ(0, v8::String::Cast(*value)->Length());
1317 : break;
1318 : }
1319 : }
1320 : // check handles
1321 11 : fast_return_value_object_is_empty = false;
1322 11 : value = TestFastReturnValues<Object>();
1323 11 : CHECK(value->IsObject());
1324 11 : fast_return_value_object_is_empty = true;
1325 11 : value = TestFastReturnValues<Object>();
1326 22 : CHECK(value->IsUndefined());
1327 11 : }
1328 :
1329 :
1330 25881 : THREADED_TEST(FunctionTemplateSetLength) {
1331 6 : LocalContext env;
1332 6 : v8::Isolate* isolate = env->GetIsolate();
1333 12 : v8::HandleScope scope(isolate);
1334 : {
1335 : Local<v8::FunctionTemplate> fun_templ =
1336 : v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1337 6 : Local<v8::Signature>(), 23);
1338 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1339 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1340 6 : Local<Script> script = v8_compile("obj.length");
1341 6 : CHECK_EQ(23, v8_run_int32value(script));
1342 : }
1343 : {
1344 : Local<v8::FunctionTemplate> fun_templ =
1345 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1346 6 : fun_templ->SetLength(22);
1347 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1348 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1349 6 : Local<Script> script = v8_compile("obj.length");
1350 6 : CHECK_EQ(22, v8_run_int32value(script));
1351 : }
1352 : {
1353 : // Without setting length it defaults to 0.
1354 : Local<v8::FunctionTemplate> fun_templ =
1355 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1356 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1357 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1358 6 : Local<Script> script = v8_compile("obj.length");
1359 6 : CHECK_EQ(0, v8_run_int32value(script));
1360 6 : }
1361 6 : }
1362 :
1363 :
1364 : static void* expected_ptr;
1365 16848 : static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1366 8424 : void* ptr = v8::External::Cast(*args.Data())->Value();
1367 8424 : CHECK_EQ(expected_ptr, ptr);
1368 : args.GetReturnValue().Set(true);
1369 8424 : }
1370 :
1371 :
1372 648 : static void TestExternalPointerWrapping() {
1373 648 : LocalContext env;
1374 648 : v8::Isolate* isolate = env->GetIsolate();
1375 1296 : v8::HandleScope scope(isolate);
1376 :
1377 648 : v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1378 :
1379 648 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
1380 4536 : CHECK(obj->Set(env.local(), v8_str("func"),
1381 : v8::FunctionTemplate::New(isolate, callback, data)
1382 : ->GetFunction(env.local())
1383 : .ToLocalChecked())
1384 : .FromJust());
1385 3240 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1386 :
1387 648 : CHECK(CompileRun("function foo() {\n"
1388 : " for (var i = 0; i < 13; i++) obj.func();\n"
1389 : "}\n"
1390 : "foo(), true")
1391 648 : ->BooleanValue(isolate));
1392 648 : }
1393 :
1394 :
1395 25881 : THREADED_TEST(ExternalWrap) {
1396 : // Check heap allocated object.
1397 6 : int* ptr = new int;
1398 6 : expected_ptr = ptr;
1399 6 : TestExternalPointerWrapping();
1400 6 : delete ptr;
1401 :
1402 : // Check stack allocated object.
1403 : int foo;
1404 6 : expected_ptr = &foo;
1405 6 : TestExternalPointerWrapping();
1406 :
1407 : // Check not aligned addresses.
1408 : const int n = 100;
1409 6 : char* s = new char[n];
1410 606 : for (int i = 0; i < n; i++) {
1411 600 : expected_ptr = s + i;
1412 600 : TestExternalPointerWrapping();
1413 : }
1414 :
1415 6 : delete[] s;
1416 :
1417 : // Check several invalid addresses.
1418 6 : expected_ptr = reinterpret_cast<void*>(1);
1419 6 : TestExternalPointerWrapping();
1420 :
1421 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF);
1422 6 : TestExternalPointerWrapping();
1423 :
1424 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF + 1);
1425 6 : TestExternalPointerWrapping();
1426 :
1427 : #if defined(V8_HOST_ARCH_X64)
1428 : // Check a value with a leading 1 bit in x64 Smi encoding.
1429 6 : expected_ptr = reinterpret_cast<void*>(0x400000000);
1430 6 : TestExternalPointerWrapping();
1431 :
1432 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF);
1433 6 : TestExternalPointerWrapping();
1434 :
1435 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF + 1);
1436 6 : TestExternalPointerWrapping();
1437 : #endif
1438 6 : }
1439 :
1440 :
1441 25881 : THREADED_TEST(FindInstanceInPrototypeChain) {
1442 6 : LocalContext env;
1443 6 : v8::Isolate* isolate = env->GetIsolate();
1444 12 : v8::HandleScope scope(isolate);
1445 :
1446 6 : Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1447 6 : Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1448 6 : Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1449 6 : derived->Inherit(base);
1450 :
1451 : Local<v8::Function> base_function =
1452 12 : base->GetFunction(env.local()).ToLocalChecked();
1453 : Local<v8::Function> derived_function =
1454 6 : derived->GetFunction(env.local()).ToLocalChecked();
1455 : Local<v8::Function> other_function =
1456 12 : other->GetFunction(env.local()).ToLocalChecked();
1457 :
1458 : Local<v8::Object> base_instance =
1459 6 : base_function->NewInstance(env.local()).ToLocalChecked();
1460 : Local<v8::Object> derived_instance =
1461 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1462 : Local<v8::Object> derived_instance2 =
1463 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1464 : Local<v8::Object> other_instance =
1465 6 : other_function->NewInstance(env.local()).ToLocalChecked();
1466 18 : CHECK(
1467 : derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1468 : .FromJust());
1469 18 : CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1470 : .FromJust());
1471 :
1472 : // base_instance is only an instance of base.
1473 18 : CHECK(base_instance->Equals(env.local(),
1474 : base_instance->FindInstanceInPrototypeChain(base))
1475 : .FromJust());
1476 12 : CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1477 12 : CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1478 :
1479 : // derived_instance is an instance of base and derived.
1480 18 : CHECK(derived_instance->Equals(env.local(),
1481 : derived_instance->FindInstanceInPrototypeChain(
1482 : base))
1483 : .FromJust());
1484 18 : CHECK(derived_instance->Equals(env.local(),
1485 : derived_instance->FindInstanceInPrototypeChain(
1486 : derived))
1487 : .FromJust());
1488 12 : CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1489 :
1490 : // other_instance is an instance of other and its immediate
1491 : // prototype derived_instance2 is an instance of base and derived.
1492 : // Note, derived_instance is an instance of base and derived too,
1493 : // but it comes after derived_instance2 in the prototype chain of
1494 : // other_instance.
1495 18 : CHECK(derived_instance2->Equals(
1496 : env.local(),
1497 : other_instance->FindInstanceInPrototypeChain(base))
1498 : .FromJust());
1499 18 : CHECK(derived_instance2->Equals(env.local(),
1500 : other_instance->FindInstanceInPrototypeChain(
1501 : derived))
1502 : .FromJust());
1503 18 : CHECK(other_instance->Equals(
1504 : env.local(),
1505 : other_instance->FindInstanceInPrototypeChain(other))
1506 6 : .FromJust());
1507 6 : }
1508 :
1509 :
1510 25881 : THREADED_TEST(TinyInteger) {
1511 6 : LocalContext env;
1512 6 : v8::Isolate* isolate = env->GetIsolate();
1513 12 : v8::HandleScope scope(isolate);
1514 :
1515 : int32_t value = 239;
1516 6 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1517 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1518 6 : }
1519 :
1520 :
1521 25881 : THREADED_TEST(BigSmiInteger) {
1522 6 : LocalContext env;
1523 12 : v8::HandleScope scope(env->GetIsolate());
1524 6 : v8::Isolate* isolate = CcTest::isolate();
1525 :
1526 : int32_t value = i::Smi::kMaxValue;
1527 : // We cannot add one to a Smi::kMaxValue without wrapping.
1528 : if (i::SmiValuesAre31Bits()) {
1529 : CHECK(i::Smi::IsValid(value));
1530 : CHECK(!i::Smi::IsValid(value + 1));
1531 :
1532 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1533 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1534 6 : }
1535 6 : }
1536 :
1537 :
1538 25881 : THREADED_TEST(BigInteger) {
1539 6 : LocalContext env;
1540 12 : v8::HandleScope scope(env->GetIsolate());
1541 6 : v8::Isolate* isolate = CcTest::isolate();
1542 :
1543 : // We cannot add one to a Smi::kMaxValue without wrapping.
1544 : if (i::SmiValuesAre31Bits()) {
1545 : // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1546 : // The code will not be run in that case, due to the "if" guard.
1547 : int32_t value =
1548 : static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1549 : CHECK_GT(value, i::Smi::kMaxValue);
1550 : CHECK(!i::Smi::IsValid(value));
1551 :
1552 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1553 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1554 6 : }
1555 6 : }
1556 :
1557 :
1558 25881 : THREADED_TEST(TinyUnsignedInteger) {
1559 6 : LocalContext env;
1560 12 : v8::HandleScope scope(env->GetIsolate());
1561 6 : v8::Isolate* isolate = CcTest::isolate();
1562 :
1563 : uint32_t value = 239;
1564 :
1565 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1566 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1567 6 : }
1568 :
1569 :
1570 25881 : THREADED_TEST(BigUnsignedSmiInteger) {
1571 6 : LocalContext env;
1572 12 : v8::HandleScope scope(env->GetIsolate());
1573 6 : v8::Isolate* isolate = CcTest::isolate();
1574 :
1575 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1576 : CHECK(i::Smi::IsValid(value));
1577 : CHECK(!i::Smi::IsValid(value + 1));
1578 :
1579 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1580 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1581 6 : }
1582 :
1583 :
1584 25881 : THREADED_TEST(BigUnsignedInteger) {
1585 6 : LocalContext env;
1586 12 : v8::HandleScope scope(env->GetIsolate());
1587 6 : v8::Isolate* isolate = CcTest::isolate();
1588 :
1589 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1590 : CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1591 : CHECK(!i::Smi::IsValid(value));
1592 :
1593 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1594 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1595 6 : }
1596 :
1597 :
1598 25881 : THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1599 6 : LocalContext env;
1600 12 : v8::HandleScope scope(env->GetIsolate());
1601 6 : v8::Isolate* isolate = CcTest::isolate();
1602 :
1603 : uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1604 : uint32_t value = INT32_MAX_AS_UINT + 1;
1605 : CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1606 :
1607 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1608 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1609 6 : }
1610 :
1611 :
1612 25881 : THREADED_TEST(IsNativeError) {
1613 6 : LocalContext env;
1614 12 : v8::HandleScope scope(env->GetIsolate());
1615 : v8::Local<Value> syntax_error = CompileRun(
1616 : "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1617 6 : CHECK(syntax_error->IsNativeError());
1618 : v8::Local<Value> not_error = CompileRun("{a:42}");
1619 6 : CHECK(!not_error->IsNativeError());
1620 : v8::Local<Value> not_object = CompileRun("42");
1621 12 : CHECK(!not_object->IsNativeError());
1622 6 : }
1623 :
1624 :
1625 25881 : THREADED_TEST(IsGeneratorFunctionOrObject) {
1626 6 : LocalContext env;
1627 12 : v8::HandleScope scope(env->GetIsolate());
1628 :
1629 : CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1630 : v8::Local<Value> gen = CompileRun("gen");
1631 : v8::Local<Value> genObj = CompileRun("gen()");
1632 : v8::Local<Value> object = CompileRun("{a:42}");
1633 : v8::Local<Value> func = CompileRun("func");
1634 :
1635 6 : CHECK(gen->IsGeneratorFunction());
1636 6 : CHECK(gen->IsFunction());
1637 6 : CHECK(!gen->IsGeneratorObject());
1638 :
1639 6 : CHECK(!genObj->IsGeneratorFunction());
1640 6 : CHECK(!genObj->IsFunction());
1641 6 : CHECK(genObj->IsGeneratorObject());
1642 :
1643 6 : CHECK(!object->IsGeneratorFunction());
1644 6 : CHECK(!object->IsFunction());
1645 6 : CHECK(!object->IsGeneratorObject());
1646 :
1647 6 : CHECK(!func->IsGeneratorFunction());
1648 6 : CHECK(func->IsFunction());
1649 12 : CHECK(!func->IsGeneratorObject());
1650 6 : }
1651 :
1652 25881 : THREADED_TEST(IsAsyncFunction) {
1653 6 : LocalContext env;
1654 6 : v8::Isolate* isolate = env->GetIsolate();
1655 12 : v8::HandleScope scope(isolate);
1656 :
1657 : CompileRun("async function foo() {}");
1658 : v8::Local<Value> foo = CompileRun("foo");
1659 :
1660 6 : CHECK(foo->IsAsyncFunction());
1661 6 : CHECK(foo->IsFunction());
1662 6 : CHECK(!foo->IsGeneratorFunction());
1663 6 : CHECK(!foo->IsGeneratorObject());
1664 :
1665 : CompileRun("function bar() {}");
1666 : v8::Local<Value> bar = CompileRun("bar");
1667 :
1668 6 : CHECK(!bar->IsAsyncFunction());
1669 12 : CHECK(bar->IsFunction());
1670 6 : }
1671 :
1672 25881 : THREADED_TEST(ArgumentsObject) {
1673 6 : LocalContext env;
1674 12 : v8::HandleScope scope(env->GetIsolate());
1675 : v8::Local<Value> arguments_object =
1676 : CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1677 6 : CHECK(arguments_object->IsArgumentsObject());
1678 : v8::Local<Value> array = CompileRun("[1,2,3]");
1679 6 : CHECK(!array->IsArgumentsObject());
1680 : v8::Local<Value> object = CompileRun("{a:42}");
1681 12 : CHECK(!object->IsArgumentsObject());
1682 6 : }
1683 :
1684 :
1685 25881 : THREADED_TEST(IsMapOrSet) {
1686 6 : LocalContext env;
1687 12 : v8::HandleScope scope(env->GetIsolate());
1688 : v8::Local<Value> map = CompileRun("new Map()");
1689 : v8::Local<Value> set = CompileRun("new Set()");
1690 : v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1691 : v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1692 6 : CHECK(map->IsMap());
1693 6 : CHECK(set->IsSet());
1694 6 : CHECK(weak_map->IsWeakMap());
1695 6 : CHECK(weak_set->IsWeakSet());
1696 :
1697 6 : CHECK(!map->IsSet());
1698 6 : CHECK(!map->IsWeakMap());
1699 6 : CHECK(!map->IsWeakSet());
1700 :
1701 6 : CHECK(!set->IsMap());
1702 6 : CHECK(!set->IsWeakMap());
1703 6 : CHECK(!set->IsWeakSet());
1704 :
1705 6 : CHECK(!weak_map->IsMap());
1706 6 : CHECK(!weak_map->IsSet());
1707 6 : CHECK(!weak_map->IsWeakSet());
1708 :
1709 6 : CHECK(!weak_set->IsMap());
1710 6 : CHECK(!weak_set->IsSet());
1711 6 : CHECK(!weak_set->IsWeakMap());
1712 :
1713 : v8::Local<Value> object = CompileRun("{a:42}");
1714 6 : CHECK(!object->IsMap());
1715 6 : CHECK(!object->IsSet());
1716 6 : CHECK(!object->IsWeakMap());
1717 12 : CHECK(!object->IsWeakSet());
1718 6 : }
1719 :
1720 :
1721 25881 : THREADED_TEST(StringObject) {
1722 6 : LocalContext env;
1723 12 : v8::HandleScope scope(env->GetIsolate());
1724 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1725 6 : CHECK(boxed_string->IsStringObject());
1726 : v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1727 6 : CHECK(!unboxed_string->IsStringObject());
1728 : v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1729 6 : CHECK(!boxed_not_string->IsStringObject());
1730 : v8::Local<Value> not_object = CompileRun("0");
1731 6 : CHECK(!not_object->IsStringObject());
1732 : v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1733 6 : CHECK(!as_boxed.IsEmpty());
1734 6 : Local<v8::String> the_string = as_boxed->ValueOf();
1735 6 : CHECK(!the_string.IsEmpty());
1736 6 : ExpectObject("\"test\"", the_string);
1737 : v8::Local<v8::Value> new_boxed_string =
1738 6 : v8::StringObject::New(CcTest::isolate(), the_string);
1739 6 : CHECK(new_boxed_string->IsStringObject());
1740 : as_boxed = new_boxed_string.As<v8::StringObject>();
1741 6 : the_string = as_boxed->ValueOf();
1742 6 : CHECK(!the_string.IsEmpty());
1743 12 : ExpectObject("\"test\"", the_string);
1744 6 : }
1745 :
1746 :
1747 25880 : TEST(StringObjectDelete) {
1748 5 : LocalContext context;
1749 10 : v8::HandleScope scope(context->GetIsolate());
1750 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1751 5 : CHECK(boxed_string->IsStringObject());
1752 : v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1753 10 : CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1754 15 : CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1755 5 : }
1756 :
1757 :
1758 25881 : THREADED_TEST(NumberObject) {
1759 6 : LocalContext env;
1760 12 : v8::HandleScope scope(env->GetIsolate());
1761 : v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1762 6 : CHECK(boxed_number->IsNumberObject());
1763 : v8::Local<Value> unboxed_number = CompileRun("42");
1764 6 : CHECK(!unboxed_number->IsNumberObject());
1765 : v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1766 6 : CHECK(!boxed_not_number->IsNumberObject());
1767 : v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1768 6 : CHECK(!as_boxed.IsEmpty());
1769 6 : double the_number = as_boxed->ValueOf();
1770 6 : CHECK_EQ(42.0, the_number);
1771 : v8::Local<v8::Value> new_boxed_number =
1772 6 : v8::NumberObject::New(env->GetIsolate(), 43);
1773 6 : CHECK(new_boxed_number->IsNumberObject());
1774 : as_boxed = new_boxed_number.As<v8::NumberObject>();
1775 6 : the_number = as_boxed->ValueOf();
1776 12 : CHECK_EQ(43.0, the_number);
1777 6 : }
1778 :
1779 25881 : THREADED_TEST(BigIntObject) {
1780 6 : LocalContext env;
1781 6 : v8::Isolate* isolate = env->GetIsolate();
1782 12 : v8::HandleScope scope(isolate);
1783 6 : v8::Local<v8::Context> context(env.local());
1784 : v8::Local<Value> boxed_bigint = CompileRun("new Object(42n)");
1785 6 : CHECK(!boxed_bigint->IsBigInt());
1786 6 : CHECK(boxed_bigint->IsBigIntObject());
1787 : v8::Local<Value> unboxed_bigint = CompileRun("42n");
1788 6 : CHECK(unboxed_bigint->IsBigInt());
1789 6 : CHECK(!unboxed_bigint->IsBigIntObject());
1790 : v8::Local<v8::BigIntObject> as_boxed = boxed_bigint.As<v8::BigIntObject>();
1791 6 : CHECK(!as_boxed.IsEmpty());
1792 6 : v8::Local<v8::BigInt> unpacked = as_boxed->ValueOf();
1793 6 : CHECK(!unpacked.IsEmpty());
1794 6 : v8::Local<v8::Value> new_boxed_bigint = v8::BigIntObject::New(isolate, 43);
1795 6 : CHECK(new_boxed_bigint->IsBigIntObject());
1796 6 : v8::Local<v8::Value> new_unboxed_bigint = v8::BigInt::New(isolate, 44);
1797 6 : CHECK(new_unboxed_bigint->IsBigInt());
1798 :
1799 : // Test functionality inherited from v8::Value.
1800 6 : CHECK(unboxed_bigint->BooleanValue(isolate));
1801 : v8::Local<v8::String> string =
1802 6 : unboxed_bigint->ToString(context).ToLocalChecked();
1803 6 : CHECK_EQ(0, strcmp("42", *v8::String::Utf8Value(isolate, string)));
1804 :
1805 : // IntegerValue throws.
1806 18 : CHECK(unboxed_bigint->IntegerValue(context).IsNothing());
1807 6 : }
1808 :
1809 25881 : THREADED_TEST(BooleanObject) {
1810 6 : LocalContext env;
1811 12 : v8::HandleScope scope(env->GetIsolate());
1812 : v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1813 6 : CHECK(boxed_boolean->IsBooleanObject());
1814 : v8::Local<Value> unboxed_boolean = CompileRun("true");
1815 6 : CHECK(!unboxed_boolean->IsBooleanObject());
1816 : v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1817 6 : CHECK(!boxed_not_boolean->IsBooleanObject());
1818 : v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1819 6 : CHECK(!as_boxed.IsEmpty());
1820 6 : bool the_boolean = as_boxed->ValueOf();
1821 6 : CHECK(the_boolean);
1822 : v8::Local<v8::Value> boxed_true =
1823 6 : v8::BooleanObject::New(env->GetIsolate(), true);
1824 : v8::Local<v8::Value> boxed_false =
1825 6 : v8::BooleanObject::New(env->GetIsolate(), false);
1826 6 : CHECK(boxed_true->IsBooleanObject());
1827 6 : CHECK(boxed_false->IsBooleanObject());
1828 : as_boxed = boxed_true.As<v8::BooleanObject>();
1829 6 : CHECK(as_boxed->ValueOf());
1830 : as_boxed = boxed_false.As<v8::BooleanObject>();
1831 12 : CHECK(!as_boxed->ValueOf());
1832 6 : }
1833 :
1834 :
1835 25881 : THREADED_TEST(PrimitiveAndWrappedBooleans) {
1836 6 : LocalContext env;
1837 6 : v8::Isolate* isolate = env->GetIsolate();
1838 12 : v8::HandleScope scope(isolate);
1839 :
1840 : Local<Value> primitive_false = Boolean::New(isolate, false);
1841 6 : CHECK(primitive_false->IsBoolean());
1842 6 : CHECK(!primitive_false->IsBooleanObject());
1843 6 : CHECK(!primitive_false->BooleanValue(isolate));
1844 6 : CHECK(!primitive_false->IsTrue());
1845 6 : CHECK(primitive_false->IsFalse());
1846 :
1847 6 : Local<Value> false_value = BooleanObject::New(isolate, false);
1848 6 : CHECK(!false_value->IsBoolean());
1849 6 : CHECK(false_value->IsBooleanObject());
1850 6 : CHECK(false_value->BooleanValue(isolate));
1851 6 : CHECK(!false_value->IsTrue());
1852 6 : CHECK(!false_value->IsFalse());
1853 :
1854 : Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1855 6 : CHECK(!false_boolean_object->IsBoolean());
1856 6 : CHECK(false_boolean_object->IsBooleanObject());
1857 6 : CHECK(false_boolean_object->BooleanValue(isolate));
1858 6 : CHECK(!false_boolean_object->ValueOf());
1859 6 : CHECK(!false_boolean_object->IsTrue());
1860 6 : CHECK(!false_boolean_object->IsFalse());
1861 :
1862 : Local<Value> primitive_true = Boolean::New(isolate, true);
1863 6 : CHECK(primitive_true->IsBoolean());
1864 6 : CHECK(!primitive_true->IsBooleanObject());
1865 6 : CHECK(primitive_true->BooleanValue(isolate));
1866 6 : CHECK(primitive_true->IsTrue());
1867 6 : CHECK(!primitive_true->IsFalse());
1868 :
1869 6 : Local<Value> true_value = BooleanObject::New(isolate, true);
1870 6 : CHECK(!true_value->IsBoolean());
1871 6 : CHECK(true_value->IsBooleanObject());
1872 6 : CHECK(true_value->BooleanValue(isolate));
1873 6 : CHECK(!true_value->IsTrue());
1874 6 : CHECK(!true_value->IsFalse());
1875 :
1876 : Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1877 6 : CHECK(!true_boolean_object->IsBoolean());
1878 6 : CHECK(true_boolean_object->IsBooleanObject());
1879 6 : CHECK(true_boolean_object->BooleanValue(isolate));
1880 6 : CHECK(true_boolean_object->ValueOf());
1881 6 : CHECK(!true_boolean_object->IsTrue());
1882 12 : CHECK(!true_boolean_object->IsFalse());
1883 6 : }
1884 :
1885 :
1886 25881 : THREADED_TEST(Number) {
1887 6 : LocalContext env;
1888 12 : v8::HandleScope scope(env->GetIsolate());
1889 : double PI = 3.1415926;
1890 6 : Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1891 24 : CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1892 6 : }
1893 :
1894 :
1895 25881 : THREADED_TEST(ToNumber) {
1896 6 : LocalContext env;
1897 6 : v8::Isolate* isolate = CcTest::isolate();
1898 12 : v8::HandleScope scope(isolate);
1899 6 : Local<String> str = v8_str("3.1415926");
1900 18 : CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1901 : v8::Local<v8::Boolean> t = v8::True(isolate);
1902 12 : CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1903 : v8::Local<v8::Boolean> f = v8::False(isolate);
1904 18 : CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1905 6 : }
1906 :
1907 :
1908 25881 : THREADED_TEST(Date) {
1909 6 : LocalContext env;
1910 12 : v8::HandleScope scope(env->GetIsolate());
1911 : double PI = 3.1415926;
1912 6 : Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1913 12 : CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1914 24 : CHECK(date.As<v8::Date>()
1915 : ->Set(env.local(), v8_str("property"),
1916 : v8::Integer::New(env->GetIsolate(), 42))
1917 : .FromJust());
1918 24 : CHECK_EQ(42, date.As<v8::Date>()
1919 : ->Get(env.local(), v8_str("property"))
1920 : .ToLocalChecked()
1921 : ->Int32Value(env.local())
1922 6 : .FromJust());
1923 6 : }
1924 :
1925 :
1926 25881 : THREADED_TEST(Boolean) {
1927 6 : LocalContext env;
1928 6 : v8::Isolate* isolate = env->GetIsolate();
1929 12 : v8::HandleScope scope(isolate);
1930 : v8::Local<v8::Boolean> t = v8::True(isolate);
1931 6 : CHECK(t->Value());
1932 : v8::Local<v8::Boolean> f = v8::False(isolate);
1933 6 : CHECK(!f->Value());
1934 : v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1935 6 : CHECK(!u->BooleanValue(isolate));
1936 : v8::Local<v8::Primitive> n = v8::Null(isolate);
1937 6 : CHECK(!n->BooleanValue(isolate));
1938 6 : v8::Local<String> str1 = v8_str("");
1939 6 : CHECK(!str1->BooleanValue(isolate));
1940 6 : v8::Local<String> str2 = v8_str("x");
1941 6 : CHECK(str2->BooleanValue(isolate));
1942 12 : CHECK(!v8::Number::New(isolate, 0)->BooleanValue(isolate));
1943 12 : CHECK(v8::Number::New(isolate, -1)->BooleanValue(isolate));
1944 12 : CHECK(v8::Number::New(isolate, 1)->BooleanValue(isolate));
1945 12 : CHECK(v8::Number::New(isolate, 42)->BooleanValue(isolate));
1946 18 : CHECK(!v8_compile("NaN")
1947 : ->Run(env.local())
1948 : .ToLocalChecked()
1949 6 : ->BooleanValue(isolate));
1950 6 : }
1951 :
1952 :
1953 12 : static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1954 6 : ApiTestFuzzer::Fuzz();
1955 6 : args.GetReturnValue().Set(v8_num(13.4));
1956 6 : }
1957 :
1958 :
1959 6 : static void GetM(Local<String> name,
1960 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1961 6 : ApiTestFuzzer::Fuzz();
1962 6 : info.GetReturnValue().Set(v8_num(876));
1963 6 : }
1964 :
1965 :
1966 25881 : THREADED_TEST(GlobalPrototype) {
1967 6 : v8::Isolate* isolate = CcTest::isolate();
1968 6 : v8::HandleScope scope(isolate);
1969 : v8::Local<v8::FunctionTemplate> func_templ =
1970 6 : v8::FunctionTemplate::New(isolate);
1971 12 : func_templ->PrototypeTemplate()->Set(
1972 12 : isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1973 6 : v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1974 6 : templ->Set(isolate, "x", v8_num(200));
1975 6 : templ->SetAccessor(v8_str("m"), GetM);
1976 12 : LocalContext env(nullptr, templ);
1977 : v8::Local<Script> script(v8_compile("dummy()"));
1978 6 : v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1979 12 : CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
1980 6 : CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
1981 12 : CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
1982 6 : }
1983 :
1984 :
1985 25881 : THREADED_TEST(ObjectTemplate) {
1986 6 : LocalContext env;
1987 6 : v8::Isolate* isolate = CcTest::isolate();
1988 12 : v8::HandleScope scope(isolate);
1989 : Local<v8::FunctionTemplate> acc =
1990 6 : v8::FunctionTemplate::New(isolate, Returns42);
1991 42 : CHECK(env->Global()
1992 : ->Set(env.local(), v8_str("acc"),
1993 : acc->GetFunction(env.local()).ToLocalChecked())
1994 : .FromJust());
1995 :
1996 6 : Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1997 6 : v8::Local<v8::String> class_name = v8_str("the_class_name");
1998 6 : fun->SetClassName(class_name);
1999 6 : Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
2000 6 : templ1->Set(isolate, "x", v8_num(10));
2001 6 : templ1->Set(isolate, "y", v8_num(13));
2002 12 : templ1->Set(v8_str("foo"), acc);
2003 : Local<v8::Object> instance1 =
2004 6 : templ1->NewInstance(env.local()).ToLocalChecked();
2005 12 : CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
2006 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
2007 6 : CHECK(CompileRun("(p.x == 10)")->BooleanValue(isolate));
2008 6 : CHECK(CompileRun("(p.y == 13)")->BooleanValue(isolate));
2009 6 : CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(isolate));
2010 6 : CHECK(CompileRun("(p.foo == acc)")->BooleanValue(isolate));
2011 : // Ensure that foo become a data field.
2012 : CompileRun("p.foo = function() {}");
2013 6 : Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
2014 12 : fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
2015 6 : Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
2016 6 : templ2->Set(isolate, "a", v8_num(12));
2017 : templ2->Set(isolate, "b", templ1);
2018 12 : templ2->Set(v8_str("bar"), acc);
2019 12 : templ2->SetAccessorProperty(v8_str("acc"), acc);
2020 : Local<v8::Object> instance2 =
2021 6 : templ2->NewInstance(env.local()).ToLocalChecked();
2022 30 : CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
2023 6 : CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(isolate));
2024 6 : CHECK(CompileRun("(q.a == 12)")->BooleanValue(isolate));
2025 6 : CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(isolate));
2026 6 : CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(isolate));
2027 6 : CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(isolate));
2028 6 : CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(isolate));
2029 6 : CHECK(CompileRun("(q.b !== p)")->BooleanValue(isolate));
2030 6 : CHECK(CompileRun("(q.acc == 42)")->BooleanValue(isolate));
2031 6 : CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(isolate));
2032 6 : CHECK(CompileRun("(q.bar == acc)")->BooleanValue(isolate));
2033 :
2034 6 : instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
2035 30 : CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
2036 6 : CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(isolate));
2037 6 : CHECK(CompileRun("(q2.a == 12)")->BooleanValue(isolate));
2038 6 : CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(isolate));
2039 6 : CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(isolate));
2040 6 : CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(isolate));
2041 6 : CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(isolate));
2042 6 : CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(isolate));
2043 6 : CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(isolate));
2044 6 : CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(isolate));
2045 :
2046 6 : CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(isolate));
2047 6 : CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")->BooleanValue(isolate));
2048 6 : CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
2049 : "(desc1.get === acc)")
2050 : ->BooleanValue(isolate));
2051 6 : CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
2052 : "(desc2.get === acc)")
2053 6 : ->BooleanValue(isolate));
2054 6 : }
2055 :
2056 25881 : THREADED_TEST(IntegerValue) {
2057 6 : LocalContext env;
2058 6 : v8::Isolate* isolate = CcTest::isolate();
2059 12 : v8::HandleScope scope(isolate);
2060 :
2061 24 : CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
2062 6 : }
2063 :
2064 126 : static void GetNirk(Local<String> name,
2065 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2066 126 : ApiTestFuzzer::Fuzz();
2067 126 : info.GetReturnValue().Set(v8_num(900));
2068 126 : }
2069 :
2070 126 : static void GetRino(Local<String> name,
2071 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2072 126 : ApiTestFuzzer::Fuzz();
2073 126 : info.GetReturnValue().Set(v8_num(560));
2074 126 : }
2075 :
2076 : enum ObjectInstantiationMode {
2077 : // Create object using ObjectTemplate::NewInstance.
2078 : ObjectTemplate_NewInstance,
2079 : // Create object using FunctionTemplate::NewInstance on constructor.
2080 : Constructor_GetFunction_NewInstance,
2081 : // Create object using new operator on constructor.
2082 : Constructor_GetFunction_New
2083 : };
2084 :
2085 : // Test object instance creation using a function template with an instance
2086 : // template inherited from another function template with accessors and data
2087 : // properties in prototype template.
2088 18 : static void TestObjectTemplateInheritedWithPrototype(
2089 : ObjectInstantiationMode mode) {
2090 18 : LocalContext env;
2091 18 : v8::Isolate* isolate = CcTest::isolate();
2092 36 : v8::HandleScope scope(isolate);
2093 :
2094 18 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2095 18 : fun_A->SetClassName(v8_str("A"));
2096 18 : v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
2097 18 : prototype_templ->Set(isolate, "a", v8_num(113));
2098 18 : prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2099 18 : prototype_templ->Set(isolate, "b", v8_num(153));
2100 :
2101 18 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2102 18 : v8::Local<v8::String> class_name = v8_str("B");
2103 18 : fun_B->SetClassName(class_name);
2104 18 : fun_B->Inherit(fun_A);
2105 18 : prototype_templ = fun_B->PrototypeTemplate();
2106 18 : prototype_templ->Set(isolate, "c", v8_num(713));
2107 18 : prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
2108 18 : prototype_templ->Set(isolate, "d", v8_num(753));
2109 :
2110 18 : Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
2111 18 : templ->Set(isolate, "x", v8_num(10));
2112 18 : templ->Set(isolate, "y", v8_num(13));
2113 :
2114 : // Perform several iterations to trigger creation from cached boilerplate.
2115 72 : for (int i = 0; i < 3; i++) {
2116 : Local<v8::Object> instance;
2117 54 : switch (mode) {
2118 : case ObjectTemplate_NewInstance:
2119 18 : instance = templ->NewInstance(env.local()).ToLocalChecked();
2120 18 : break;
2121 :
2122 : case Constructor_GetFunction_NewInstance: {
2123 : Local<v8::Function> function_B =
2124 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2125 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2126 : break;
2127 : }
2128 : case Constructor_GetFunction_New: {
2129 : Local<v8::Function> function_B =
2130 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2131 18 : if (i == 0) {
2132 24 : CHECK(env->Global()
2133 : ->Set(env.local(), class_name, function_B)
2134 : .FromJust());
2135 : }
2136 : instance =
2137 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2138 : break;
2139 : }
2140 : default:
2141 0 : UNREACHABLE();
2142 : }
2143 :
2144 108 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2145 270 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2146 :
2147 162 : CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2148 162 : CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2149 :
2150 162 : CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2151 162 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2152 162 : CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2153 162 : CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2154 162 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2155 162 : CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2156 18 : }
2157 18 : }
2158 :
2159 25881 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2160 6 : TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2161 6 : }
2162 :
2163 25881 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2164 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2165 6 : }
2166 :
2167 25881 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2168 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2169 6 : }
2170 :
2171 : // Test object instance creation using a function template without an instance
2172 : // template inherited from another function template.
2173 12 : static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2174 : ObjectInstantiationMode mode) {
2175 12 : LocalContext env;
2176 12 : v8::Isolate* isolate = CcTest::isolate();
2177 24 : v8::HandleScope scope(isolate);
2178 :
2179 12 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2180 12 : fun_A->SetClassName(v8_str("A"));
2181 :
2182 12 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2183 12 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2184 12 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2185 :
2186 12 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2187 12 : v8::Local<v8::String> class_name = v8_str("B");
2188 12 : fun_B->SetClassName(class_name);
2189 12 : fun_B->Inherit(fun_A);
2190 :
2191 : // Perform several iterations to trigger creation from cached boilerplate.
2192 48 : for (int i = 0; i < 3; i++) {
2193 : Local<v8::Object> instance;
2194 36 : switch (mode) {
2195 : case Constructor_GetFunction_NewInstance: {
2196 : Local<v8::Function> function_B =
2197 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2198 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2199 : break;
2200 : }
2201 : case Constructor_GetFunction_New: {
2202 : Local<v8::Function> function_B =
2203 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2204 18 : if (i == 0) {
2205 24 : CHECK(env->Global()
2206 : ->Set(env.local(), class_name, function_B)
2207 : .FromJust());
2208 : }
2209 : instance =
2210 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2211 : break;
2212 : }
2213 : default:
2214 0 : UNREACHABLE();
2215 : }
2216 :
2217 72 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2218 180 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2219 :
2220 108 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2221 108 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2222 12 : }
2223 12 : }
2224 :
2225 25881 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2226 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2227 6 : Constructor_GetFunction_NewInstance);
2228 6 : }
2229 :
2230 25881 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2231 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2232 6 : Constructor_GetFunction_New);
2233 6 : }
2234 :
2235 25881 : THREADED_TEST(TestObjectTemplateClassInheritance) {
2236 6 : LocalContext env;
2237 6 : v8::Isolate* isolate = CcTest::isolate();
2238 12 : v8::HandleScope scope(isolate);
2239 :
2240 6 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2241 6 : fun_A->SetClassName(v8_str("A"));
2242 :
2243 6 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2244 6 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2245 6 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2246 :
2247 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2248 6 : v8::Local<v8::String> class_name = v8_str("B");
2249 6 : fun_B->SetClassName(class_name);
2250 6 : fun_B->Inherit(fun_A);
2251 :
2252 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2253 : v8::Local<v8::Object> b_proto;
2254 : v8::Local<v8::Object> c_proto;
2255 : // Perform several iterations to make sure the cache doesn't break
2256 : // subclassing.
2257 24 : for (int i = 0; i < 3; i++) {
2258 : Local<v8::Function> function_B =
2259 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2260 18 : if (i == 0) {
2261 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2262 : CompileRun("class C extends B {}");
2263 : b_proto =
2264 12 : CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2265 : c_proto =
2266 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2267 12 : CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2268 : }
2269 : Local<v8::Object> instance =
2270 36 : CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2271 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2272 :
2273 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2274 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2275 :
2276 54 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2277 54 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2278 6 : }
2279 6 : }
2280 :
2281 276 : static void NamedPropertyGetterWhichReturns42(
2282 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2283 276 : info.GetReturnValue().Set(v8_num(42));
2284 276 : }
2285 :
2286 25881 : THREADED_TEST(TestObjectTemplateReflectConstruct) {
2287 6 : LocalContext env;
2288 6 : v8::Isolate* isolate = CcTest::isolate();
2289 12 : v8::HandleScope scope(isolate);
2290 :
2291 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2292 : fun_B->InstanceTemplate()->SetHandler(
2293 12 : v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2294 6 : v8::Local<v8::String> class_name = v8_str("B");
2295 6 : fun_B->SetClassName(class_name);
2296 :
2297 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2298 : v8::Local<v8::Object> b_proto;
2299 : v8::Local<v8::Object> c_proto;
2300 : // Perform several iterations to make sure the cache doesn't break
2301 : // subclassing.
2302 24 : for (int i = 0; i < 3; i++) {
2303 : Local<v8::Function> function_B =
2304 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2305 18 : if (i == 0) {
2306 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2307 : CompileRun("function C() {}");
2308 : c_proto =
2309 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2310 : }
2311 : Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2312 18 : ->ToObject(env.local())
2313 18 : .ToLocalChecked();
2314 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2315 :
2316 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2317 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2318 :
2319 54 : CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2320 54 : CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2321 6 : }
2322 6 : }
2323 :
2324 24 : static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2325 12 : ApiTestFuzzer::Fuzz();
2326 12 : args.GetReturnValue().Set(v8_num(17.2));
2327 12 : }
2328 :
2329 :
2330 30 : static void GetKnurd(Local<String> property,
2331 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2332 30 : ApiTestFuzzer::Fuzz();
2333 30 : info.GetReturnValue().Set(v8_num(15.2));
2334 30 : }
2335 :
2336 :
2337 25881 : THREADED_TEST(DescriptorInheritance) {
2338 6 : v8::Isolate* isolate = CcTest::isolate();
2339 6 : v8::HandleScope scope(isolate);
2340 6 : v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2341 12 : super->PrototypeTemplate()->Set(isolate, "flabby",
2342 : v8::FunctionTemplate::New(isolate,
2343 12 : GetFlabby));
2344 12 : super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2345 :
2346 12 : super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2347 :
2348 6 : v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2349 6 : base1->Inherit(super);
2350 12 : base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2351 :
2352 6 : v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2353 6 : base2->Inherit(super);
2354 12 : base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2355 :
2356 12 : LocalContext env;
2357 :
2358 36 : CHECK(env->Global()
2359 : ->Set(env.local(), v8_str("s"),
2360 : super->GetFunction(env.local()).ToLocalChecked())
2361 : .FromJust());
2362 36 : CHECK(env->Global()
2363 : ->Set(env.local(), v8_str("base1"),
2364 : base1->GetFunction(env.local()).ToLocalChecked())
2365 : .FromJust());
2366 36 : CHECK(env->Global()
2367 : ->Set(env.local(), v8_str("base2"),
2368 : base2->GetFunction(env.local()).ToLocalChecked())
2369 : .FromJust());
2370 :
2371 : // Checks right __proto__ chain.
2372 6 : CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2373 : ->BooleanValue(isolate));
2374 6 : CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2375 : ->BooleanValue(isolate));
2376 :
2377 18 : CHECK(v8_compile("s.prototype.PI == 3.14")
2378 : ->Run(env.local())
2379 : .ToLocalChecked()
2380 : ->BooleanValue(isolate));
2381 :
2382 : // Instance accessor should not be visible on function object or its prototype
2383 6 : CHECK(CompileRun("s.knurd == undefined")->BooleanValue(isolate));
2384 6 : CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue(isolate));
2385 6 : CHECK(
2386 : CompileRun("base1.prototype.knurd == undefined")->BooleanValue(isolate));
2387 :
2388 36 : CHECK(env->Global()
2389 : ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2390 : .ToLocalChecked()
2391 : ->NewInstance(env.local())
2392 : .ToLocalChecked())
2393 : .FromJust());
2394 18 : CHECK_EQ(17.2,
2395 : CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2396 6 : CHECK(CompileRun("'flabby' in obj")->BooleanValue(isolate));
2397 18 : CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2398 6 : CHECK(CompileRun("'knurd' in obj")->BooleanValue(isolate));
2399 18 : CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2400 :
2401 36 : CHECK(env->Global()
2402 : ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2403 : .ToLocalChecked()
2404 : ->NewInstance(env.local())
2405 : .ToLocalChecked())
2406 : .FromJust());
2407 18 : CHECK_EQ(17.2,
2408 : CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2409 6 : CHECK(CompileRun("'flabby' in obj2")->BooleanValue(isolate));
2410 18 : CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2411 6 : CHECK(CompileRun("'knurd' in obj2")->BooleanValue(isolate));
2412 18 : CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2413 :
2414 : // base1 and base2 cannot cross reference to each's prototype
2415 6 : CHECK(CompileRun("obj.v2")->IsUndefined());
2416 12 : CHECK(CompileRun("obj2.v1")->IsUndefined());
2417 6 : }
2418 :
2419 25881 : THREADED_TEST(DescriptorInheritance2) {
2420 6 : LocalContext env;
2421 6 : v8::Isolate* isolate = CcTest::isolate();
2422 12 : v8::HandleScope scope(isolate);
2423 6 : v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2424 6 : fun_A->SetClassName(v8_str("A"));
2425 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2426 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2427 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2428 :
2429 6 : v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2430 6 : fun_B->SetClassName(v8_str("B"));
2431 6 : fun_B->Inherit(fun_A);
2432 :
2433 6 : v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2434 6 : fun_C->SetClassName(v8_str("C"));
2435 6 : fun_C->Inherit(fun_B);
2436 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2437 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2438 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2439 :
2440 6 : v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2441 6 : fun_D->SetClassName(v8_str("D"));
2442 6 : fun_D->Inherit(fun_C);
2443 :
2444 6 : v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2445 6 : fun_E->SetClassName(v8_str("E"));
2446 6 : fun_E->Inherit(fun_D);
2447 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2448 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2449 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2450 :
2451 6 : v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2452 6 : fun_F->SetClassName(v8_str("F"));
2453 6 : fun_F->Inherit(fun_E);
2454 6 : v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2455 : const int kDataPropertiesNumber = 100;
2456 606 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2457 600 : v8::Local<v8::Value> val = v8_num(i);
2458 1200 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2459 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2460 :
2461 600 : templ->Set(name, val);
2462 600 : templ->Set(val_str, val);
2463 : }
2464 :
2465 36 : CHECK(env->Global()
2466 : ->Set(env.local(), v8_str("F"),
2467 : fun_F->GetFunction(env.local()).ToLocalChecked())
2468 : .FromJust());
2469 :
2470 : v8::Local<v8::Script> script = v8_compile("o = new F()");
2471 :
2472 606 : for (int i = 0; i < 100; i++) {
2473 600 : v8::HandleScope scope(isolate);
2474 600 : script->Run(env.local()).ToLocalChecked();
2475 600 : }
2476 6 : v8::Local<v8::Object> object = script->Run(env.local())
2477 6 : .ToLocalChecked()
2478 6 : ->ToObject(env.local())
2479 6 : .ToLocalChecked();
2480 :
2481 18 : CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2482 18 : CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2483 18 : CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2484 :
2485 18 : CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2486 18 : CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2487 18 : CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2488 :
2489 18 : CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2490 18 : CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2491 18 : CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2492 :
2493 600 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2494 600 : v8::Local<v8::Value> val = v8_num(i);
2495 1800 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2496 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2497 :
2498 2400 : CHECK_EQ(i, object->Get(env.local(), name)
2499 : .ToLocalChecked()
2500 : ->IntegerValue(env.local())
2501 : .FromJust());
2502 1800 : CHECK_EQ(i, object->Get(env.local(), val)
2503 : .ToLocalChecked()
2504 : ->IntegerValue(env.local())
2505 : .FromJust());
2506 6 : }
2507 6 : }
2508 :
2509 :
2510 : // Helper functions for Interceptor/Accessor interaction tests
2511 :
2512 36 : void SimpleAccessorGetter(Local<String> name,
2513 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2514 : Local<Object> self = Local<Object>::Cast(info.This());
2515 : info.GetReturnValue().Set(
2516 : self->Get(info.GetIsolate()->GetCurrentContext(),
2517 144 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
2518 36 : .ToLocalChecked());
2519 36 : }
2520 :
2521 6 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2522 : const v8::PropertyCallbackInfo<void>& info) {
2523 : Local<Object> self = Local<Object>::Cast(info.This());
2524 24 : CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2525 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name),
2526 : value)
2527 : .FromJust());
2528 6 : }
2529 :
2530 36 : void SymbolAccessorGetter(Local<Name> name,
2531 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2532 36 : CHECK(name->IsSymbol());
2533 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2534 72 : if (sym->Name()->IsUndefined())
2535 36 : return;
2536 36 : SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2537 : }
2538 :
2539 6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2540 : const v8::PropertyCallbackInfo<void>& info) {
2541 6 : CHECK(name->IsSymbol());
2542 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2543 12 : if (sym->Name()->IsUndefined())
2544 6 : return;
2545 6 : SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2546 : }
2547 :
2548 5 : void SymbolAccessorGetterReturnsDefault(
2549 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2550 5 : CHECK(name->IsSymbol());
2551 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2552 15 : if (sym->Name()->IsUndefined()) return;
2553 : info.GetReturnValue().Set(info.Data());
2554 : }
2555 :
2556 5 : static void ThrowingSymbolAccessorGetter(
2557 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2558 10 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2559 5 : }
2560 :
2561 :
2562 25881 : THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2563 6 : v8::Isolate* isolate = CcTest::isolate();
2564 6 : v8::HandleScope scope(isolate);
2565 12 : LocalContext env;
2566 : v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2567 : i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2568 12 : CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
2569 : CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2570 12 : CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
2571 : // But we should still have an AccessorInfo.
2572 12 : i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2573 : i::LookupIterator it(CcTest::i_isolate(), a, name,
2574 6 : i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2575 6 : CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2576 24 : CHECK(it.GetAccessors()->IsAccessorInfo());
2577 6 : }
2578 :
2579 :
2580 25881 : THREADED_TEST(UndefinedIsNotEnumerable) {
2581 6 : LocalContext env;
2582 12 : v8::HandleScope scope(env->GetIsolate());
2583 : v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2584 12 : CHECK(result->IsFalse());
2585 6 : }
2586 :
2587 :
2588 : v8::Local<Script> call_recursively_script;
2589 : static const int kTargetRecursionDepth = 100; // near maximum
2590 :
2591 606 : static void CallScriptRecursivelyCall(
2592 3012 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2593 606 : ApiTestFuzzer::Fuzz();
2594 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2595 : int depth = args.This()
2596 1212 : ->Get(context, v8_str("depth"))
2597 606 : .ToLocalChecked()
2598 : ->Int32Value(context)
2599 1212 : .FromJust();
2600 612 : if (depth == kTargetRecursionDepth) return;
2601 3000 : CHECK(args.This()
2602 : ->Set(context, v8_str("depth"),
2603 : v8::Integer::New(args.GetIsolate(), depth + 1))
2604 : .FromJust());
2605 : args.GetReturnValue().Set(
2606 600 : call_recursively_script->Run(context).ToLocalChecked());
2607 : }
2608 :
2609 :
2610 606 : static void CallFunctionRecursivelyCall(
2611 4212 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2612 606 : ApiTestFuzzer::Fuzz();
2613 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2614 : int depth = args.This()
2615 1212 : ->Get(context, v8_str("depth"))
2616 606 : .ToLocalChecked()
2617 : ->Int32Value(context)
2618 1212 : .FromJust();
2619 606 : if (depth == kTargetRecursionDepth) {
2620 : printf("[depth = %d]\n", depth);
2621 612 : return;
2622 : }
2623 3000 : CHECK(args.This()
2624 : ->Set(context, v8_str("depth"),
2625 : v8::Integer::New(args.GetIsolate(), depth + 1))
2626 : .FromJust());
2627 : v8::Local<Value> function =
2628 : args.This()
2629 1200 : ->Get(context, v8_str("callFunctionRecursively"))
2630 600 : .ToLocalChecked();
2631 : args.GetReturnValue().Set(function.As<Function>()
2632 600 : ->Call(context, args.This(), 0, nullptr)
2633 600 : .ToLocalChecked());
2634 : }
2635 :
2636 :
2637 25881 : THREADED_TEST(DeepCrossLanguageRecursion) {
2638 6 : v8::Isolate* isolate = CcTest::isolate();
2639 6 : v8::HandleScope scope(isolate);
2640 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2641 : global->Set(v8_str("callScriptRecursively"),
2642 18 : v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2643 : global->Set(v8_str("callFunctionRecursively"),
2644 18 : v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2645 12 : LocalContext env(nullptr, global);
2646 :
2647 36 : CHECK(env->Global()
2648 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2649 : .FromJust());
2650 6 : call_recursively_script = v8_compile("callScriptRecursively()");
2651 12 : call_recursively_script->Run(env.local()).ToLocalChecked();
2652 6 : call_recursively_script = v8::Local<Script>();
2653 :
2654 36 : CHECK(env->Global()
2655 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2656 : .FromJust());
2657 6 : CompileRun("callFunctionRecursively()");
2658 6 : }
2659 :
2660 :
2661 24 : static void ThrowingPropertyHandlerGet(
2662 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2663 : // Since this interceptor is used on "with" objects, the runtime will look up
2664 : // @@unscopables. Punt.
2665 48 : if (key->IsSymbol()) return;
2666 12 : ApiTestFuzzer::Fuzz();
2667 24 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2668 : }
2669 :
2670 :
2671 0 : static void ThrowingPropertyHandlerSet(
2672 : Local<Name> key, Local<Value>,
2673 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2674 0 : info.GetIsolate()->ThrowException(key);
2675 : info.GetReturnValue().SetUndefined(); // not the same as empty handle
2676 0 : }
2677 :
2678 :
2679 25881 : THREADED_TEST(CallbackExceptionRegression) {
2680 6 : v8::Isolate* isolate = CcTest::isolate();
2681 6 : v8::HandleScope scope(isolate);
2682 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2683 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2684 6 : ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2685 12 : LocalContext env;
2686 36 : CHECK(env->Global()
2687 : ->Set(env.local(), v8_str("obj"),
2688 : obj->NewInstance(env.local()).ToLocalChecked())
2689 : .FromJust());
2690 : v8::Local<Value> otto =
2691 6 : CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2692 18 : CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2693 : v8::Local<Value> netto =
2694 6 : CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2695 24 : CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2696 6 : }
2697 :
2698 :
2699 25881 : THREADED_TEST(FunctionPrototype) {
2700 6 : v8::Isolate* isolate = CcTest::isolate();
2701 6 : v8::HandleScope scope(isolate);
2702 6 : Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2703 24 : Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2704 12 : LocalContext env;
2705 36 : CHECK(env->Global()
2706 : ->Set(env.local(), v8_str("Foo"),
2707 : Foo->GetFunction(env.local()).ToLocalChecked())
2708 : .FromJust());
2709 6 : Local<Script> script = v8_compile("Foo.prototype.plak");
2710 12 : CHECK_EQ(v8_run_int32value(script), 321);
2711 6 : }
2712 :
2713 25881 : THREADED_TEST(InternalFields) {
2714 6 : LocalContext env;
2715 6 : v8::Isolate* isolate = env->GetIsolate();
2716 12 : v8::HandleScope scope(isolate);
2717 :
2718 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2719 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2720 6 : instance_templ->SetInternalFieldCount(1);
2721 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2722 6 : .ToLocalChecked()
2723 6 : ->NewInstance(env.local())
2724 : .ToLocalChecked();
2725 6 : CHECK_EQ(1, obj->InternalFieldCount());
2726 6 : CHECK(obj->GetInternalField(0)->IsUndefined());
2727 6 : obj->SetInternalField(0, v8_num(17));
2728 24 : CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2729 6 : }
2730 :
2731 25880 : TEST(InternalFieldsSubclassing) {
2732 5 : LocalContext env;
2733 5 : v8::Isolate* isolate = env->GetIsolate();
2734 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2735 10 : v8::HandleScope scope(isolate);
2736 65 : for (int nof_embedder_fields = 0;
2737 : nof_embedder_fields < i::JSObject::kMaxEmbedderFields;
2738 : nof_embedder_fields++) {
2739 60 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2740 60 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2741 60 : instance_templ->SetInternalFieldCount(nof_embedder_fields);
2742 : Local<Function> constructor =
2743 60 : templ->GetFunction(env.local()).ToLocalChecked();
2744 : // Check that instances have the correct NOF properties.
2745 : Local<v8::Object> obj =
2746 60 : constructor->NewInstance(env.local()).ToLocalChecked();
2747 :
2748 : i::Handle<i::JSObject> i_obj =
2749 60 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
2750 60 : CHECK_EQ(nof_embedder_fields, obj->InternalFieldCount());
2751 60 : CHECK_EQ(0, i_obj->map()->GetInObjectProperties());
2752 : // Check writing and reading internal fields.
2753 330 : for (int j = 0; j < nof_embedder_fields; j++) {
2754 330 : CHECK(obj->GetInternalField(j)->IsUndefined());
2755 330 : int value = 17 + j;
2756 330 : obj->SetInternalField(j, v8_num(value));
2757 : }
2758 330 : for (int j = 0; j < nof_embedder_fields; j++) {
2759 330 : int value = 17 + j;
2760 990 : CHECK_EQ(value,
2761 : obj->GetInternalField(j)->Int32Value(env.local()).FromJust());
2762 : }
2763 300 : CHECK(env->Global()
2764 : ->Set(env.local(), v8_str("BaseClass"), constructor)
2765 : .FromJust());
2766 : // Create various levels of subclasses to stress instance size calculation.
2767 : const int kMaxNofProperties =
2768 : i::JSObject::kMaxInObjectProperties -
2769 60 : nof_embedder_fields * i::kEmbedderDataSlotSizeInTaggedSlots;
2770 : // Select only a few values to speed up the test.
2771 : int sizes[] = {0,
2772 : 1,
2773 : 2,
2774 : 3,
2775 : 4,
2776 : 5,
2777 : 6,
2778 60 : kMaxNofProperties / 4,
2779 60 : kMaxNofProperties / 2,
2780 60 : kMaxNofProperties - 2,
2781 60 : kMaxNofProperties - 1,
2782 60 : kMaxNofProperties + 1,
2783 60 : kMaxNofProperties + 2,
2784 60 : kMaxNofProperties * 2,
2785 480 : kMaxNofProperties * 2};
2786 960 : for (size_t i = 0; i < arraysize(sizes); i++) {
2787 900 : int nof_properties = sizes[i];
2788 900 : bool in_object_only = nof_properties <= kMaxNofProperties;
2789 900 : std::ostringstream src;
2790 : // Assembler source string for a subclass with {nof_properties}
2791 : // in-object properties.
2792 900 : src << "(function() {\n"
2793 900 : << " class SubClass extends BaseClass {\n"
2794 900 : << " constructor() {\n"
2795 900 : << " super();\n";
2796 : // Set {nof_properties} instance properties in the constructor.
2797 131535 : for (int j = 0; j < nof_properties; j++) {
2798 130635 : src << " this.property" << j << " = " << j << ";\n";
2799 : }
2800 900 : src << " }\n"
2801 900 : << " };\n"
2802 900 : << " let instance;\n"
2803 900 : << " for (let i = 0; i < 3; i++) {\n"
2804 900 : << " instance = new SubClass();\n"
2805 900 : << " }"
2806 900 : << " return instance;\n"
2807 900 : << "})();";
2808 900 : Local<v8::Object> value = CompileRun(src.str().c_str()).As<v8::Object>();
2809 :
2810 : i::Handle<i::JSObject> i_value =
2811 900 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*value));
2812 : #ifdef VERIFY_HEAP
2813 : i_value->HeapObjectVerify(i_isolate);
2814 : i_value->map()->HeapObjectVerify(i_isolate);
2815 : i_value->map()->FindRootMap(i_isolate)->HeapObjectVerify(i_isolate);
2816 : #endif
2817 900 : CHECK_EQ(nof_embedder_fields, value->InternalFieldCount());
2818 900 : if (in_object_only) {
2819 660 : CHECK_LE(nof_properties, i_value->map()->GetInObjectProperties());
2820 : } else {
2821 240 : CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
2822 : }
2823 :
2824 : // Make Sure we get the precise property count.
2825 1800 : i_value->map()->FindRootMap(i_isolate)->CompleteInobjectSlackTracking(
2826 900 : i_isolate);
2827 : // TODO(cbruni): fix accounting to make this condition true.
2828 : // CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
2829 900 : if (in_object_only) {
2830 660 : CHECK_EQ(nof_properties, i_value->map()->GetInObjectProperties());
2831 : } else {
2832 240 : CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
2833 : }
2834 900 : }
2835 5 : }
2836 5 : }
2837 :
2838 25881 : THREADED_TEST(InternalFieldsOfRegularObjects) {
2839 6 : LocalContext env;
2840 6 : v8::Isolate* isolate = env->GetIsolate();
2841 12 : v8::HandleScope scope(isolate);
2842 :
2843 6 : const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"};
2844 24 : for (size_t i = 0; i < arraysize(sources); ++i) {
2845 : i::ScopedVector<char> source(128);
2846 18 : i::SNPrintF(source, "(function() { return %s })()", sources[i]);
2847 : v8::Local<v8::Object> obj = CompileRun(source.start()).As<v8::Object>();
2848 18 : CHECK_EQ(0, obj->InternalFieldCount());
2849 6 : }
2850 6 : }
2851 :
2852 25881 : THREADED_TEST(GlobalObjectInternalFields) {
2853 6 : v8::Isolate* isolate = CcTest::isolate();
2854 6 : v8::HandleScope scope(isolate);
2855 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2856 6 : global_template->SetInternalFieldCount(1);
2857 12 : LocalContext env(nullptr, global_template);
2858 6 : v8::Local<v8::Object> global_proxy = env->Global();
2859 6 : v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2860 6 : CHECK_EQ(1, global->InternalFieldCount());
2861 6 : CHECK(global->GetInternalField(0)->IsUndefined());
2862 6 : global->SetInternalField(0, v8_num(17));
2863 24 : CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2864 6 : }
2865 :
2866 :
2867 25881 : THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2868 6 : LocalContext env;
2869 12 : v8::HandleScope scope(CcTest::isolate());
2870 :
2871 6 : v8::Local<v8::Object> global = env->Global();
2872 18 : CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2873 18 : CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2874 6 : }
2875 :
2876 24 : static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2877 : void* value) {
2878 24 : CHECK(HAS_SMI_TAG(reinterpret_cast<i::Address>(value)));
2879 24 : obj->SetAlignedPointerInInternalField(0, value);
2880 24 : CcTest::CollectAllGarbage();
2881 24 : CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2882 24 : }
2883 :
2884 25881 : THREADED_TEST(InternalFieldsAlignedPointers) {
2885 6 : LocalContext env;
2886 6 : v8::Isolate* isolate = env->GetIsolate();
2887 12 : v8::HandleScope scope(isolate);
2888 :
2889 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2890 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2891 6 : instance_templ->SetInternalFieldCount(1);
2892 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2893 6 : .ToLocalChecked()
2894 6 : ->NewInstance(env.local())
2895 : .ToLocalChecked();
2896 6 : CHECK_EQ(1, obj->InternalFieldCount());
2897 :
2898 6 : CheckAlignedPointerInInternalField(obj, nullptr);
2899 :
2900 6 : int* heap_allocated = new int[100];
2901 6 : CheckAlignedPointerInInternalField(obj, heap_allocated);
2902 6 : delete[] heap_allocated;
2903 :
2904 : int stack_allocated[100];
2905 6 : CheckAlignedPointerInInternalField(obj, stack_allocated);
2906 :
2907 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2908 6 : CheckAlignedPointerInInternalField(obj, huge);
2909 :
2910 : v8::Global<v8::Object> persistent(isolate, obj);
2911 6 : CHECK_EQ(1, Object::InternalFieldCount(persistent));
2912 12 : CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2913 6 : }
2914 :
2915 25881 : THREADED_TEST(SetAlignedPointerInInternalFields) {
2916 6 : LocalContext env;
2917 6 : v8::Isolate* isolate = env->GetIsolate();
2918 12 : v8::HandleScope scope(isolate);
2919 :
2920 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2921 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2922 6 : instance_templ->SetInternalFieldCount(2);
2923 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2924 6 : .ToLocalChecked()
2925 6 : ->NewInstance(env.local())
2926 : .ToLocalChecked();
2927 6 : CHECK_EQ(2, obj->InternalFieldCount());
2928 :
2929 6 : int* heap_allocated_1 = new int[100];
2930 6 : int* heap_allocated_2 = new int[100];
2931 6 : int indices[] = {0, 1};
2932 6 : void* values[] = {heap_allocated_1, heap_allocated_2};
2933 :
2934 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2935 6 : CcTest::CollectAllGarbage();
2936 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0));
2937 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1));
2938 :
2939 6 : indices[0] = 1;
2940 6 : indices[1] = 0;
2941 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2942 6 : CcTest::CollectAllGarbage();
2943 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0));
2944 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1));
2945 :
2946 6 : delete[] heap_allocated_1;
2947 12 : delete[] heap_allocated_2;
2948 6 : }
2949 :
2950 24 : static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2951 : void* value) {
2952 24 : CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2953 24 : (*env)->SetAlignedPointerInEmbedderData(index, value);
2954 24 : CcTest::CollectAllGarbage();
2955 24 : CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2956 24 : }
2957 :
2958 :
2959 : static void* AlignedTestPointer(int i) {
2960 1200 : return reinterpret_cast<void*>(i * 1234);
2961 : }
2962 :
2963 :
2964 25881 : THREADED_TEST(EmbedderDataAlignedPointers) {
2965 6 : LocalContext env;
2966 12 : v8::HandleScope scope(env->GetIsolate());
2967 :
2968 6 : CheckAlignedPointerInEmbedderData(&env, 0, nullptr);
2969 6 : CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields());
2970 :
2971 6 : int* heap_allocated = new int[100];
2972 6 : CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2973 6 : CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields());
2974 6 : delete[] heap_allocated;
2975 :
2976 : int stack_allocated[100];
2977 6 : CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2978 6 : CHECK_EQ(3, (*env)->GetNumberOfEmbedderDataFields());
2979 :
2980 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2981 6 : CheckAlignedPointerInEmbedderData(&env, 3, huge);
2982 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
2983 :
2984 : // Test growing of the embedder data's backing store.
2985 600 : for (int i = 0; i < 100; i++) {
2986 600 : env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2987 : }
2988 6 : CcTest::CollectAllGarbage();
2989 606 : for (int i = 0; i < 100; i++) {
2990 600 : CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2991 6 : }
2992 6 : }
2993 :
2994 30 : static void CheckEmbedderData(LocalContext* env, int index,
2995 : v8::Local<Value> data) {
2996 30 : (*env)->SetEmbedderData(index, data);
2997 30 : CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2998 30 : }
2999 :
3000 :
3001 25881 : THREADED_TEST(EmbedderData) {
3002 6 : LocalContext env;
3003 6 : v8::Isolate* isolate = env->GetIsolate();
3004 12 : v8::HandleScope scope(isolate);
3005 :
3006 6 : CHECK_EQ(0, (*env)->GetNumberOfEmbedderDataFields());
3007 12 : CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
3008 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3009 12 : CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
3010 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3011 12 : CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
3012 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3013 6 : CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
3014 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3015 6 : CheckEmbedderData(&env, 211, v8::Boolean::New(isolate, true));
3016 12 : CHECK_EQ(212, (*env)->GetNumberOfEmbedderDataFields());
3017 6 : }
3018 :
3019 :
3020 25881 : THREADED_TEST(IdentityHash) {
3021 6 : LocalContext env;
3022 6 : v8::Isolate* isolate = env->GetIsolate();
3023 12 : v8::HandleScope scope(isolate);
3024 :
3025 : // Ensure that the test starts with an fresh heap to test whether the hash
3026 : // code is based on the address.
3027 6 : CcTest::CollectAllGarbage();
3028 6 : Local<v8::Object> obj = v8::Object::New(isolate);
3029 6 : int hash = obj->GetIdentityHash();
3030 6 : int hash1 = obj->GetIdentityHash();
3031 6 : CHECK_EQ(hash, hash1);
3032 12 : int hash2 = v8::Object::New(isolate)->GetIdentityHash();
3033 : // Since the identity hash is essentially a random number two consecutive
3034 : // objects should not be assigned the same hash code. If the test below fails
3035 : // the random number generator should be evaluated.
3036 6 : CHECK_NE(hash, hash2);
3037 6 : CcTest::CollectAllGarbage();
3038 12 : int hash3 = v8::Object::New(isolate)->GetIdentityHash();
3039 : // Make sure that the identity hash is not based on the initial address of
3040 : // the object alone. If the test below fails the random number generator
3041 : // should be evaluated.
3042 6 : CHECK_NE(hash, hash3);
3043 6 : int hash4 = obj->GetIdentityHash();
3044 6 : CHECK_EQ(hash, hash4);
3045 :
3046 : // Check identity hashes behaviour in the presence of JS accessors.
3047 : // Put a getter for 'v8::IdentityHash' on the Object's prototype:
3048 : {
3049 : CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
3050 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3051 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3052 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3053 : }
3054 : {
3055 : CompileRun(
3056 : "function cnst() { return 42; };\n"
3057 : "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3058 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3059 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3060 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3061 6 : }
3062 6 : }
3063 :
3064 :
3065 12 : void GlobalProxyIdentityHash(bool set_in_js) {
3066 12 : LocalContext env;
3067 12 : v8::Isolate* isolate = env->GetIsolate();
3068 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3069 24 : v8::HandleScope scope(isolate);
3070 12 : Local<Object> global_proxy = env->Global();
3071 : i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
3072 60 : CHECK(env->Global()
3073 : ->Set(env.local(), v8_str("global"), global_proxy)
3074 : .FromJust());
3075 : int32_t hash1;
3076 12 : if (set_in_js) {
3077 : CompileRun("var m = new Set(); m.add(global);");
3078 6 : i::Object original_hash = i_global_proxy->GetHash();
3079 6 : CHECK(original_hash->IsSmi());
3080 6 : hash1 = i::Smi::ToInt(original_hash);
3081 : } else {
3082 12 : hash1 = i_global_proxy->GetOrCreateHash(i_isolate)->value();
3083 : }
3084 : // Hash should be retained after being detached.
3085 12 : env->DetachGlobal();
3086 12 : int hash2 = global_proxy->GetIdentityHash();
3087 12 : CHECK_EQ(hash1, hash2);
3088 : {
3089 : // Re-attach global proxy to a new context, hash should stay the same.
3090 12 : LocalContext env2(nullptr, Local<ObjectTemplate>(), global_proxy);
3091 12 : int hash3 = global_proxy->GetIdentityHash();
3092 12 : CHECK_EQ(hash1, hash3);
3093 12 : }
3094 12 : }
3095 :
3096 :
3097 25881 : THREADED_TEST(GlobalProxyIdentityHash) {
3098 6 : GlobalProxyIdentityHash(true);
3099 6 : GlobalProxyIdentityHash(false);
3100 6 : }
3101 :
3102 :
3103 25880 : TEST(SymbolIdentityHash) {
3104 5 : LocalContext env;
3105 5 : v8::Isolate* isolate = env->GetIsolate();
3106 10 : v8::HandleScope scope(isolate);
3107 :
3108 : {
3109 5 : Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3110 5 : int hash = symbol->GetIdentityHash();
3111 5 : int hash1 = symbol->GetIdentityHash();
3112 5 : CHECK_EQ(hash, hash1);
3113 5 : CcTest::CollectAllGarbage();
3114 5 : int hash3 = symbol->GetIdentityHash();
3115 5 : CHECK_EQ(hash, hash3);
3116 : }
3117 :
3118 : {
3119 : v8::Local<v8::Symbol> js_symbol =
3120 : CompileRun("Symbol('foo')").As<v8::Symbol>();
3121 5 : int hash = js_symbol->GetIdentityHash();
3122 5 : int hash1 = js_symbol->GetIdentityHash();
3123 5 : CHECK_EQ(hash, hash1);
3124 5 : CcTest::CollectAllGarbage();
3125 5 : int hash3 = js_symbol->GetIdentityHash();
3126 5 : CHECK_EQ(hash, hash3);
3127 5 : }
3128 5 : }
3129 :
3130 :
3131 25880 : TEST(StringIdentityHash) {
3132 5 : LocalContext env;
3133 5 : v8::Isolate* isolate = env->GetIsolate();
3134 10 : v8::HandleScope scope(isolate);
3135 :
3136 5 : Local<v8::String> str = v8_str("str1");
3137 5 : int hash = str->GetIdentityHash();
3138 5 : int hash1 = str->GetIdentityHash();
3139 5 : CHECK_EQ(hash, hash1);
3140 5 : CcTest::CollectAllGarbage();
3141 5 : int hash3 = str->GetIdentityHash();
3142 5 : CHECK_EQ(hash, hash3);
3143 :
3144 5 : Local<v8::String> str2 = v8_str("str1");
3145 5 : int hash4 = str2->GetIdentityHash();
3146 10 : CHECK_EQ(hash, hash4);
3147 5 : }
3148 :
3149 :
3150 25881 : THREADED_TEST(SymbolProperties) {
3151 6 : LocalContext env;
3152 6 : v8::Isolate* isolate = env->GetIsolate();
3153 12 : v8::HandleScope scope(isolate);
3154 :
3155 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3156 6 : v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3157 6 : v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
3158 6 : v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
3159 6 : v8::Local<v8::Symbol> sym4 = v8::Symbol::New(isolate, v8_str("native"));
3160 :
3161 6 : CcTest::CollectAllGarbage();
3162 :
3163 : // Check basic symbol functionality.
3164 6 : CHECK(sym1->IsSymbol());
3165 6 : CHECK(sym2->IsSymbol());
3166 6 : CHECK(!obj->IsSymbol());
3167 :
3168 12 : CHECK(sym1->Equals(env.local(), sym1).FromJust());
3169 12 : CHECK(sym2->Equals(env.local(), sym2).FromJust());
3170 12 : CHECK(!sym1->Equals(env.local(), sym2).FromJust());
3171 12 : CHECK(!sym2->Equals(env.local(), sym1).FromJust());
3172 6 : CHECK(sym1->StrictEquals(sym1));
3173 6 : CHECK(sym2->StrictEquals(sym2));
3174 6 : CHECK(!sym1->StrictEquals(sym2));
3175 6 : CHECK(!sym2->StrictEquals(sym1));
3176 :
3177 24 : CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
3178 :
3179 : v8::Local<v8::Value> sym_val = sym2;
3180 6 : CHECK(sym_val->IsSymbol());
3181 12 : CHECK(sym_val->Equals(env.local(), sym2).FromJust());
3182 6 : CHECK(sym_val->StrictEquals(sym2));
3183 12 : CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
3184 :
3185 6 : v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3186 6 : CHECK(sym_obj->IsSymbolObject());
3187 6 : CHECK(!sym2->IsSymbolObject());
3188 6 : CHECK(!obj->IsSymbolObject());
3189 12 : CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
3190 6 : CHECK(!sym_obj->StrictEquals(sym2));
3191 12 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3192 : ->Equals(env.local(), sym_obj)
3193 : .FromJust());
3194 18 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3195 : ->ValueOf()
3196 : ->Equals(env.local(), sym2)
3197 : .FromJust());
3198 :
3199 : // Make sure delete of a non-existent symbol property works.
3200 12 : CHECK(obj->Delete(env.local(), sym1).FromJust());
3201 12 : CHECK(!obj->Has(env.local(), sym1).FromJust());
3202 :
3203 18 : CHECK(
3204 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
3205 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3206 24 : CHECK_EQ(1503, obj->Get(env.local(), sym1)
3207 : .ToLocalChecked()
3208 : ->Int32Value(env.local())
3209 : .FromJust());
3210 18 : CHECK(
3211 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
3212 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3213 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3214 : .ToLocalChecked()
3215 : ->Int32Value(env.local())
3216 : .FromJust());
3217 12 : CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
3218 :
3219 12 : CHECK_EQ(0u,
3220 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3221 : unsigned num_props =
3222 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3223 24 : CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
3224 : .FromJust());
3225 12 : CHECK_EQ(1u,
3226 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3227 12 : CHECK_EQ(num_props + 1,
3228 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3229 :
3230 6 : CcTest::CollectAllGarbage();
3231 :
3232 12 : CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
3233 : SymbolAccessorSetter)
3234 : .FromJust());
3235 12 : CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
3236 18 : CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
3237 30 : CHECK(obj->Get(env.local(), sym3)
3238 : .ToLocalChecked()
3239 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3240 : .FromJust());
3241 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3242 : .ToLocalChecked()
3243 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3244 : .FromJust());
3245 :
3246 12 : CHECK(obj->SetNativeDataProperty(env.local(), sym4, SymbolAccessorGetter)
3247 : .FromJust());
3248 12 : CHECK(obj->Get(env.local(), sym4).ToLocalChecked()->IsUndefined());
3249 24 : CHECK(obj->Set(env.local(), v8_str("accessor_native"),
3250 : v8::Integer::New(isolate, 123))
3251 : .FromJust());
3252 24 : CHECK_EQ(123, obj->Get(env.local(), sym4)
3253 : .ToLocalChecked()
3254 : ->Int32Value(env.local())
3255 : .FromJust());
3256 18 : CHECK(obj->Set(env.local(), sym4, v8::Integer::New(isolate, 314)).FromJust());
3257 30 : CHECK(obj->Get(env.local(), sym4)
3258 : .ToLocalChecked()
3259 : ->Equals(env.local(), v8::Integer::New(isolate, 314))
3260 : .FromJust());
3261 18 : CHECK(obj->Delete(env.local(), v8_str("accessor_native")).FromJust());
3262 :
3263 : // Add another property and delete it afterwards to force the object in
3264 : // slow case.
3265 18 : CHECK(
3266 : obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
3267 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3268 : .ToLocalChecked()
3269 : ->Int32Value(env.local())
3270 : .FromJust());
3271 24 : CHECK_EQ(2008, obj->Get(env.local(), sym2)
3272 : .ToLocalChecked()
3273 : ->Int32Value(env.local())
3274 : .FromJust());
3275 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3276 : .ToLocalChecked()
3277 : ->Int32Value(env.local())
3278 : .FromJust());
3279 12 : CHECK_EQ(2u,
3280 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3281 :
3282 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3283 12 : CHECK(obj->Has(env.local(), sym2).FromJust());
3284 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3285 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3286 12 : CHECK(obj->Delete(env.local(), sym2).FromJust());
3287 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3288 12 : CHECK(!obj->Has(env.local(), sym2).FromJust());
3289 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3290 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3291 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3292 : .ToLocalChecked()
3293 : ->Int32Value(env.local())
3294 : .FromJust());
3295 30 : CHECK(obj->Get(env.local(), sym3)
3296 : .ToLocalChecked()
3297 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3298 : .FromJust());
3299 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3300 : .ToLocalChecked()
3301 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3302 : .FromJust());
3303 12 : CHECK_EQ(2u,
3304 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3305 :
3306 : // Symbol properties are inherited.
3307 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3308 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3309 12 : CHECK(child->Has(env.local(), sym1).FromJust());
3310 24 : CHECK_EQ(2002, child->Get(env.local(), sym1)
3311 : .ToLocalChecked()
3312 : ->Int32Value(env.local())
3313 : .FromJust());
3314 30 : CHECK(obj->Get(env.local(), sym3)
3315 : .ToLocalChecked()
3316 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3317 : .FromJust());
3318 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3319 : .ToLocalChecked()
3320 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3321 : .FromJust());
3322 12 : CHECK_EQ(0u,
3323 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3324 6 : }
3325 :
3326 :
3327 25881 : THREADED_TEST(SymbolTemplateProperties) {
3328 6 : LocalContext env;
3329 6 : v8::Isolate* isolate = env->GetIsolate();
3330 12 : v8::HandleScope scope(isolate);
3331 6 : v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3332 6 : v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3333 6 : CHECK(!name.IsEmpty());
3334 18 : foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3335 : v8::Local<v8::Object> new_instance =
3336 18 : foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3337 6 : CHECK(!new_instance.IsEmpty());
3338 18 : CHECK(new_instance->Has(env.local(), name).FromJust());
3339 6 : }
3340 :
3341 :
3342 25881 : THREADED_TEST(PrivatePropertiesOnProxies) {
3343 6 : LocalContext env;
3344 6 : v8::Isolate* isolate = env->GetIsolate();
3345 12 : v8::HandleScope scope(isolate);
3346 :
3347 6 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3348 6 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3349 :
3350 : v8::Local<v8::Proxy> proxy =
3351 6 : v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3352 :
3353 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3354 : v8::Local<v8::Private> priv2 =
3355 6 : v8::Private::New(isolate, v8_str("my-private"));
3356 :
3357 6 : CcTest::CollectAllGarbage();
3358 :
3359 30 : CHECK(priv2->Name()
3360 : ->Equals(env.local(),
3361 : v8::String::NewFromUtf8(isolate, "my-private",
3362 : v8::NewStringType::kNormal)
3363 : .ToLocalChecked())
3364 : .FromJust());
3365 :
3366 : // Make sure delete of a non-existent private symbol property works.
3367 12 : proxy->DeletePrivate(env.local(), priv1).FromJust();
3368 12 : CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3369 :
3370 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3371 : .FromJust());
3372 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3373 18 : CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3374 : .ToLocalChecked()
3375 : ->Int32Value(env.local())
3376 : .FromJust());
3377 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3378 : .FromJust());
3379 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3380 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3381 : .ToLocalChecked()
3382 : ->Int32Value(env.local())
3383 : .FromJust());
3384 :
3385 12 : CHECK_EQ(0u,
3386 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3387 : unsigned num_props =
3388 12 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3389 24 : CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3390 : isolate, "bla", v8::NewStringType::kNormal)
3391 : .ToLocalChecked(),
3392 : v8::Integer::New(isolate, 20))
3393 : .FromJust());
3394 12 : CHECK_EQ(1u,
3395 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3396 12 : CHECK_EQ(num_props + 1,
3397 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3398 :
3399 6 : CcTest::CollectAllGarbage();
3400 :
3401 : // Add another property and delete it afterwards to force the object in
3402 : // slow case.
3403 18 : CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3404 : .FromJust());
3405 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3406 : .ToLocalChecked()
3407 : ->Int32Value(env.local())
3408 : .FromJust());
3409 18 : CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3410 : .ToLocalChecked()
3411 : ->Int32Value(env.local())
3412 : .FromJust());
3413 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3414 : .ToLocalChecked()
3415 : ->Int32Value(env.local())
3416 : .FromJust());
3417 12 : CHECK_EQ(1u,
3418 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3419 :
3420 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3421 12 : CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3422 12 : CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3423 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3424 12 : CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3425 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3426 : .ToLocalChecked()
3427 : ->Int32Value(env.local())
3428 : .FromJust());
3429 12 : CHECK_EQ(1u,
3430 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3431 :
3432 : // Private properties are not inherited (for the time being).
3433 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3434 12 : CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3435 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3436 12 : CHECK_EQ(0u,
3437 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3438 6 : }
3439 :
3440 :
3441 25881 : THREADED_TEST(PrivateProperties) {
3442 6 : LocalContext env;
3443 6 : v8::Isolate* isolate = env->GetIsolate();
3444 12 : v8::HandleScope scope(isolate);
3445 :
3446 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3447 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3448 : v8::Local<v8::Private> priv2 =
3449 6 : v8::Private::New(isolate, v8_str("my-private"));
3450 :
3451 6 : CcTest::CollectAllGarbage();
3452 :
3453 30 : CHECK(priv2->Name()
3454 : ->Equals(env.local(),
3455 : v8::String::NewFromUtf8(isolate, "my-private",
3456 : v8::NewStringType::kNormal)
3457 : .ToLocalChecked())
3458 : .FromJust());
3459 :
3460 : // Make sure delete of a non-existent private symbol property works.
3461 12 : obj->DeletePrivate(env.local(), priv1).FromJust();
3462 12 : CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3463 :
3464 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3465 : .FromJust());
3466 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3467 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3468 : .ToLocalChecked()
3469 : ->Int32Value(env.local())
3470 : .FromJust());
3471 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3472 : .FromJust());
3473 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3474 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3475 : .ToLocalChecked()
3476 : ->Int32Value(env.local())
3477 : .FromJust());
3478 :
3479 12 : CHECK_EQ(0u,
3480 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3481 : unsigned num_props =
3482 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3483 24 : CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3484 : isolate, "bla", v8::NewStringType::kNormal)
3485 : .ToLocalChecked(),
3486 : v8::Integer::New(isolate, 20))
3487 : .FromJust());
3488 12 : CHECK_EQ(1u,
3489 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3490 12 : CHECK_EQ(num_props + 1,
3491 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3492 :
3493 6 : CcTest::CollectAllGarbage();
3494 :
3495 : // Add another property and delete it afterwards to force the object in
3496 : // slow case.
3497 18 : CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3498 : .FromJust());
3499 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3500 : .ToLocalChecked()
3501 : ->Int32Value(env.local())
3502 : .FromJust());
3503 18 : CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3504 : .ToLocalChecked()
3505 : ->Int32Value(env.local())
3506 : .FromJust());
3507 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3508 : .ToLocalChecked()
3509 : ->Int32Value(env.local())
3510 : .FromJust());
3511 12 : CHECK_EQ(1u,
3512 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3513 :
3514 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3515 12 : CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3516 12 : CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3517 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3518 12 : CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3519 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3520 : .ToLocalChecked()
3521 : ->Int32Value(env.local())
3522 : .FromJust());
3523 12 : CHECK_EQ(1u,
3524 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3525 :
3526 : // Private properties are not inherited (for the time being).
3527 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3528 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3529 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3530 12 : CHECK_EQ(0u,
3531 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3532 6 : }
3533 :
3534 :
3535 25881 : THREADED_TEST(GlobalSymbols) {
3536 6 : LocalContext env;
3537 6 : v8::Isolate* isolate = env->GetIsolate();
3538 12 : v8::HandleScope scope(isolate);
3539 :
3540 6 : v8::Local<String> name = v8_str("my-symbol");
3541 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3542 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3543 6 : CHECK(glob2->SameValue(glob));
3544 :
3545 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3546 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3547 6 : CHECK(glob_api2->SameValue(glob_api));
3548 6 : CHECK(!glob_api->SameValue(glob));
3549 :
3550 6 : v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3551 6 : CHECK(!sym->SameValue(glob));
3552 :
3553 : CompileRun("var sym2 = Symbol.for('my-symbol')");
3554 : v8::Local<Value> sym2 =
3555 30 : env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3556 6 : CHECK(sym2->SameValue(glob));
3557 12 : CHECK(!sym2->SameValue(glob_api));
3558 6 : }
3559 :
3560 25881 : THREADED_TEST(GlobalSymbolsNoContext) {
3561 6 : v8::Isolate* isolate = CcTest::isolate();
3562 6 : v8::HandleScope scope(isolate);
3563 :
3564 6 : v8::Local<String> name = v8_str("my-symbol");
3565 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3566 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3567 6 : CHECK(glob2->SameValue(glob));
3568 :
3569 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3570 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3571 6 : CHECK(glob_api2->SameValue(glob_api));
3572 6 : CHECK(!glob_api->SameValue(glob));
3573 6 : }
3574 :
3575 60 : static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3576 : const char* name) {
3577 60 : LocalContext env;
3578 60 : v8::Isolate* isolate = env->GetIsolate();
3579 120 : v8::HandleScope scope(isolate);
3580 :
3581 60 : v8::Local<v8::Symbol> symbol = getter(isolate);
3582 120 : std::string script = std::string("var sym = ") + name;
3583 : CompileRun(script.c_str());
3584 : v8::Local<Value> value =
3585 300 : env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3586 :
3587 60 : CHECK(!value.IsEmpty());
3588 60 : CHECK(!symbol.IsEmpty());
3589 120 : CHECK(value->SameValue(symbol));
3590 60 : }
3591 :
3592 :
3593 25881 : THREADED_TEST(WellKnownSymbols) {
3594 6 : CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3595 6 : CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3596 6 : CheckWellKnownSymbol(v8::Symbol::GetHasInstance, "Symbol.hasInstance");
3597 : CheckWellKnownSymbol(v8::Symbol::GetIsConcatSpreadable,
3598 6 : "Symbol.isConcatSpreadable");
3599 6 : CheckWellKnownSymbol(v8::Symbol::GetMatch, "Symbol.match");
3600 6 : CheckWellKnownSymbol(v8::Symbol::GetReplace, "Symbol.replace");
3601 6 : CheckWellKnownSymbol(v8::Symbol::GetSearch, "Symbol.search");
3602 6 : CheckWellKnownSymbol(v8::Symbol::GetSplit, "Symbol.split");
3603 6 : CheckWellKnownSymbol(v8::Symbol::GetToPrimitive, "Symbol.toPrimitive");
3604 6 : CheckWellKnownSymbol(v8::Symbol::GetToStringTag, "Symbol.toStringTag");
3605 6 : }
3606 :
3607 :
3608 25881 : THREADED_TEST(GlobalPrivates) {
3609 6 : i::FLAG_allow_natives_syntax = true;
3610 6 : LocalContext env;
3611 6 : v8::Isolate* isolate = env->GetIsolate();
3612 12 : v8::HandleScope scope(isolate);
3613 :
3614 6 : v8::Local<String> name = v8_str("my-private");
3615 6 : v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3616 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3617 18 : CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3618 : .FromJust());
3619 :
3620 6 : v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3621 12 : CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3622 :
3623 6 : v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3624 12 : CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3625 :
3626 : CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3627 : v8::Local<Value> intern =
3628 30 : env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3629 18 : CHECK(!obj->Has(env.local(), intern).FromJust());
3630 6 : }
3631 :
3632 :
3633 : class ScopedArrayBufferContents {
3634 : public:
3635 : explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3636 36 : : contents_(contents) {}
3637 36 : ~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
3638 : void* Data() const { return contents_.Data(); }
3639 : size_t ByteLength() const { return contents_.ByteLength(); }
3640 :
3641 : void* AllocationBase() const { return contents_.AllocationBase(); }
3642 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3643 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3644 : return contents_.AllocationMode();
3645 : }
3646 :
3647 : private:
3648 : const v8::ArrayBuffer::Contents contents_;
3649 : };
3650 :
3651 : template <typename T>
3652 282 : static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3653 282 : CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3654 564 : for (int i = 0; i < value->InternalFieldCount(); i++) {
3655 1692 : CHECK_EQ(0, value->GetInternalField(i)
3656 : ->Int32Value(CcTest::isolate()->GetCurrentContext())
3657 : .FromJust());
3658 : }
3659 282 : }
3660 :
3661 :
3662 25881 : THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3663 6 : LocalContext env;
3664 6 : v8::Isolate* isolate = env->GetIsolate();
3665 12 : v8::HandleScope handle_scope(isolate);
3666 :
3667 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3668 6 : CheckInternalFieldsAreZero(ab);
3669 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3670 6 : CHECK(!ab->IsExternal());
3671 6 : CcTest::CollectAllGarbage();
3672 :
3673 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3674 6 : CHECK(ab->IsExternal());
3675 :
3676 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3677 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3678 6 : CHECK_NOT_NULL(data);
3679 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3680 :
3681 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3682 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3683 :
3684 : result = CompileRun(
3685 : "var u8 = new Uint8Array(ab);"
3686 : "u8[0] = 0xFF;"
3687 : "u8[1] = 0xAA;"
3688 : "u8.length");
3689 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3690 12 : CHECK_EQ(0xFF, data[0]);
3691 12 : CHECK_EQ(0xAA, data[1]);
3692 6 : data[0] = 0xCC;
3693 6 : data[1] = 0x11;
3694 : result = CompileRun("u8[0] + u8[1]");
3695 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3696 6 : }
3697 :
3698 :
3699 25881 : THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3700 6 : LocalContext env;
3701 6 : v8::Isolate* isolate = env->GetIsolate();
3702 12 : v8::HandleScope handle_scope(isolate);
3703 :
3704 :
3705 : v8::Local<v8::Value> result = CompileRun(
3706 : "var ab1 = new ArrayBuffer(2);"
3707 : "var u8_a = new Uint8Array(ab1);"
3708 : "u8_a[0] = 0xAA;"
3709 : "u8_a[1] = 0xFF; u8_a.buffer");
3710 : Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3711 6 : CheckInternalFieldsAreZero(ab1);
3712 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3713 6 : CHECK(!ab1->IsExternal());
3714 12 : ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3715 6 : CHECK(ab1->IsExternal());
3716 :
3717 : result = CompileRun("ab1.byteLength");
3718 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3719 : result = CompileRun("u8_a[0]");
3720 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3721 : result = CompileRun("u8_a[1]");
3722 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3723 : result = CompileRun(
3724 : "var u8_b = new Uint8Array(ab1);"
3725 : "u8_b[0] = 0xBB;"
3726 : "u8_a[0]");
3727 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3728 : result = CompileRun("u8_b[1]");
3729 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3730 :
3731 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3732 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3733 12 : CHECK_EQ(0xBB, ab1_data[0]);
3734 12 : CHECK_EQ(0xFF, ab1_data[1]);
3735 6 : ab1_data[0] = 0xCC;
3736 6 : ab1_data[1] = 0x11;
3737 : result = CompileRun("u8_a[0] + u8_a[1]");
3738 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3739 6 : }
3740 :
3741 :
3742 25881 : THREADED_TEST(ArrayBuffer_External) {
3743 6 : LocalContext env;
3744 6 : v8::Isolate* isolate = env->GetIsolate();
3745 12 : v8::HandleScope handle_scope(isolate);
3746 :
3747 : i::ScopedVector<uint8_t> my_data(100);
3748 : memset(my_data.start(), 0, 100);
3749 : Local<v8::ArrayBuffer> ab3 =
3750 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3751 6 : CheckInternalFieldsAreZero(ab3);
3752 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3753 6 : CHECK(ab3->IsExternal());
3754 :
3755 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3756 :
3757 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3758 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3759 :
3760 : result = CompileRun(
3761 : "var u8_b = new Uint8Array(ab3);"
3762 : "u8_b[0] = 0xBB;"
3763 : "u8_b[1] = 0xCC;"
3764 : "u8_b.length");
3765 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3766 12 : CHECK_EQ(0xBB, my_data[0]);
3767 12 : CHECK_EQ(0xCC, my_data[1]);
3768 6 : my_data[0] = 0xCC;
3769 6 : my_data[1] = 0x11;
3770 : result = CompileRun("u8_b[0] + u8_b[1]");
3771 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3772 6 : }
3773 :
3774 25881 : THREADED_TEST(ArrayBuffer_DisableDetach) {
3775 6 : LocalContext env;
3776 6 : v8::Isolate* isolate = env->GetIsolate();
3777 12 : v8::HandleScope handle_scope(isolate);
3778 :
3779 : i::ScopedVector<uint8_t> my_data(100);
3780 : memset(my_data.start(), 0, 100);
3781 : Local<v8::ArrayBuffer> ab =
3782 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3783 6 : CHECK(ab->IsDetachable());
3784 :
3785 : i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3786 : buf->set_is_detachable(false);
3787 :
3788 12 : CHECK(!ab->IsDetachable());
3789 6 : }
3790 :
3791 12 : static void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
3792 12 : CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3793 12 : CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3794 12 : }
3795 :
3796 108 : static void CheckIsDetached(v8::Local<v8::TypedArray> ta) {
3797 108 : CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3798 108 : CHECK_EQ(0, static_cast<int>(ta->Length()));
3799 108 : CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3800 108 : }
3801 :
3802 54 : static void CheckIsTypedArrayVarDetached(const char* name) {
3803 : i::ScopedVector<char> source(1024);
3804 : i::SNPrintF(source,
3805 : "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3806 54 : name, name, name);
3807 54 : CHECK(CompileRun(source.start())->IsTrue());
3808 : v8::Local<v8::TypedArray> ta =
3809 54 : v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3810 54 : CheckIsDetached(ta);
3811 54 : }
3812 :
3813 : template <typename TypedArray, int kElementSize>
3814 54 : static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3815 : int byteOffset, int length) {
3816 54 : v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3817 54 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3818 54 : CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3819 54 : CHECK_EQ(length, static_cast<int>(ta->Length()));
3820 54 : CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3821 54 : return ta;
3822 : }
3823 :
3824 25881 : THREADED_TEST(ArrayBuffer_DetachingApi) {
3825 6 : LocalContext env;
3826 6 : v8::Isolate* isolate = env->GetIsolate();
3827 12 : v8::HandleScope handle_scope(isolate);
3828 :
3829 6 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3830 :
3831 : v8::Local<v8::Uint8Array> u8a =
3832 6 : CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3833 : v8::Local<v8::Uint8ClampedArray> u8c =
3834 6 : CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3835 : v8::Local<v8::Int8Array> i8a =
3836 6 : CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3837 :
3838 : v8::Local<v8::Uint16Array> u16a =
3839 6 : CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3840 : v8::Local<v8::Int16Array> i16a =
3841 6 : CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3842 :
3843 : v8::Local<v8::Uint32Array> u32a =
3844 6 : CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3845 : v8::Local<v8::Int32Array> i32a =
3846 6 : CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3847 :
3848 : v8::Local<v8::Float32Array> f32a =
3849 6 : CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3850 : v8::Local<v8::Float64Array> f64a =
3851 6 : CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3852 :
3853 6 : v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3854 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3855 6 : CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3856 6 : CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3857 :
3858 12 : ScopedArrayBufferContents contents(buffer->Externalize());
3859 6 : buffer->Detach();
3860 6 : CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3861 6 : CheckIsDetached(u8a);
3862 6 : CheckIsDetached(u8c);
3863 6 : CheckIsDetached(i8a);
3864 6 : CheckIsDetached(u16a);
3865 6 : CheckIsDetached(i16a);
3866 6 : CheckIsDetached(u32a);
3867 6 : CheckIsDetached(i32a);
3868 6 : CheckIsDetached(f32a);
3869 6 : CheckIsDetached(f64a);
3870 12 : CheckDataViewIsDetached(dv);
3871 6 : }
3872 :
3873 25881 : THREADED_TEST(ArrayBuffer_DetachingScript) {
3874 6 : LocalContext env;
3875 6 : v8::Isolate* isolate = env->GetIsolate();
3876 12 : v8::HandleScope handle_scope(isolate);
3877 :
3878 : CompileRun(
3879 : "var ab = new ArrayBuffer(1024);"
3880 : "var u8a = new Uint8Array(ab, 1, 1023);"
3881 : "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3882 : "var i8a = new Int8Array(ab, 1, 1023);"
3883 : "var u16a = new Uint16Array(ab, 2, 511);"
3884 : "var i16a = new Int16Array(ab, 2, 511);"
3885 : "var u32a = new Uint32Array(ab, 4, 255);"
3886 : "var i32a = new Int32Array(ab, 4, 255);"
3887 : "var f32a = new Float32Array(ab, 4, 255);"
3888 : "var f64a = new Float64Array(ab, 8, 127);"
3889 : "var dv = new DataView(ab, 1, 1023);");
3890 :
3891 : v8::Local<v8::ArrayBuffer> ab =
3892 : Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3893 :
3894 6 : v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3895 :
3896 12 : ScopedArrayBufferContents contents(ab->Externalize());
3897 6 : ab->Detach();
3898 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3899 6 : CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3900 :
3901 6 : CheckIsTypedArrayVarDetached("u8a");
3902 6 : CheckIsTypedArrayVarDetached("u8c");
3903 6 : CheckIsTypedArrayVarDetached("i8a");
3904 6 : CheckIsTypedArrayVarDetached("u16a");
3905 6 : CheckIsTypedArrayVarDetached("i16a");
3906 6 : CheckIsTypedArrayVarDetached("u32a");
3907 6 : CheckIsTypedArrayVarDetached("i32a");
3908 6 : CheckIsTypedArrayVarDetached("f32a");
3909 6 : CheckIsTypedArrayVarDetached("f64a");
3910 :
3911 6 : CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3912 12 : CheckDataViewIsDetached(dv);
3913 6 : }
3914 :
3915 25881 : THREADED_TEST(ArrayBuffer_AllocationInformation) {
3916 6 : LocalContext env;
3917 6 : v8::Isolate* isolate = env->GetIsolate();
3918 12 : v8::HandleScope handle_scope(isolate);
3919 :
3920 : const size_t ab_size = 1024;
3921 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
3922 12 : ScopedArrayBufferContents contents(ab->Externalize());
3923 :
3924 : // Array buffers should have normal allocation mode.
3925 6 : CHECK_EQ(contents.AllocationMode(),
3926 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
3927 : // The allocation must contain the buffer (normally they will be equal, but
3928 : // this is not required by the contract).
3929 6 : CHECK_NOT_NULL(contents.AllocationBase());
3930 : const uintptr_t alloc =
3931 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
3932 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
3933 6 : CHECK_LE(alloc, data);
3934 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
3935 6 : }
3936 :
3937 25881 : THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
3938 6 : LocalContext env;
3939 6 : v8::Isolate* isolate = env->GetIsolate();
3940 12 : v8::HandleScope handle_scope(isolate);
3941 :
3942 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 0);
3943 6 : CheckInternalFieldsAreZero(ab);
3944 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3945 6 : CHECK(!ab->IsExternal());
3946 :
3947 : // Externalize the buffer (taking ownership of the backing store memory).
3948 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3949 :
3950 6 : Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0);
3951 : // Calling Buffer() will materialize the ArrayBuffer (transitioning it from
3952 : // on-heap to off-heap if need be). This should not affect whether it is
3953 : // marked as is_external or not.
3954 6 : USE(u8a->Buffer());
3955 :
3956 12 : CHECK(ab->IsExternal());
3957 6 : }
3958 :
3959 : class ScopedSharedArrayBufferContents {
3960 : public:
3961 : explicit ScopedSharedArrayBufferContents(
3962 : const v8::SharedArrayBuffer::Contents& contents)
3963 18 : : contents_(contents) {}
3964 18 : ~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
3965 : void* Data() const { return contents_.Data(); }
3966 : size_t ByteLength() const { return contents_.ByteLength(); }
3967 :
3968 : void* AllocationBase() const { return contents_.AllocationBase(); }
3969 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3970 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3971 : return contents_.AllocationMode();
3972 : }
3973 :
3974 : private:
3975 : const v8::SharedArrayBuffer::Contents contents_;
3976 : };
3977 :
3978 :
3979 25881 : THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
3980 6 : i::FLAG_harmony_sharedarraybuffer = true;
3981 6 : LocalContext env;
3982 6 : v8::Isolate* isolate = env->GetIsolate();
3983 12 : v8::HandleScope handle_scope(isolate);
3984 :
3985 6 : Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
3986 6 : CheckInternalFieldsAreZero(ab);
3987 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3988 6 : CHECK(!ab->IsExternal());
3989 6 : CcTest::CollectAllGarbage();
3990 :
3991 12 : ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
3992 6 : CHECK(ab->IsExternal());
3993 :
3994 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3995 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3996 6 : CHECK_NOT_NULL(data);
3997 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3998 :
3999 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
4000 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4001 :
4002 : result = CompileRun(
4003 : "var u8 = new Uint8Array(ab);"
4004 : "u8[0] = 0xFF;"
4005 : "u8[1] = 0xAA;"
4006 : "u8.length");
4007 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4008 12 : CHECK_EQ(0xFF, data[0]);
4009 12 : CHECK_EQ(0xAA, data[1]);
4010 6 : data[0] = 0xCC;
4011 6 : data[1] = 0x11;
4012 : result = CompileRun("u8[0] + u8[1]");
4013 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4014 6 : }
4015 :
4016 :
4017 25881 : THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
4018 6 : i::FLAG_harmony_sharedarraybuffer = true;
4019 6 : LocalContext env;
4020 6 : v8::Isolate* isolate = env->GetIsolate();
4021 12 : v8::HandleScope handle_scope(isolate);
4022 :
4023 :
4024 : v8::Local<v8::Value> result = CompileRun(
4025 : "var ab1 = new SharedArrayBuffer(2);"
4026 : "var u8_a = new Uint8Array(ab1);"
4027 : "u8_a[0] = 0xAA;"
4028 : "u8_a[1] = 0xFF; u8_a.buffer");
4029 : Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
4030 6 : CheckInternalFieldsAreZero(ab1);
4031 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
4032 6 : CHECK(!ab1->IsExternal());
4033 12 : ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
4034 6 : CHECK(ab1->IsExternal());
4035 :
4036 : result = CompileRun("ab1.byteLength");
4037 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
4038 : result = CompileRun("u8_a[0]");
4039 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
4040 : result = CompileRun("u8_a[1]");
4041 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4042 : result = CompileRun(
4043 : "var u8_b = new Uint8Array(ab1);"
4044 : "u8_b[0] = 0xBB;"
4045 : "u8_a[0]");
4046 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
4047 : result = CompileRun("u8_b[1]");
4048 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4049 :
4050 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
4051 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
4052 12 : CHECK_EQ(0xBB, ab1_data[0]);
4053 12 : CHECK_EQ(0xFF, ab1_data[1]);
4054 6 : ab1_data[0] = 0xCC;
4055 6 : ab1_data[1] = 0x11;
4056 : result = CompileRun("u8_a[0] + u8_a[1]");
4057 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4058 6 : }
4059 :
4060 :
4061 25881 : THREADED_TEST(SharedArrayBuffer_External) {
4062 6 : i::FLAG_harmony_sharedarraybuffer = true;
4063 6 : LocalContext env;
4064 6 : v8::Isolate* isolate = env->GetIsolate();
4065 12 : v8::HandleScope handle_scope(isolate);
4066 :
4067 : i::ScopedVector<uint8_t> my_data(100);
4068 : memset(my_data.start(), 0, 100);
4069 : Local<v8::SharedArrayBuffer> ab3 =
4070 6 : v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
4071 6 : CheckInternalFieldsAreZero(ab3);
4072 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
4073 6 : CHECK(ab3->IsExternal());
4074 :
4075 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
4076 :
4077 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
4078 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4079 :
4080 : result = CompileRun(
4081 : "var u8_b = new Uint8Array(ab3);"
4082 : "u8_b[0] = 0xBB;"
4083 : "u8_b[1] = 0xCC;"
4084 : "u8_b.length");
4085 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4086 12 : CHECK_EQ(0xBB, my_data[0]);
4087 12 : CHECK_EQ(0xCC, my_data[1]);
4088 6 : my_data[0] = 0xCC;
4089 6 : my_data[1] = 0x11;
4090 : result = CompileRun("u8_b[0] + u8_b[1]");
4091 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4092 6 : }
4093 :
4094 :
4095 25881 : THREADED_TEST(HiddenProperties) {
4096 6 : LocalContext env;
4097 6 : v8::Isolate* isolate = env->GetIsolate();
4098 12 : v8::HandleScope scope(isolate);
4099 :
4100 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4101 : v8::Local<v8::Private> key =
4102 6 : v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
4103 6 : v8::Local<v8::String> empty = v8_str("");
4104 6 : v8::Local<v8::String> prop_name = v8_str("prop_name");
4105 :
4106 6 : CcTest::CollectAllGarbage();
4107 :
4108 : // Make sure delete of a non-existent hidden value works
4109 12 : obj->DeletePrivate(env.local(), key).FromJust();
4110 :
4111 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
4112 : .FromJust());
4113 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
4114 : .ToLocalChecked()
4115 : ->Int32Value(env.local())
4116 : .FromJust());
4117 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4118 : .FromJust());
4119 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4120 : .ToLocalChecked()
4121 : ->Int32Value(env.local())
4122 : .FromJust());
4123 :
4124 6 : CcTest::CollectAllGarbage();
4125 :
4126 : // Make sure we do not find the hidden property.
4127 12 : CHECK(!obj->Has(env.local(), empty).FromJust());
4128 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4129 : .ToLocalChecked()
4130 : ->Int32Value(env.local())
4131 : .FromJust());
4132 12 : CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
4133 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4134 : .ToLocalChecked()
4135 : ->Int32Value(env.local())
4136 : .FromJust());
4137 18 : CHECK(
4138 : obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
4139 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4140 : .ToLocalChecked()
4141 : ->Int32Value(env.local())
4142 : .FromJust());
4143 24 : CHECK_EQ(2003, obj->Get(env.local(), empty)
4144 : .ToLocalChecked()
4145 : ->Int32Value(env.local())
4146 : .FromJust());
4147 :
4148 6 : CcTest::CollectAllGarbage();
4149 :
4150 : // Add another property and delete it afterwards to force the object in
4151 : // slow case.
4152 18 : CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
4153 : .FromJust());
4154 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4155 : .ToLocalChecked()
4156 : ->Int32Value(env.local())
4157 : .FromJust());
4158 24 : CHECK_EQ(2008, obj->Get(env.local(), prop_name)
4159 : .ToLocalChecked()
4160 : ->Int32Value(env.local())
4161 : .FromJust());
4162 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4163 : .ToLocalChecked()
4164 : ->Int32Value(env.local())
4165 : .FromJust());
4166 12 : CHECK(obj->Delete(env.local(), prop_name).FromJust());
4167 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4168 : .ToLocalChecked()
4169 : ->Int32Value(env.local())
4170 : .FromJust());
4171 :
4172 6 : CcTest::CollectAllGarbage();
4173 :
4174 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4175 : .FromJust());
4176 12 : CHECK(obj->DeletePrivate(env.local(), key).FromJust());
4177 18 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4178 6 : }
4179 :
4180 :
4181 25881 : THREADED_TEST(Regress97784) {
4182 : // Regression test for crbug.com/97784
4183 : // Messing with the Object.prototype should not have effect on
4184 : // hidden properties.
4185 6 : LocalContext env;
4186 12 : v8::HandleScope scope(env->GetIsolate());
4187 :
4188 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4189 : v8::Local<v8::Private> key =
4190 12 : v8::Private::New(env->GetIsolate(), v8_str("hidden"));
4191 :
4192 : CompileRun(
4193 : "set_called = false;"
4194 : "Object.defineProperty("
4195 : " Object.prototype,"
4196 : " 'hidden',"
4197 : " {get: function() { return 45; },"
4198 : " set: function() { set_called = true; }})");
4199 :
4200 12 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4201 : // Make sure that the getter and setter from Object.prototype is not invoked.
4202 : // If it did we would have full access to the hidden properties in
4203 : // the accessor.
4204 18 : CHECK(
4205 : obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
4206 : .FromJust());
4207 : ExpectFalse("set_called");
4208 18 : CHECK_EQ(42, obj->GetPrivate(env.local(), key)
4209 : .ToLocalChecked()
4210 : ->Int32Value(env.local())
4211 6 : .FromJust());
4212 6 : }
4213 :
4214 :
4215 25881 : THREADED_TEST(External) {
4216 6 : v8::HandleScope scope(CcTest::isolate());
4217 6 : int x = 3;
4218 6 : Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
4219 12 : LocalContext env;
4220 30 : CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
4221 : Local<Value> reext_obj = CompileRun("this.ext");
4222 : v8::Local<v8::External> reext = reext_obj.As<v8::External>();
4223 6 : int* ptr = static_cast<int*>(reext->Value());
4224 6 : CHECK_EQ(3, x);
4225 6 : *ptr = 10;
4226 6 : CHECK_EQ(x, 10);
4227 :
4228 : {
4229 : i::Handle<i::Object> obj = v8::Utils::OpenHandle(*ext);
4230 18 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4231 6 : CHECK(ext->IsExternal());
4232 6 : CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty());
4233 18 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4234 6 : CHECK(ext->IsExternal());
4235 : }
4236 :
4237 : // Make sure unaligned pointers are wrapped properly.
4238 6 : char* data = i::StrDup("0123456789");
4239 6 : Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
4240 6 : Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
4241 6 : Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
4242 6 : Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
4243 :
4244 6 : char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
4245 6 : CHECK_EQ('0', *char_ptr);
4246 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
4247 6 : CHECK_EQ('1', *char_ptr);
4248 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
4249 6 : CHECK_EQ('2', *char_ptr);
4250 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
4251 6 : CHECK_EQ('3', *char_ptr);
4252 6 : i::DeleteArray(data);
4253 6 : }
4254 :
4255 :
4256 25881 : THREADED_TEST(GlobalHandle) {
4257 6 : v8::Isolate* isolate = CcTest::isolate();
4258 : v8::Persistent<String> global;
4259 : {
4260 6 : v8::HandleScope scope(isolate);
4261 12 : global.Reset(isolate, v8_str("str"));
4262 : }
4263 : {
4264 6 : v8::HandleScope scope(isolate);
4265 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4266 : }
4267 : global.Reset();
4268 : {
4269 6 : v8::HandleScope scope(isolate);
4270 12 : global.Reset(isolate, v8_str("str"));
4271 : }
4272 : {
4273 6 : v8::HandleScope scope(isolate);
4274 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4275 : }
4276 : global.Reset();
4277 6 : }
4278 :
4279 :
4280 25881 : THREADED_TEST(ResettingGlobalHandle) {
4281 12 : v8::Isolate* isolate = CcTest::isolate();
4282 : v8::Persistent<String> global;
4283 : {
4284 6 : v8::HandleScope scope(isolate);
4285 12 : global.Reset(isolate, v8_str("str"));
4286 : }
4287 18 : v8::internal::GlobalHandles* global_handles =
4288 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4289 : size_t initial_handle_count = global_handles->handles_count();
4290 : {
4291 6 : v8::HandleScope scope(isolate);
4292 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4293 : }
4294 : {
4295 6 : v8::HandleScope scope(isolate);
4296 12 : global.Reset(isolate, v8_str("longer"));
4297 : }
4298 6 : CHECK_EQ(global_handles->handles_count(), initial_handle_count);
4299 : {
4300 6 : v8::HandleScope scope(isolate);
4301 6 : CHECK_EQ(6, v8::Local<String>::New(isolate, global)->Length());
4302 : }
4303 : global.Reset();
4304 12 : CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4305 6 : }
4306 :
4307 :
4308 25881 : THREADED_TEST(ResettingGlobalHandleToEmpty) {
4309 12 : v8::Isolate* isolate = CcTest::isolate();
4310 : v8::Persistent<String> global;
4311 : {
4312 6 : v8::HandleScope scope(isolate);
4313 12 : global.Reset(isolate, v8_str("str"));
4314 : }
4315 12 : v8::internal::GlobalHandles* global_handles =
4316 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4317 : size_t initial_handle_count = global_handles->handles_count();
4318 : {
4319 6 : v8::HandleScope scope(isolate);
4320 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4321 : }
4322 : {
4323 6 : v8::HandleScope scope(isolate);
4324 : Local<String> empty;
4325 6 : global.Reset(isolate, empty);
4326 : }
4327 6 : CHECK(global.IsEmpty());
4328 12 : CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4329 6 : }
4330 :
4331 :
4332 : template <class T>
4333 : static v8::Global<T> PassUnique(v8::Global<T> unique) {
4334 : return unique.Pass();
4335 : }
4336 :
4337 :
4338 : template <class T>
4339 6 : static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
4340 : const v8::Persistent<T>& global) {
4341 : v8::Global<String> unique(isolate, global);
4342 6 : return unique.Pass();
4343 : }
4344 :
4345 :
4346 25881 : THREADED_TEST(Global) {
4347 12 : v8::Isolate* isolate = CcTest::isolate();
4348 : v8::Persistent<String> global;
4349 : {
4350 6 : v8::HandleScope scope(isolate);
4351 12 : global.Reset(isolate, v8_str("str"));
4352 : }
4353 48 : v8::internal::GlobalHandles* global_handles =
4354 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4355 : size_t initial_handle_count = global_handles->handles_count();
4356 : {
4357 : v8::Global<String> unique(isolate, global);
4358 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4359 : // Test assignment via Pass
4360 : {
4361 : v8::Global<String> copy = unique.Pass();
4362 6 : CHECK(unique.IsEmpty());
4363 6 : CHECK(copy == global);
4364 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4365 6 : unique = copy.Pass();
4366 : }
4367 : // Test ctor via Pass
4368 : {
4369 : v8::Global<String> copy(unique.Pass());
4370 6 : CHECK(unique.IsEmpty());
4371 6 : CHECK(copy == global);
4372 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4373 6 : unique = copy.Pass();
4374 : }
4375 : // Test pass through function call
4376 : {
4377 6 : v8::Global<String> copy = PassUnique(unique.Pass());
4378 6 : CHECK(unique.IsEmpty());
4379 6 : CHECK(copy == global);
4380 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4381 6 : unique = copy.Pass();
4382 : }
4383 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4384 : }
4385 : // Test pass from function call
4386 : {
4387 6 : v8::Global<String> unique = ReturnUnique(isolate, global);
4388 6 : CHECK(unique == global);
4389 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4390 : }
4391 6 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4392 : global.Reset();
4393 6 : }
4394 :
4395 :
4396 : namespace {
4397 :
4398 : class TwoPassCallbackData;
4399 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4400 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4401 :
4402 :
4403 : class TwoPassCallbackData {
4404 : public:
4405 215 : TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4406 : : first_pass_called_(false),
4407 : second_pass_called_(false),
4408 : trigger_gc_(false),
4409 430 : instance_counter_(instance_counter) {
4410 215 : HandleScope scope(isolate);
4411 : i::ScopedVector<char> buffer(40);
4412 215 : i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4413 : auto string =
4414 : v8::String::NewFromUtf8(isolate, buffer.start(),
4415 215 : v8::NewStringType::kNormal).ToLocalChecked();
4416 : cell_.Reset(isolate, string);
4417 430 : (*instance_counter_)++;
4418 215 : }
4419 :
4420 215 : ~TwoPassCallbackData() {
4421 215 : CHECK(first_pass_called_);
4422 215 : CHECK(second_pass_called_);
4423 215 : CHECK(cell_.IsEmpty());
4424 215 : (*instance_counter_)--;
4425 215 : }
4426 :
4427 215 : void FirstPass() {
4428 215 : CHECK(!first_pass_called_);
4429 215 : CHECK(!second_pass_called_);
4430 215 : CHECK(!cell_.IsEmpty());
4431 : cell_.Reset();
4432 215 : first_pass_called_ = true;
4433 215 : }
4434 :
4435 215 : void SecondPass() {
4436 215 : CHECK(first_pass_called_);
4437 215 : CHECK(!second_pass_called_);
4438 215 : CHECK(cell_.IsEmpty());
4439 215 : second_pass_called_ = true;
4440 215 : delete this;
4441 215 : }
4442 :
4443 : void SetWeak() {
4444 : cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4445 : }
4446 :
4447 15 : void MarkTriggerGc() { trigger_gc_ = true; }
4448 : bool trigger_gc() { return trigger_gc_; }
4449 :
4450 : int* instance_counter() { return instance_counter_; }
4451 :
4452 : private:
4453 : bool first_pass_called_;
4454 : bool second_pass_called_;
4455 : bool trigger_gc_;
4456 : v8::Global<v8::String> cell_;
4457 : int* instance_counter_;
4458 : };
4459 :
4460 :
4461 445 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4462 215 : ApiTestFuzzer::Fuzz();
4463 215 : bool trigger_gc = data.GetParameter()->trigger_gc();
4464 215 : int* instance_counter = data.GetParameter()->instance_counter();
4465 215 : data.GetParameter()->SecondPass();
4466 430 : if (!trigger_gc) return;
4467 15 : auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4468 : data_2->SetWeak();
4469 15 : CcTest::CollectAllGarbage();
4470 : }
4471 :
4472 :
4473 430 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4474 215 : data.GetParameter()->FirstPass();
4475 : data.SetSecondPassCallback(SecondPassCallback);
4476 215 : }
4477 :
4478 : } // namespace
4479 :
4480 :
4481 25880 : TEST(TwoPassPhantomCallbacks) {
4482 5 : auto isolate = CcTest::isolate();
4483 : const size_t kLength = 20;
4484 5 : int instance_counter = 0;
4485 105 : for (size_t i = 0; i < kLength; ++i) {
4486 100 : auto data = new TwoPassCallbackData(isolate, &instance_counter);
4487 : data->SetWeak();
4488 : }
4489 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4490 5 : CcTest::CollectAllGarbage();
4491 5 : EmptyMessageQueues(isolate);
4492 5 : CHECK_EQ(0, instance_counter);
4493 5 : }
4494 :
4495 :
4496 25880 : TEST(TwoPassPhantomCallbacksNestedGc) {
4497 5 : auto isolate = CcTest::isolate();
4498 : const size_t kLength = 20;
4499 : TwoPassCallbackData* array[kLength];
4500 5 : int instance_counter = 0;
4501 105 : for (size_t i = 0; i < kLength; ++i) {
4502 100 : array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4503 : array[i]->SetWeak();
4504 : }
4505 5 : array[5]->MarkTriggerGc();
4506 5 : array[10]->MarkTriggerGc();
4507 5 : array[15]->MarkTriggerGc();
4508 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4509 5 : CcTest::CollectAllGarbage();
4510 5 : EmptyMessageQueues(isolate);
4511 5 : CHECK_EQ(0, instance_counter);
4512 5 : }
4513 :
4514 :
4515 : namespace {
4516 :
4517 30 : void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4518 :
4519 :
4520 20 : Local<v8::Object> NewObjectForIntKey(
4521 : v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4522 : int key) {
4523 : auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4524 20 : auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4525 20 : obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4526 20 : return obj;
4527 : }
4528 :
4529 :
4530 : template <typename K, typename V>
4531 : class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4532 : public:
4533 : typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4534 : static const v8::PersistentContainerCallbackType kCallbackType =
4535 : v8::kWeakWithInternalFields;
4536 : struct WeakCallbackDataType {
4537 : MapType* map;
4538 : K key;
4539 : };
4540 : static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4541 : Local<V> value) {
4542 25 : WeakCallbackDataType* data = new WeakCallbackDataType;
4543 25 : data->map = map;
4544 25 : data->key = key;
4545 : return data;
4546 : }
4547 : static MapType* MapFromWeakCallbackInfo(
4548 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4549 5 : return data.GetParameter()->map;
4550 : }
4551 : static K KeyFromWeakCallbackInfo(
4552 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4553 10 : return data.GetParameter()->key;
4554 : }
4555 25 : static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
4556 5 : static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4557 5 : CHECK_EQ(IntKeyToVoidPointer(key),
4558 : v8::Object::GetAlignedPointerFromInternalField(value, 0));
4559 5 : }
4560 : static void OnWeakCallback(
4561 : const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
4562 5 : static void DisposeWeak(
4563 : const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4564 : K key = KeyFromWeakCallbackInfo(info);
4565 5 : CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4566 : DisposeCallbackData(info.GetParameter());
4567 5 : }
4568 : };
4569 :
4570 :
4571 : template <typename Map>
4572 10 : void TestGlobalValueMap() {
4573 10 : LocalContext env;
4574 20 : v8::Isolate* isolate = env->GetIsolate();
4575 : v8::Global<ObjectTemplate> templ;
4576 : {
4577 10 : HandleScope scope(isolate);
4578 10 : auto t = ObjectTemplate::New(isolate);
4579 10 : t->SetInternalFieldCount(1);
4580 10 : templ.Reset(isolate, t);
4581 : }
4582 : Map map(isolate);
4583 40 : v8::internal::GlobalHandles* global_handles =
4584 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4585 : size_t initial_handle_count = global_handles->handles_count();
4586 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4587 : {
4588 10 : HandleScope scope(isolate);
4589 10 : Local<v8::Object> obj = map.Get(7);
4590 10 : CHECK(obj.IsEmpty());
4591 10 : Local<v8::Object> expected = v8::Object::New(isolate);
4592 20 : map.Set(7, expected);
4593 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4594 10 : obj = map.Get(7);
4595 20 : CHECK(expected->Equals(env.local(), obj).FromJust());
4596 : {
4597 10 : typename Map::PersistentValueReference ref = map.GetReference(7);
4598 20 : CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4599 : }
4600 10 : v8::Global<v8::Object> removed = map.Remove(7);
4601 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4602 10 : CHECK(expected == removed);
4603 20 : removed = map.Remove(7);
4604 10 : CHECK(removed.IsEmpty());
4605 20 : map.Set(8, expected);
4606 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4607 20 : map.Set(8, expected);
4608 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4609 : {
4610 : typename Map::PersistentValueReference ref;
4611 10 : Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4612 30 : removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4613 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4614 10 : CHECK(expected == removed);
4615 20 : CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4616 10 : }
4617 : }
4618 10 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4619 : if (map.IsWeak()) {
4620 5 : CcTest::PreciseCollectAllGarbage();
4621 : } else {
4622 5 : map.Clear();
4623 : }
4624 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4625 10 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4626 : {
4627 10 : HandleScope scope(isolate);
4628 10 : Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4629 20 : map.Set(9, value);
4630 10 : map.Clear();
4631 : }
4632 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4633 20 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4634 10 : }
4635 :
4636 : } // namespace
4637 :
4638 :
4639 25880 : TEST(GlobalValueMap) {
4640 : // Default case, w/o weak callbacks:
4641 5 : TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4642 :
4643 : // Custom traits with weak callbacks:
4644 : typedef v8::GlobalValueMap<int, v8::Object,
4645 : PhantomStdMapTraits<int, v8::Object>> WeakMap;
4646 5 : TestGlobalValueMap<WeakMap>();
4647 5 : }
4648 :
4649 :
4650 25880 : TEST(PersistentValueVector) {
4651 5 : LocalContext env;
4652 5 : v8::Isolate* isolate = env->GetIsolate();
4653 15 : v8::internal::GlobalHandles* global_handles =
4654 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4655 : size_t handle_count = global_handles->handles_count();
4656 10 : HandleScope scope(isolate);
4657 :
4658 5 : v8::PersistentValueVector<v8::Object> vector(isolate);
4659 :
4660 5 : Local<v8::Object> obj1 = v8::Object::New(isolate);
4661 5 : Local<v8::Object> obj2 = v8::Object::New(isolate);
4662 5 : v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4663 :
4664 5 : CHECK(vector.IsEmpty());
4665 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4666 :
4667 : vector.ReserveCapacity(3);
4668 5 : CHECK(vector.IsEmpty());
4669 :
4670 5 : vector.Append(obj1);
4671 5 : vector.Append(obj2);
4672 5 : vector.Append(obj1);
4673 5 : vector.Append(obj3.Pass());
4674 5 : vector.Append(obj1);
4675 :
4676 5 : CHECK(!vector.IsEmpty());
4677 5 : CHECK_EQ(5, static_cast<int>(vector.Size()));
4678 5 : CHECK(obj3.IsEmpty());
4679 15 : CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4680 15 : CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4681 15 : CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4682 20 : CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4683 :
4684 5 : CHECK_EQ(5 + handle_count, global_handles->handles_count());
4685 :
4686 5 : vector.Clear();
4687 5 : CHECK(vector.IsEmpty());
4688 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4689 10 : CHECK_EQ(handle_count, global_handles->handles_count());
4690 5 : }
4691 :
4692 :
4693 25881 : THREADED_TEST(GlobalHandleUpcast) {
4694 6 : v8::Isolate* isolate = CcTest::isolate();
4695 6 : v8::HandleScope scope(isolate);
4696 6 : v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4697 : v8::Persistent<String> global_string(isolate, local);
4698 : v8::Persistent<Value>& global_value =
4699 : v8::Persistent<Value>::Cast(global_string);
4700 6 : CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4701 6 : CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4702 6 : global_string.Reset();
4703 6 : }
4704 :
4705 :
4706 25881 : THREADED_TEST(HandleEquality) {
4707 6 : v8::Isolate* isolate = CcTest::isolate();
4708 : v8::Persistent<String> global1;
4709 : v8::Persistent<String> global2;
4710 : {
4711 6 : v8::HandleScope scope(isolate);
4712 12 : global1.Reset(isolate, v8_str("str"));
4713 12 : global2.Reset(isolate, v8_str("str2"));
4714 : }
4715 6 : CHECK(global1 == global1);
4716 6 : CHECK(!(global1 != global1));
4717 : {
4718 6 : v8::HandleScope scope(isolate);
4719 : Local<String> local1 = Local<String>::New(isolate, global1);
4720 : Local<String> local2 = Local<String>::New(isolate, global2);
4721 :
4722 6 : CHECK(global1 == local1);
4723 6 : CHECK(!(global1 != local1));
4724 6 : CHECK(local1 == global1);
4725 6 : CHECK(!(local1 != global1));
4726 :
4727 6 : CHECK(!(global1 == local2));
4728 6 : CHECK(global1 != local2);
4729 6 : CHECK(!(local2 == global1));
4730 6 : CHECK(local2 != global1);
4731 :
4732 6 : CHECK(!(local1 == local2));
4733 6 : CHECK(local1 != local2);
4734 :
4735 : Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4736 6 : CHECK(local1 == anotherLocal1);
4737 6 : CHECK(!(local1 != anotherLocal1));
4738 : }
4739 : global1.Reset();
4740 : global2.Reset();
4741 6 : }
4742 :
4743 :
4744 25881 : THREADED_TEST(LocalHandle) {
4745 6 : v8::HandleScope scope(CcTest::isolate());
4746 : v8::Local<String> local =
4747 6 : v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4748 6 : CHECK_EQ(3, local->Length());
4749 6 : }
4750 :
4751 :
4752 : class WeakCallCounter {
4753 : public:
4754 5 : explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
4755 : int id() { return id_; }
4756 10 : void increment() { number_of_weak_calls_++; }
4757 : int NumberOfWeakCalls() { return number_of_weak_calls_; }
4758 :
4759 : private:
4760 : int id_;
4761 : int number_of_weak_calls_;
4762 : };
4763 :
4764 :
4765 : template <typename T>
4766 : struct WeakCallCounterAndPersistent {
4767 : explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4768 10 : : counter(counter) {}
4769 : WeakCallCounter* counter;
4770 : v8::Persistent<T> handle;
4771 : };
4772 :
4773 :
4774 : template <typename T>
4775 10 : static void WeakPointerCallback(
4776 20 : const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4777 10 : CHECK_EQ(1234, data.GetParameter()->counter->id());
4778 : data.GetParameter()->counter->increment();
4779 : data.GetParameter()->handle.Reset();
4780 10 : }
4781 :
4782 25881 : THREADED_TEST(ScriptException) {
4783 6 : LocalContext env;
4784 12 : v8::HandleScope scope(env->GetIsolate());
4785 : Local<Script> script = v8_compile("throw 'panama!';");
4786 12 : v8::TryCatch try_catch(env->GetIsolate());
4787 6 : v8::MaybeLocal<Value> result = script->Run(env.local());
4788 6 : CHECK(result.IsEmpty());
4789 6 : CHECK(try_catch.HasCaught());
4790 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
4791 12 : CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4792 6 : }
4793 :
4794 :
4795 25880 : TEST(TryCatchCustomException) {
4796 5 : LocalContext env;
4797 5 : v8::Isolate* isolate = env->GetIsolate();
4798 10 : v8::HandleScope scope(isolate);
4799 10 : v8::TryCatch try_catch(isolate);
4800 : CompileRun(
4801 : "function CustomError() { this.a = 'b'; }"
4802 : "(function f() { throw new CustomError(); })();");
4803 5 : CHECK(try_catch.HasCaught());
4804 35 : CHECK(try_catch.Exception()
4805 : ->ToObject(env.local())
4806 : .ToLocalChecked()
4807 : ->Get(env.local(), v8_str("a"))
4808 : .ToLocalChecked()
4809 : ->Equals(env.local(), v8_str("b"))
4810 5 : .FromJust());
4811 5 : }
4812 :
4813 :
4814 : bool message_received;
4815 :
4816 :
4817 6 : static void check_message_0(v8::Local<v8::Message> message,
4818 : v8::Local<Value> data) {
4819 18 : CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4820 : .FromJust());
4821 12 : CHECK_EQ(6.75, message->GetScriptOrigin()
4822 : .ResourceName()
4823 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4824 : .FromJust());
4825 6 : CHECK(!message->IsSharedCrossOrigin());
4826 6 : message_received = true;
4827 6 : }
4828 :
4829 :
4830 25881 : THREADED_TEST(MessageHandler0) {
4831 6 : message_received = false;
4832 6 : v8::HandleScope scope(CcTest::isolate());
4833 6 : CHECK(!message_received);
4834 12 : LocalContext context;
4835 6 : CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4836 6 : v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4837 18 : CHECK(script->Run(context.local()).IsEmpty());
4838 6 : CHECK(message_received);
4839 : // clear out the message listener
4840 12 : CcTest::isolate()->RemoveMessageListeners(check_message_0);
4841 6 : }
4842 :
4843 :
4844 5 : static void check_message_1(v8::Local<v8::Message> message,
4845 : v8::Local<Value> data) {
4846 5 : CHECK(data->IsNumber());
4847 10 : CHECK_EQ(1337,
4848 : data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4849 5 : CHECK(!message->IsSharedCrossOrigin());
4850 5 : message_received = true;
4851 5 : }
4852 :
4853 :
4854 25880 : TEST(MessageHandler1) {
4855 5 : message_received = false;
4856 5 : v8::HandleScope scope(CcTest::isolate());
4857 5 : CHECK(!message_received);
4858 5 : CcTest::isolate()->AddMessageListener(check_message_1);
4859 10 : LocalContext context;
4860 : CompileRun("throw 1337;");
4861 5 : CHECK(message_received);
4862 : // clear out the message listener
4863 10 : CcTest::isolate()->RemoveMessageListeners(check_message_1);
4864 5 : }
4865 :
4866 :
4867 5 : static void check_message_2(v8::Local<v8::Message> message,
4868 : v8::Local<Value> data) {
4869 5 : LocalContext context;
4870 5 : CHECK(data->IsObject());
4871 : v8::Local<v8::Value> hidden_property =
4872 : v8::Object::Cast(*data)
4873 : ->GetPrivate(
4874 : context.local(),
4875 5 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4876 10 : .ToLocalChecked();
4877 15 : CHECK(v8_str("hidden value")
4878 : ->Equals(context.local(), hidden_property)
4879 : .FromJust());
4880 5 : CHECK(!message->IsSharedCrossOrigin());
4881 5 : message_received = true;
4882 5 : }
4883 :
4884 :
4885 25880 : TEST(MessageHandler2) {
4886 5 : message_received = false;
4887 5 : v8::HandleScope scope(CcTest::isolate());
4888 5 : CHECK(!message_received);
4889 5 : CcTest::isolate()->AddMessageListener(check_message_2);
4890 10 : LocalContext context;
4891 5 : v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4892 : v8::Object::Cast(*error)
4893 : ->SetPrivate(context.local(),
4894 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4895 15 : v8_str("hidden value"))
4896 10 : .FromJust();
4897 25 : CHECK(context->Global()
4898 : ->Set(context.local(), v8_str("error"), error)
4899 : .FromJust());
4900 : CompileRun("throw error;");
4901 5 : CHECK(message_received);
4902 : // clear out the message listener
4903 10 : CcTest::isolate()->RemoveMessageListeners(check_message_2);
4904 5 : }
4905 :
4906 :
4907 5 : static void check_message_3(v8::Local<v8::Message> message,
4908 : v8::Local<Value> data) {
4909 5 : CHECK(message->IsSharedCrossOrigin());
4910 10 : CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4911 10 : CHECK(message->GetScriptOrigin().Options().IsOpaque());
4912 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4913 : .ResourceName()
4914 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4915 : .FromJust());
4916 10 : CHECK_EQ(7.40, message->GetScriptOrigin()
4917 : .SourceMapUrl()
4918 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4919 : .FromJust());
4920 5 : message_received = true;
4921 5 : }
4922 :
4923 :
4924 25880 : TEST(MessageHandler3) {
4925 5 : message_received = false;
4926 5 : v8::Isolate* isolate = CcTest::isolate();
4927 5 : v8::HandleScope scope(isolate);
4928 5 : CHECK(!message_received);
4929 5 : isolate->AddMessageListener(check_message_3);
4930 10 : LocalContext context;
4931 : v8::ScriptOrigin origin =
4932 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4933 : v8::Integer::New(isolate, 2), v8::True(isolate),
4934 5 : Local<v8::Integer>(), v8_str("7.40"), v8::True(isolate));
4935 : v8::Local<v8::Script> script =
4936 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4937 5 : .ToLocalChecked();
4938 10 : CHECK(script->Run(context.local()).IsEmpty());
4939 5 : CHECK(message_received);
4940 : // clear out the message listener
4941 10 : isolate->RemoveMessageListeners(check_message_3);
4942 5 : }
4943 :
4944 :
4945 5 : static void check_message_4(v8::Local<v8::Message> message,
4946 : v8::Local<Value> data) {
4947 5 : CHECK(!message->IsSharedCrossOrigin());
4948 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4949 : .ResourceName()
4950 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4951 : .FromJust());
4952 5 : message_received = true;
4953 5 : }
4954 :
4955 :
4956 25880 : TEST(MessageHandler4) {
4957 5 : message_received = false;
4958 5 : v8::Isolate* isolate = CcTest::isolate();
4959 5 : v8::HandleScope scope(isolate);
4960 5 : CHECK(!message_received);
4961 5 : isolate->AddMessageListener(check_message_4);
4962 10 : LocalContext context;
4963 : v8::ScriptOrigin origin =
4964 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4965 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
4966 : v8::Local<v8::Script> script =
4967 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4968 5 : .ToLocalChecked();
4969 10 : CHECK(script->Run(context.local()).IsEmpty());
4970 5 : CHECK(message_received);
4971 : // clear out the message listener
4972 10 : isolate->RemoveMessageListeners(check_message_4);
4973 5 : }
4974 :
4975 :
4976 5 : static void check_message_5a(v8::Local<v8::Message> message,
4977 : v8::Local<Value> data) {
4978 5 : CHECK(message->IsSharedCrossOrigin());
4979 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4980 : .ResourceName()
4981 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4982 : .FromJust());
4983 5 : message_received = true;
4984 5 : }
4985 :
4986 :
4987 5 : static void check_message_5b(v8::Local<v8::Message> message,
4988 : v8::Local<Value> data) {
4989 5 : CHECK(!message->IsSharedCrossOrigin());
4990 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4991 : .ResourceName()
4992 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4993 : .FromJust());
4994 5 : message_received = true;
4995 5 : }
4996 :
4997 :
4998 25880 : TEST(MessageHandler5) {
4999 5 : message_received = false;
5000 5 : v8::Isolate* isolate = CcTest::isolate();
5001 5 : v8::HandleScope scope(isolate);
5002 5 : CHECK(!message_received);
5003 5 : isolate->AddMessageListener(check_message_5a);
5004 10 : LocalContext context;
5005 : v8::ScriptOrigin origin1 =
5006 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5007 5 : v8::Integer::New(isolate, 2), v8::True(isolate));
5008 : v8::Local<v8::Script> script =
5009 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
5010 5 : .ToLocalChecked();
5011 10 : CHECK(script->Run(context.local()).IsEmpty());
5012 5 : CHECK(message_received);
5013 : // clear out the message listener
5014 5 : isolate->RemoveMessageListeners(check_message_5a);
5015 :
5016 5 : message_received = false;
5017 5 : isolate->AddMessageListener(check_message_5b);
5018 : v8::ScriptOrigin origin2 =
5019 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5020 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
5021 5 : script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
5022 5 : .ToLocalChecked();
5023 10 : CHECK(script->Run(context.local()).IsEmpty());
5024 5 : CHECK(message_received);
5025 : // clear out the message listener
5026 10 : isolate->RemoveMessageListeners(check_message_5b);
5027 5 : }
5028 :
5029 :
5030 25881 : THREADED_TEST(GetSetProperty) {
5031 6 : LocalContext context;
5032 6 : v8::Isolate* isolate = context->GetIsolate();
5033 12 : v8::HandleScope scope(isolate);
5034 30 : CHECK(context->Global()
5035 : ->Set(context.local(), v8_str("foo"), v8_num(14))
5036 : .FromJust());
5037 30 : CHECK(context->Global()
5038 : ->Set(context.local(), v8_str("12"), v8_num(92))
5039 : .FromJust());
5040 30 : CHECK(context->Global()
5041 : ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
5042 : .FromJust());
5043 24 : CHECK(context->Global()
5044 : ->Set(context.local(), v8_num(13), v8_num(56))
5045 : .FromJust());
5046 : Local<Value> foo = CompileRun("this.foo");
5047 12 : CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
5048 : Local<Value> twelve = CompileRun("this[12]");
5049 12 : CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
5050 : Local<Value> sixteen = CompileRun("this[16]");
5051 12 : CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
5052 : Local<Value> thirteen = CompileRun("this[13]");
5053 12 : CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
5054 36 : CHECK_EQ(92, context->Global()
5055 : ->Get(context.local(), v8::Integer::New(isolate, 12))
5056 : .ToLocalChecked()
5057 : ->Int32Value(context.local())
5058 : .FromJust());
5059 36 : CHECK_EQ(92, context->Global()
5060 : ->Get(context.local(), v8_str("12"))
5061 : .ToLocalChecked()
5062 : ->Int32Value(context.local())
5063 : .FromJust());
5064 30 : CHECK_EQ(92, context->Global()
5065 : ->Get(context.local(), v8_num(12))
5066 : .ToLocalChecked()
5067 : ->Int32Value(context.local())
5068 : .FromJust());
5069 36 : CHECK_EQ(32, context->Global()
5070 : ->Get(context.local(), v8::Integer::New(isolate, 16))
5071 : .ToLocalChecked()
5072 : ->Int32Value(context.local())
5073 : .FromJust());
5074 36 : CHECK_EQ(32, context->Global()
5075 : ->Get(context.local(), v8_str("16"))
5076 : .ToLocalChecked()
5077 : ->Int32Value(context.local())
5078 : .FromJust());
5079 30 : CHECK_EQ(32, context->Global()
5080 : ->Get(context.local(), v8_num(16))
5081 : .ToLocalChecked()
5082 : ->Int32Value(context.local())
5083 : .FromJust());
5084 36 : CHECK_EQ(56, context->Global()
5085 : ->Get(context.local(), v8::Integer::New(isolate, 13))
5086 : .ToLocalChecked()
5087 : ->Int32Value(context.local())
5088 : .FromJust());
5089 36 : CHECK_EQ(56, context->Global()
5090 : ->Get(context.local(), v8_str("13"))
5091 : .ToLocalChecked()
5092 : ->Int32Value(context.local())
5093 : .FromJust());
5094 30 : CHECK_EQ(56, context->Global()
5095 : ->Get(context.local(), v8_num(13))
5096 : .ToLocalChecked()
5097 : ->Int32Value(context.local())
5098 6 : .FromJust());
5099 6 : }
5100 :
5101 :
5102 25881 : THREADED_TEST(PropertyAttributes) {
5103 6 : LocalContext context;
5104 12 : v8::HandleScope scope(context->GetIsolate());
5105 : // none
5106 6 : Local<String> prop = v8_str("none");
5107 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5108 24 : CHECK_EQ(v8::None, context->Global()
5109 : ->GetPropertyAttributes(context.local(), prop)
5110 : .FromJust());
5111 : // read-only
5112 6 : prop = v8_str("read_only");
5113 : context->Global()
5114 24 : ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5115 12 : .FromJust();
5116 36 : CHECK_EQ(7, context->Global()
5117 : ->Get(context.local(), prop)
5118 : .ToLocalChecked()
5119 : ->Int32Value(context.local())
5120 : .FromJust());
5121 24 : CHECK_EQ(v8::ReadOnly, context->Global()
5122 : ->GetPropertyAttributes(context.local(), prop)
5123 : .FromJust());
5124 : CompileRun("read_only = 9");
5125 36 : CHECK_EQ(7, context->Global()
5126 : ->Get(context.local(), prop)
5127 : .ToLocalChecked()
5128 : ->Int32Value(context.local())
5129 : .FromJust());
5130 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5131 36 : CHECK_EQ(7, context->Global()
5132 : ->Get(context.local(), prop)
5133 : .ToLocalChecked()
5134 : ->Int32Value(context.local())
5135 : .FromJust());
5136 : // dont-delete
5137 6 : prop = v8_str("dont_delete");
5138 : context->Global()
5139 24 : ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5140 12 : .FromJust();
5141 36 : CHECK_EQ(13, context->Global()
5142 : ->Get(context.local(), prop)
5143 : .ToLocalChecked()
5144 : ->Int32Value(context.local())
5145 : .FromJust());
5146 : CompileRun("delete dont_delete");
5147 36 : CHECK_EQ(13, context->Global()
5148 : ->Get(context.local(), prop)
5149 : .ToLocalChecked()
5150 : ->Int32Value(context.local())
5151 : .FromJust());
5152 24 : CHECK_EQ(v8::DontDelete, context->Global()
5153 : ->GetPropertyAttributes(context.local(), prop)
5154 : .FromJust());
5155 : // dont-enum
5156 6 : prop = v8_str("dont_enum");
5157 : context->Global()
5158 24 : ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5159 12 : .FromJust();
5160 24 : CHECK_EQ(v8::DontEnum, context->Global()
5161 : ->GetPropertyAttributes(context.local(), prop)
5162 : .FromJust());
5163 : // absent
5164 6 : prop = v8_str("absent");
5165 24 : CHECK_EQ(v8::None, context->Global()
5166 : ->GetPropertyAttributes(context.local(), prop)
5167 : .FromJust());
5168 6 : Local<Value> fake_prop = v8_num(1);
5169 24 : CHECK_EQ(v8::None, context->Global()
5170 : ->GetPropertyAttributes(context.local(), fake_prop)
5171 : .FromJust());
5172 : // exception
5173 12 : TryCatch try_catch(context->GetIsolate());
5174 : Local<Value> exception =
5175 6 : CompileRun("({ toString: function() { throw 'exception';} })");
5176 24 : CHECK(context->Global()
5177 : ->GetPropertyAttributes(context.local(), exception)
5178 : .IsNothing());
5179 6 : CHECK(try_catch.HasCaught());
5180 : String::Utf8Value exception_value(context->GetIsolate(),
5181 18 : try_catch.Exception());
5182 6 : CHECK_EQ(0, strcmp("exception", *exception_value));
5183 12 : try_catch.Reset();
5184 6 : }
5185 :
5186 :
5187 25881 : THREADED_TEST(Array) {
5188 6 : LocalContext context;
5189 12 : v8::HandleScope scope(context->GetIsolate());
5190 6 : Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5191 6 : CHECK_EQ(0u, array->Length());
5192 12 : CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5193 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5194 12 : CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5195 12 : CHECK(!array->Has(context.local(), 100).FromJust());
5196 12 : CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5197 6 : CHECK_EQ(3u, array->Length());
5198 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5199 12 : CHECK(!array->Has(context.local(), 1).FromJust());
5200 12 : CHECK(array->Has(context.local(), 2).FromJust());
5201 18 : CHECK_EQ(7, array->Get(context.local(), 2)
5202 : .ToLocalChecked()
5203 : ->Int32Value(context.local())
5204 : .FromJust());
5205 : Local<Value> obj = CompileRun("[1, 2, 3]");
5206 : Local<v8::Array> arr = obj.As<v8::Array>();
5207 6 : CHECK_EQ(3u, arr->Length());
5208 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5209 : .ToLocalChecked()
5210 : ->Int32Value(context.local())
5211 : .FromJust());
5212 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5213 : .ToLocalChecked()
5214 : ->Int32Value(context.local())
5215 : .FromJust());
5216 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5217 : .ToLocalChecked()
5218 : ->Int32Value(context.local())
5219 : .FromJust());
5220 6 : array = v8::Array::New(context->GetIsolate(), 27);
5221 6 : CHECK_EQ(27u, array->Length());
5222 6 : array = v8::Array::New(context->GetIsolate(), -27);
5223 6 : CHECK_EQ(0u, array->Length());
5224 :
5225 12 : std::vector<Local<Value>> vector = {v8_num(1), v8_num(2), v8_num(3)};
5226 12 : array = v8::Array::New(context->GetIsolate(), vector.data(), vector.size());
5227 12 : CHECK_EQ(vector.size(), array->Length());
5228 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5229 : .ToLocalChecked()
5230 : ->Int32Value(context.local())
5231 : .FromJust());
5232 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5233 : .ToLocalChecked()
5234 : ->Int32Value(context.local())
5235 : .FromJust());
5236 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5237 : .ToLocalChecked()
5238 : ->Int32Value(context.local())
5239 6 : .FromJust());
5240 6 : }
5241 :
5242 :
5243 180 : void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5244 30 : v8::EscapableHandleScope scope(args.GetIsolate());
5245 30 : ApiTestFuzzer::Fuzz();
5246 30 : Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5247 180 : for (int i = 0; i < args.Length(); i++) {
5248 180 : CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5249 : .FromJust());
5250 : }
5251 : args.GetReturnValue().Set(scope.Escape(result));
5252 30 : }
5253 :
5254 :
5255 25881 : THREADED_TEST(Vector) {
5256 6 : v8::Isolate* isolate = CcTest::isolate();
5257 6 : v8::HandleScope scope(isolate);
5258 6 : Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5259 18 : global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5260 12 : LocalContext context(nullptr, global);
5261 :
5262 : const char* fun = "f()";
5263 : Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5264 6 : CHECK_EQ(0u, a0->Length());
5265 :
5266 : const char* fun2 = "f(11)";
5267 : Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5268 6 : CHECK_EQ(1u, a1->Length());
5269 18 : CHECK_EQ(11, a1->Get(context.local(), 0)
5270 : .ToLocalChecked()
5271 : ->Int32Value(context.local())
5272 : .FromJust());
5273 :
5274 : const char* fun3 = "f(12, 13)";
5275 : Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5276 6 : CHECK_EQ(2u, a2->Length());
5277 18 : CHECK_EQ(12, a2->Get(context.local(), 0)
5278 : .ToLocalChecked()
5279 : ->Int32Value(context.local())
5280 : .FromJust());
5281 18 : CHECK_EQ(13, a2->Get(context.local(), 1)
5282 : .ToLocalChecked()
5283 : ->Int32Value(context.local())
5284 : .FromJust());
5285 :
5286 : const char* fun4 = "f(14, 15, 16)";
5287 : Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5288 6 : CHECK_EQ(3u, a3->Length());
5289 18 : CHECK_EQ(14, a3->Get(context.local(), 0)
5290 : .ToLocalChecked()
5291 : ->Int32Value(context.local())
5292 : .FromJust());
5293 18 : CHECK_EQ(15, a3->Get(context.local(), 1)
5294 : .ToLocalChecked()
5295 : ->Int32Value(context.local())
5296 : .FromJust());
5297 18 : CHECK_EQ(16, a3->Get(context.local(), 2)
5298 : .ToLocalChecked()
5299 : ->Int32Value(context.local())
5300 : .FromJust());
5301 :
5302 : const char* fun5 = "f(17, 18, 19, 20)";
5303 : Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5304 6 : CHECK_EQ(4u, a4->Length());
5305 18 : CHECK_EQ(17, a4->Get(context.local(), 0)
5306 : .ToLocalChecked()
5307 : ->Int32Value(context.local())
5308 : .FromJust());
5309 18 : CHECK_EQ(18, a4->Get(context.local(), 1)
5310 : .ToLocalChecked()
5311 : ->Int32Value(context.local())
5312 : .FromJust());
5313 18 : CHECK_EQ(19, a4->Get(context.local(), 2)
5314 : .ToLocalChecked()
5315 : ->Int32Value(context.local())
5316 : .FromJust());
5317 18 : CHECK_EQ(20, a4->Get(context.local(), 3)
5318 : .ToLocalChecked()
5319 : ->Int32Value(context.local())
5320 6 : .FromJust());
5321 6 : }
5322 :
5323 :
5324 25881 : THREADED_TEST(FunctionCall) {
5325 6 : LocalContext context;
5326 6 : v8::Isolate* isolate = context->GetIsolate();
5327 12 : v8::HandleScope scope(isolate);
5328 : CompileRun(
5329 : "function Foo() {"
5330 : " var result = [];"
5331 : " for (var i = 0; i < arguments.length; i++) {"
5332 : " result.push(arguments[i]);"
5333 : " }"
5334 : " return result;"
5335 : "}"
5336 : "function ReturnThisSloppy() {"
5337 : " return this;"
5338 : "}"
5339 : "function ReturnThisStrict() {"
5340 : " 'use strict';"
5341 : " return this;"
5342 : "}");
5343 : Local<Function> Foo = Local<Function>::Cast(
5344 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5345 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5346 : context->Global()
5347 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
5348 6 : .ToLocalChecked());
5349 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
5350 : context->Global()
5351 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
5352 6 : .ToLocalChecked());
5353 :
5354 : v8::Local<Value>* args0 = nullptr;
5355 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5356 12 : Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5357 6 : CHECK_EQ(0u, a0->Length());
5358 :
5359 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5360 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5361 12 : Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5362 6 : CHECK_EQ(1u, a1->Length());
5363 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5364 : .ToLocalChecked()
5365 : ->NumberValue(context.local())
5366 : .FromJust());
5367 :
5368 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5369 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5370 12 : Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5371 6 : CHECK_EQ(2u, a2->Length());
5372 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5373 : .ToLocalChecked()
5374 : ->NumberValue(context.local())
5375 : .FromJust());
5376 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5377 : .ToLocalChecked()
5378 : ->NumberValue(context.local())
5379 : .FromJust());
5380 :
5381 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5382 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5383 12 : Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5384 6 : CHECK_EQ(3u, a3->Length());
5385 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5386 : .ToLocalChecked()
5387 : ->NumberValue(context.local())
5388 : .FromJust());
5389 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5390 : .ToLocalChecked()
5391 : ->NumberValue(context.local())
5392 : .FromJust());
5393 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5394 : .ToLocalChecked()
5395 : ->NumberValue(context.local())
5396 : .FromJust());
5397 :
5398 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5399 6 : v8_num(10.11)};
5400 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5401 12 : Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5402 6 : CHECK_EQ(4u, a4->Length());
5403 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5404 : .ToLocalChecked()
5405 : ->NumberValue(context.local())
5406 : .FromJust());
5407 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5408 : .ToLocalChecked()
5409 : ->NumberValue(context.local())
5410 : .FromJust());
5411 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5412 : .ToLocalChecked()
5413 : ->NumberValue(context.local())
5414 : .FromJust());
5415 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5416 : .ToLocalChecked()
5417 : ->NumberValue(context.local())
5418 : .FromJust());
5419 :
5420 : Local<v8::Value> r1 =
5421 : ReturnThisSloppy
5422 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5423 6 : .ToLocalChecked();
5424 12 : CHECK(r1->StrictEquals(context->Global()));
5425 : Local<v8::Value> r2 =
5426 12 : ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, nullptr)
5427 6 : .ToLocalChecked();
5428 12 : CHECK(r2->StrictEquals(context->Global()));
5429 : Local<v8::Value> r3 =
5430 6 : ReturnThisSloppy->Call(context.local(), v8_num(42), 0, nullptr)
5431 6 : .ToLocalChecked();
5432 6 : CHECK(r3->IsNumberObject());
5433 6 : CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5434 : Local<v8::Value> r4 =
5435 18 : ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, nullptr)
5436 6 : .ToLocalChecked();
5437 6 : CHECK(r4->IsStringObject());
5438 18 : CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5439 : Local<v8::Value> r5 =
5440 12 : ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, nullptr)
5441 6 : .ToLocalChecked();
5442 6 : CHECK(r5->IsBooleanObject());
5443 6 : CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5444 :
5445 : Local<v8::Value> r6 =
5446 : ReturnThisStrict
5447 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5448 6 : .ToLocalChecked();
5449 6 : CHECK(r6->IsUndefined());
5450 : Local<v8::Value> r7 =
5451 12 : ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, nullptr)
5452 6 : .ToLocalChecked();
5453 6 : CHECK(r7->IsNull());
5454 : Local<v8::Value> r8 =
5455 6 : ReturnThisStrict->Call(context.local(), v8_num(42), 0, nullptr)
5456 6 : .ToLocalChecked();
5457 6 : CHECK(r8->StrictEquals(v8_num(42)));
5458 : Local<v8::Value> r9 =
5459 18 : ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, nullptr)
5460 6 : .ToLocalChecked();
5461 12 : CHECK(r9->StrictEquals(v8_str("hello")));
5462 : Local<v8::Value> r10 =
5463 12 : ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, nullptr)
5464 6 : .ToLocalChecked();
5465 12 : CHECK(r10->StrictEquals(v8::True(isolate)));
5466 6 : }
5467 :
5468 :
5469 25881 : THREADED_TEST(ConstructCall) {
5470 6 : LocalContext context;
5471 6 : v8::Isolate* isolate = context->GetIsolate();
5472 12 : v8::HandleScope scope(isolate);
5473 : CompileRun(
5474 : "function Foo() {"
5475 : " var result = [];"
5476 : " for (var i = 0; i < arguments.length; i++) {"
5477 : " result.push(arguments[i]);"
5478 : " }"
5479 : " return result;"
5480 : "}");
5481 : Local<Function> Foo = Local<Function>::Cast(
5482 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5483 :
5484 : v8::Local<Value>* args0 = nullptr;
5485 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5486 6 : Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5487 6 : CHECK_EQ(0u, a0->Length());
5488 :
5489 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5490 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5491 6 : Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5492 6 : CHECK_EQ(1u, a1->Length());
5493 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5494 : .ToLocalChecked()
5495 : ->NumberValue(context.local())
5496 : .FromJust());
5497 :
5498 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5499 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5500 6 : Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5501 6 : CHECK_EQ(2u, a2->Length());
5502 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5503 : .ToLocalChecked()
5504 : ->NumberValue(context.local())
5505 : .FromJust());
5506 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5507 : .ToLocalChecked()
5508 : ->NumberValue(context.local())
5509 : .FromJust());
5510 :
5511 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5512 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5513 6 : Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5514 6 : CHECK_EQ(3u, a3->Length());
5515 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5516 : .ToLocalChecked()
5517 : ->NumberValue(context.local())
5518 : .FromJust());
5519 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5520 : .ToLocalChecked()
5521 : ->NumberValue(context.local())
5522 : .FromJust());
5523 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5524 : .ToLocalChecked()
5525 : ->NumberValue(context.local())
5526 : .FromJust());
5527 :
5528 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5529 6 : v8_num(10.11)};
5530 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5531 6 : Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5532 6 : CHECK_EQ(4u, a4->Length());
5533 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5534 : .ToLocalChecked()
5535 : ->NumberValue(context.local())
5536 : .FromJust());
5537 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5538 : .ToLocalChecked()
5539 : ->NumberValue(context.local())
5540 : .FromJust());
5541 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5542 : .ToLocalChecked()
5543 : ->NumberValue(context.local())
5544 : .FromJust());
5545 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5546 : .ToLocalChecked()
5547 : ->NumberValue(context.local())
5548 6 : .FromJust());
5549 6 : }
5550 :
5551 :
5552 25881 : THREADED_TEST(ConversionNumber) {
5553 6 : LocalContext env;
5554 6 : v8::Isolate* isolate = env->GetIsolate();
5555 12 : v8::HandleScope scope(isolate);
5556 : // Very large number.
5557 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5558 : Local<Value> obj =
5559 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5560 12 : CHECK_EQ(5312874545152.0,
5561 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5562 12 : CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5563 12 : CHECK_EQ(0, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5564 : // Large number.
5565 : CompileRun("var obj = -1234567890123;");
5566 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5567 12 : CHECK_EQ(-1234567890123.0,
5568 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5569 12 : CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5570 18 : CHECK_EQ(2382691125, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5571 : // Small positive integer.
5572 : CompileRun("var obj = 42;");
5573 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5574 12 : CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5575 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5576 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5577 : // Negative integer.
5578 : CompileRun("var obj = -37;");
5579 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5580 12 : CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5581 12 : CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5582 18 : CHECK_EQ(4294967259, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5583 : // Positive non-int32 integer.
5584 : CompileRun("var obj = 0x81234567;");
5585 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5586 12 : CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5587 12 : CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5588 18 : CHECK_EQ(2166572391, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5589 : // Fraction.
5590 : CompileRun("var obj = 42.3;");
5591 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5592 12 : CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5593 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5594 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5595 : // Large negative fraction.
5596 : CompileRun("var obj = -5726623061.75;");
5597 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5598 12 : CHECK_EQ(-5726623061.75,
5599 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5600 12 : CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5601 24 : CHECK_EQ(2863311531, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5602 6 : }
5603 :
5604 :
5605 25881 : THREADED_TEST(isNumberType) {
5606 6 : LocalContext env;
5607 12 : v8::HandleScope scope(env->GetIsolate());
5608 : // Very large number.
5609 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5610 : Local<Value> obj =
5611 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5612 6 : CHECK(!obj->IsInt32());
5613 6 : CHECK(!obj->IsUint32());
5614 : // Large negative number.
5615 : CompileRun("var obj = -1234567890123;");
5616 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5617 6 : CHECK(!obj->IsInt32());
5618 6 : CHECK(!obj->IsUint32());
5619 : // Small positive integer.
5620 : CompileRun("var obj = 42;");
5621 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5622 6 : CHECK(obj->IsInt32());
5623 6 : CHECK(obj->IsUint32());
5624 : // Negative integer.
5625 : CompileRun("var obj = -37;");
5626 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5627 6 : CHECK(obj->IsInt32());
5628 6 : CHECK(!obj->IsUint32());
5629 : // Positive non-int32 integer.
5630 : CompileRun("var obj = 0x81234567;");
5631 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5632 6 : CHECK(!obj->IsInt32());
5633 6 : CHECK(obj->IsUint32());
5634 : // Fraction.
5635 : CompileRun("var obj = 42.3;");
5636 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5637 6 : CHECK(!obj->IsInt32());
5638 6 : CHECK(!obj->IsUint32());
5639 : // Large negative fraction.
5640 : CompileRun("var obj = -5726623061.75;");
5641 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5642 6 : CHECK(!obj->IsInt32());
5643 6 : CHECK(!obj->IsUint32());
5644 : // Positive zero
5645 : CompileRun("var obj = 0.0;");
5646 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5647 6 : CHECK(obj->IsInt32());
5648 6 : CHECK(obj->IsUint32());
5649 : // Negative zero
5650 : CompileRun("var obj = -0.0;");
5651 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5652 6 : CHECK(!obj->IsInt32());
5653 12 : CHECK(!obj->IsUint32());
5654 6 : }
5655 :
5656 25881 : THREADED_TEST(IntegerType) {
5657 6 : LocalContext env;
5658 12 : v8::HandleScope scope(env->GetIsolate());
5659 : Local<Value> result;
5660 :
5661 : // Small positive integer
5662 : result = CompileRun("42;");
5663 6 : CHECK(result->IsNumber());
5664 6 : CHECK_EQ(42, result.As<v8::Integer>()->Value());
5665 : // Small negative integer
5666 : result = CompileRun("-42;");
5667 6 : CHECK(result->IsNumber());
5668 6 : CHECK_EQ(-42, result.As<v8::Integer>()->Value());
5669 : // Positive non-int32 integer
5670 : result = CompileRun("1099511627776;");
5671 6 : CHECK(result->IsNumber());
5672 6 : CHECK_EQ(1099511627776, result.As<v8::Integer>()->Value());
5673 : // Negative non-int32 integer
5674 : result = CompileRun("-1099511627776;");
5675 6 : CHECK(result->IsNumber());
5676 6 : CHECK_EQ(-1099511627776, result.As<v8::Integer>()->Value());
5677 : // Positive non-integer
5678 : result = CompileRun("3.14;");
5679 6 : CHECK(result->IsNumber());
5680 6 : CHECK_EQ(3, result.As<v8::Integer>()->Value());
5681 : // Negative non-integer
5682 : result = CompileRun("-3.14;");
5683 6 : CHECK(result->IsNumber());
5684 12 : CHECK_EQ(-3, result.As<v8::Integer>()->Value());
5685 6 : }
5686 :
5687 54 : static void CheckUncle(v8::Isolate* isolate, v8::TryCatch* try_catch) {
5688 54 : CHECK(try_catch->HasCaught());
5689 54 : String::Utf8Value str_value(isolate, try_catch->Exception());
5690 54 : CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5691 54 : try_catch->Reset();
5692 54 : }
5693 :
5694 25881 : THREADED_TEST(ConversionException) {
5695 6 : LocalContext env;
5696 6 : v8::Isolate* isolate = env->GetIsolate();
5697 12 : v8::HandleScope scope(isolate);
5698 : CompileRun(
5699 : "function TestClass() { };"
5700 : "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5701 : "var obj = new TestClass();");
5702 : Local<Value> obj =
5703 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5704 :
5705 12 : v8::TryCatch try_catch(isolate);
5706 :
5707 12 : CHECK(obj->ToString(env.local()).IsEmpty());
5708 6 : CheckUncle(isolate, &try_catch);
5709 :
5710 12 : CHECK(obj->ToNumber(env.local()).IsEmpty());
5711 6 : CheckUncle(isolate, &try_catch);
5712 :
5713 12 : CHECK(obj->ToInteger(env.local()).IsEmpty());
5714 6 : CheckUncle(isolate, &try_catch);
5715 :
5716 12 : CHECK(obj->ToUint32(env.local()).IsEmpty());
5717 6 : CheckUncle(isolate, &try_catch);
5718 :
5719 12 : CHECK(obj->ToInt32(env.local()).IsEmpty());
5720 6 : CheckUncle(isolate, &try_catch);
5721 :
5722 18 : CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5723 6 : CHECK(try_catch.HasCaught());
5724 6 : try_catch.Reset();
5725 :
5726 12 : CHECK(obj->Int32Value(env.local()).IsNothing());
5727 6 : CheckUncle(isolate, &try_catch);
5728 :
5729 12 : CHECK(obj->Uint32Value(env.local()).IsNothing());
5730 6 : CheckUncle(isolate, &try_catch);
5731 :
5732 12 : CHECK(obj->NumberValue(env.local()).IsNothing());
5733 6 : CheckUncle(isolate, &try_catch);
5734 :
5735 12 : CHECK(obj->IntegerValue(env.local()).IsNothing());
5736 12 : CheckUncle(isolate, &try_catch);
5737 6 : }
5738 :
5739 :
5740 56 : void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5741 28 : ApiTestFuzzer::Fuzz();
5742 56 : args.GetIsolate()->ThrowException(v8_str("konto"));
5743 28 : }
5744 :
5745 :
5746 25 : void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5747 5 : if (args.Length() < 1) {
5748 : args.GetReturnValue().Set(false);
5749 5 : return;
5750 : }
5751 5 : v8::HandleScope scope(args.GetIsolate());
5752 10 : v8::TryCatch try_catch(args.GetIsolate());
5753 : Local<Value> result =
5754 : CompileRun(args[0]
5755 5 : ->ToString(args.GetIsolate()->GetCurrentContext())
5756 10 : .ToLocalChecked());
5757 10 : CHECK(!try_catch.HasCaught() || result.IsEmpty());
5758 10 : args.GetReturnValue().Set(try_catch.HasCaught());
5759 : }
5760 :
5761 :
5762 25881 : THREADED_TEST(APICatch) {
5763 6 : v8::Isolate* isolate = CcTest::isolate();
5764 6 : v8::HandleScope scope(isolate);
5765 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5766 : templ->Set(v8_str("ThrowFromC"),
5767 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5768 12 : LocalContext context(nullptr, templ);
5769 : CompileRun(
5770 : "var thrown = false;"
5771 : "try {"
5772 : " ThrowFromC();"
5773 : "} catch (e) {"
5774 : " thrown = true;"
5775 : "}");
5776 : Local<Value> thrown = context->Global()
5777 24 : ->Get(context.local(), v8_str("thrown"))
5778 6 : .ToLocalChecked();
5779 12 : CHECK(thrown->BooleanValue(isolate));
5780 6 : }
5781 :
5782 :
5783 25881 : THREADED_TEST(APIThrowTryCatch) {
5784 6 : v8::Isolate* isolate = CcTest::isolate();
5785 6 : v8::HandleScope scope(isolate);
5786 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5787 : templ->Set(v8_str("ThrowFromC"),
5788 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5789 12 : LocalContext context(nullptr, templ);
5790 12 : v8::TryCatch try_catch(isolate);
5791 : CompileRun("ThrowFromC();");
5792 12 : CHECK(try_catch.HasCaught());
5793 6 : }
5794 :
5795 :
5796 : // Test that a try-finally block doesn't shadow a try-catch block
5797 : // when setting up an external handler.
5798 : //
5799 : // BUG(271): Some of the exception propagation does not work on the
5800 : // ARM simulator because the simulator separates the C++ stack and the
5801 : // JS stack. This test therefore fails on the simulator. The test is
5802 : // not threaded to allow the threading tests to run on the simulator.
5803 25880 : TEST(TryCatchInTryFinally) {
5804 5 : v8::Isolate* isolate = CcTest::isolate();
5805 5 : v8::HandleScope scope(isolate);
5806 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5807 15 : templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5808 10 : LocalContext context(nullptr, templ);
5809 : Local<Value> result = CompileRun(
5810 : "try {"
5811 : " try {"
5812 : " CCatcher('throw 7;');"
5813 : " } finally {"
5814 : " }"
5815 : "} catch (e) {"
5816 : "}");
5817 10 : CHECK(result->IsTrue());
5818 5 : }
5819 :
5820 :
5821 5 : static void check_custom_error_tostring(v8::Local<v8::Message> message,
5822 : v8::Local<v8::Value> data) {
5823 : const char* uncaught_error = "Uncaught MyError toString";
5824 25 : CHECK(message->Get()
5825 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5826 : v8_str(uncaught_error))
5827 : .FromJust());
5828 5 : }
5829 :
5830 :
5831 25880 : TEST(CustomErrorToString) {
5832 5 : LocalContext context;
5833 10 : v8::HandleScope scope(context->GetIsolate());
5834 5 : context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5835 : CompileRun(
5836 : "function MyError(name, message) { "
5837 : " this.name = name; "
5838 : " this.message = message; "
5839 : "} "
5840 : "MyError.prototype = Object.create(Error.prototype); "
5841 : "MyError.prototype.toString = function() { "
5842 : " return 'MyError toString'; "
5843 : "}; "
5844 : "throw new MyError('my name', 'my message'); ");
5845 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5846 5 : }
5847 :
5848 :
5849 15 : static void check_custom_error_message(v8::Local<v8::Message> message,
5850 : v8::Local<v8::Value> data) {
5851 : const char* uncaught_error = "Uncaught MyError: my message";
5852 45 : printf("%s\n", *v8::String::Utf8Value(CcTest::isolate(), message->Get()));
5853 60 : CHECK(message->Get()
5854 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5855 : v8_str(uncaught_error))
5856 : .FromJust());
5857 15 : }
5858 :
5859 :
5860 25880 : TEST(CustomErrorMessage) {
5861 5 : LocalContext context;
5862 10 : v8::HandleScope scope(context->GetIsolate());
5863 5 : context->GetIsolate()->AddMessageListener(check_custom_error_message);
5864 :
5865 : // Handlebars.
5866 : CompileRun(
5867 : "function MyError(msg) { "
5868 : " this.name = 'MyError'; "
5869 : " this.message = msg; "
5870 : "} "
5871 : "MyError.prototype = new Error(); "
5872 : "throw new MyError('my message'); ");
5873 :
5874 : // Closure.
5875 : CompileRun(
5876 : "function MyError(msg) { "
5877 : " this.name = 'MyError'; "
5878 : " this.message = msg; "
5879 : "} "
5880 : "inherits = function(childCtor, parentCtor) { "
5881 : " function tempCtor() {}; "
5882 : " tempCtor.prototype = parentCtor.prototype; "
5883 : " childCtor.superClass_ = parentCtor.prototype; "
5884 : " childCtor.prototype = new tempCtor(); "
5885 : " childCtor.prototype.constructor = childCtor; "
5886 : "}; "
5887 : "inherits(MyError, Error); "
5888 : "throw new MyError('my message'); ");
5889 :
5890 : // Object.create.
5891 : CompileRun(
5892 : "function MyError(msg) { "
5893 : " this.name = 'MyError'; "
5894 : " this.message = msg; "
5895 : "} "
5896 : "MyError.prototype = Object.create(Error.prototype); "
5897 : "throw new MyError('my message'); ");
5898 :
5899 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5900 5 : }
5901 :
5902 :
5903 10 : static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5904 : v8::Local<v8::Value> data) {
5905 10 : CHECK(data->IsExternal());
5906 10 : int* callcount = static_cast<int*>(data.As<v8::External>()->Value());
5907 10 : ++*callcount;
5908 :
5909 : const char* uncaught_error = "Uncaught exception";
5910 50 : CHECK(message->Get()
5911 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5912 : v8_str(uncaught_error))
5913 : .FromJust());
5914 : // Test that compiling code inside a message handler works.
5915 40 : CHECK(CompileRunChecked(CcTest::isolate(), "(function(a) { return a; })(42)")
5916 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5917 : v8::Integer::NewFromUnsigned(CcTest::isolate(), 42))
5918 : .FromJust());
5919 10 : }
5920 :
5921 :
5922 25880 : TEST(CustomErrorRethrowsOnToString) {
5923 5 : int callcount = 0;
5924 5 : LocalContext context;
5925 5 : v8::Isolate* isolate = context->GetIsolate();
5926 10 : v8::HandleScope scope(isolate);
5927 : context->GetIsolate()->AddMessageListener(
5928 10 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5929 :
5930 : CompileRun(
5931 : "var e = { toString: function() { throw e; } };"
5932 : "try { throw e; } finally {}");
5933 :
5934 5 : CHECK_EQ(callcount, 1);
5935 : context->GetIsolate()->RemoveMessageListeners(
5936 10 : check_custom_rethrowing_message);
5937 5 : }
5938 :
5939 25880 : TEST(CustomErrorRethrowsOnToStringInsideVerboseTryCatch) {
5940 5 : int callcount = 0;
5941 5 : LocalContext context;
5942 5 : v8::Isolate* isolate = context->GetIsolate();
5943 10 : v8::HandleScope scope(isolate);
5944 10 : v8::TryCatch try_catch(isolate);
5945 5 : try_catch.SetVerbose(true);
5946 : context->GetIsolate()->AddMessageListener(
5947 10 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5948 :
5949 : CompileRun(
5950 : "var e = { toString: function() { throw e; } };"
5951 : "try { throw e; } finally {}");
5952 :
5953 5 : CHECK_EQ(callcount, 1);
5954 : context->GetIsolate()->RemoveMessageListeners(
5955 10 : check_custom_rethrowing_message);
5956 5 : }
5957 :
5958 :
5959 15 : static void receive_message(v8::Local<v8::Message> message,
5960 : v8::Local<v8::Value> data) {
5961 15 : message->Get();
5962 15 : message_received = true;
5963 15 : }
5964 :
5965 :
5966 25880 : TEST(APIThrowMessage) {
5967 5 : message_received = false;
5968 5 : v8::Isolate* isolate = CcTest::isolate();
5969 5 : v8::HandleScope scope(isolate);
5970 5 : isolate->AddMessageListener(receive_message);
5971 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5972 : templ->Set(v8_str("ThrowFromC"),
5973 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5974 10 : LocalContext context(nullptr, templ);
5975 : CompileRun("ThrowFromC();");
5976 5 : CHECK(message_received);
5977 10 : isolate->RemoveMessageListeners(receive_message);
5978 5 : }
5979 :
5980 :
5981 25880 : TEST(APIThrowMessageAndVerboseTryCatch) {
5982 5 : message_received = false;
5983 5 : v8::Isolate* isolate = CcTest::isolate();
5984 5 : v8::HandleScope scope(isolate);
5985 5 : isolate->AddMessageListener(receive_message);
5986 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5987 : templ->Set(v8_str("ThrowFromC"),
5988 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5989 10 : LocalContext context(nullptr, templ);
5990 10 : v8::TryCatch try_catch(isolate);
5991 5 : try_catch.SetVerbose(true);
5992 : Local<Value> result = CompileRun("ThrowFromC();");
5993 5 : CHECK(try_catch.HasCaught());
5994 5 : CHECK(result.IsEmpty());
5995 5 : CHECK(message_received);
5996 10 : isolate->RemoveMessageListeners(receive_message);
5997 5 : }
5998 :
5999 :
6000 25880 : TEST(APIStackOverflowAndVerboseTryCatch) {
6001 5 : message_received = false;
6002 5 : LocalContext context;
6003 10 : v8::HandleScope scope(context->GetIsolate());
6004 5 : context->GetIsolate()->AddMessageListener(receive_message);
6005 10 : v8::TryCatch try_catch(context->GetIsolate());
6006 5 : try_catch.SetVerbose(true);
6007 : Local<Value> result = CompileRun("function foo() { foo(); } foo();");
6008 5 : CHECK(try_catch.HasCaught());
6009 5 : CHECK(result.IsEmpty());
6010 5 : CHECK(message_received);
6011 10 : context->GetIsolate()->RemoveMessageListeners(receive_message);
6012 5 : }
6013 :
6014 :
6015 25881 : THREADED_TEST(ExternalScriptException) {
6016 6 : v8::Isolate* isolate = CcTest::isolate();
6017 6 : v8::HandleScope scope(isolate);
6018 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6019 : templ->Set(v8_str("ThrowFromC"),
6020 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
6021 12 : LocalContext context(nullptr, templ);
6022 :
6023 12 : v8::TryCatch try_catch(isolate);
6024 : Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
6025 6 : CHECK(result.IsEmpty());
6026 6 : CHECK(try_catch.HasCaught());
6027 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6028 12 : CHECK_EQ(0, strcmp("konto", *exception_value));
6029 6 : }
6030 :
6031 :
6032 370 : void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
6033 85 : ApiTestFuzzer::Fuzz();
6034 85 : CHECK_EQ(4, args.Length());
6035 85 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6036 170 : int count = args[0]->Int32Value(context).FromJust();
6037 170 : int cInterval = args[2]->Int32Value(context).FromJust();
6038 85 : if (count == 0) {
6039 10 : args.GetIsolate()->ThrowException(v8_str("FromC"));
6040 5 : return;
6041 : } else {
6042 80 : Local<v8::Object> global = context->Global();
6043 : Local<Value> fun =
6044 240 : global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
6045 320 : v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
6046 80 : if (count % cInterval == 0) {
6047 30 : v8::TryCatch try_catch(args.GetIsolate());
6048 : Local<Value> result = fun.As<Function>()
6049 30 : ->Call(context, global, 4, argv)
6050 60 : .FromMaybe(Local<Value>());
6051 60 : int expected = args[3]->Int32Value(context).FromJust();
6052 30 : if (try_catch.HasCaught()) {
6053 15 : CHECK_EQ(expected, count);
6054 15 : CHECK(result.IsEmpty());
6055 15 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
6056 : } else {
6057 15 : CHECK_NE(expected, count);
6058 : }
6059 : args.GetReturnValue().Set(result);
6060 30 : return;
6061 : } else {
6062 : args.GetReturnValue().Set(fun.As<Function>()
6063 50 : ->Call(context, global, 4, argv)
6064 100 : .FromMaybe(v8::Local<v8::Value>()));
6065 50 : return;
6066 : }
6067 : }
6068 : }
6069 :
6070 :
6071 75 : void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
6072 25 : ApiTestFuzzer::Fuzz();
6073 25 : CHECK_EQ(3, args.Length());
6074 : v8::Isolate* isolate = args.GetIsolate();
6075 25 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
6076 25 : bool equality = args[0]->BooleanValue(isolate);
6077 50 : int count = args[1]->Int32Value(context).FromJust();
6078 50 : int expected = args[2]->Int32Value(context).FromJust();
6079 25 : if (equality) {
6080 15 : CHECK_EQ(count, expected);
6081 : } else {
6082 10 : CHECK_NE(count, expected);
6083 : }
6084 25 : }
6085 :
6086 :
6087 25881 : THREADED_TEST(EvalInTryFinally) {
6088 6 : LocalContext context;
6089 12 : v8::HandleScope scope(context->GetIsolate());
6090 12 : v8::TryCatch try_catch(context->GetIsolate());
6091 : CompileRun(
6092 : "(function() {"
6093 : " try {"
6094 : " eval('asldkf (*&^&*^');"
6095 : " } finally {"
6096 : " return;"
6097 : " }"
6098 : "})()");
6099 12 : CHECK(!try_catch.HasCaught());
6100 6 : }
6101 :
6102 :
6103 : // This test works by making a stack of alternating JavaScript and C
6104 : // activations. These activations set up exception handlers with regular
6105 : // intervals, one interval for C activations and another for JavaScript
6106 : // activations. When enough activations have been created an exception is
6107 : // thrown and we check that the right activation catches the exception and that
6108 : // no other activations do. The right activation is always the topmost one with
6109 : // a handler, regardless of whether it is in JavaScript or C.
6110 : //
6111 : // The notation used to describe a test case looks like this:
6112 : //
6113 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6114 : //
6115 : // Each entry is an activation, either JS or C. The index is the count at that
6116 : // level. Stars identify activations with exception handlers, the @ identifies
6117 : // the exception handler that should catch the exception.
6118 : //
6119 : // BUG(271): Some of the exception propagation does not work on the
6120 : // ARM simulator because the simulator separates the C++ stack and the
6121 : // JS stack. This test therefore fails on the simulator. The test is
6122 : // not threaded to allow the threading tests to run on the simulator.
6123 25880 : TEST(ExceptionOrder) {
6124 5 : v8::Isolate* isolate = CcTest::isolate();
6125 5 : v8::HandleScope scope(isolate);
6126 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6127 15 : templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
6128 : templ->Set(v8_str("CThrowCountDown"),
6129 15 : v8::FunctionTemplate::New(isolate, CThrowCountDown));
6130 10 : LocalContext context(nullptr, templ);
6131 : CompileRun(
6132 : "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
6133 : " if (count == 0) throw 'FromJS';"
6134 : " if (count % jsInterval == 0) {"
6135 : " try {"
6136 : " var value = CThrowCountDown(count - 1,"
6137 : " jsInterval,"
6138 : " cInterval,"
6139 : " expected);"
6140 : " check(false, count, expected);"
6141 : " return value;"
6142 : " } catch (e) {"
6143 : " check(true, count, expected);"
6144 : " }"
6145 : " } else {"
6146 : " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
6147 : " }"
6148 : "}");
6149 : Local<Function> fun = Local<Function>::Cast(
6150 : context->Global()
6151 20 : ->Get(context.local(), v8_str("JSThrowCountDown"))
6152 5 : .ToLocalChecked());
6153 :
6154 : const int argc = 4;
6155 : // count jsInterval cInterval expected
6156 :
6157 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6158 5 : v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6159 10 : fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6160 :
6161 : // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6162 5 : v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6163 10 : fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6164 :
6165 : // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6166 5 : v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6167 10 : fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6168 :
6169 : // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6170 5 : v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6171 10 : fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6172 :
6173 : // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6174 5 : v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6175 10 : fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6176 :
6177 : // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6178 5 : v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6179 15 : fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6180 5 : }
6181 :
6182 :
6183 126 : void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6184 42 : ApiTestFuzzer::Fuzz();
6185 42 : CHECK_EQ(1, args.Length());
6186 42 : args.GetIsolate()->ThrowException(args[0]);
6187 42 : }
6188 :
6189 :
6190 25881 : THREADED_TEST(ThrowValues) {
6191 6 : v8::Isolate* isolate = CcTest::isolate();
6192 6 : v8::HandleScope scope(isolate);
6193 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6194 18 : templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6195 12 : LocalContext context(nullptr, templ);
6196 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6197 : CompileRun("function Run(obj) {"
6198 : " try {"
6199 : " Throw(obj);"
6200 : " } catch (e) {"
6201 : " return e;"
6202 : " }"
6203 : " return 'no exception';"
6204 : "}"
6205 : "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6206 6 : CHECK_EQ(5u, result->Length());
6207 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6208 : .ToLocalChecked()
6209 : ->IsString());
6210 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6211 : .ToLocalChecked()
6212 : ->IsNumber());
6213 24 : CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6214 : .ToLocalChecked()
6215 : ->Int32Value(context.local())
6216 : .FromJust());
6217 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6218 : .ToLocalChecked()
6219 : ->IsNumber());
6220 24 : CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6221 : .ToLocalChecked()
6222 : ->Int32Value(context.local())
6223 : .FromJust());
6224 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6225 : .ToLocalChecked()
6226 : ->IsNull());
6227 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6228 : .ToLocalChecked()
6229 6 : ->IsUndefined());
6230 6 : }
6231 :
6232 :
6233 25881 : THREADED_TEST(CatchZero) {
6234 6 : LocalContext context;
6235 12 : v8::HandleScope scope(context->GetIsolate());
6236 12 : v8::TryCatch try_catch(context->GetIsolate());
6237 6 : CHECK(!try_catch.HasCaught());
6238 : CompileRun("throw 10");
6239 6 : CHECK(try_catch.HasCaught());
6240 18 : CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6241 6 : try_catch.Reset();
6242 6 : CHECK(!try_catch.HasCaught());
6243 : CompileRun("throw 0");
6244 6 : CHECK(try_catch.HasCaught());
6245 24 : CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6246 6 : }
6247 :
6248 :
6249 25881 : THREADED_TEST(CatchExceptionFromWith) {
6250 6 : LocalContext context;
6251 12 : v8::HandleScope scope(context->GetIsolate());
6252 12 : v8::TryCatch try_catch(context->GetIsolate());
6253 6 : CHECK(!try_catch.HasCaught());
6254 : CompileRun("var o = {}; with (o) { throw 42; }");
6255 12 : CHECK(try_catch.HasCaught());
6256 6 : }
6257 :
6258 :
6259 25881 : THREADED_TEST(TryCatchAndFinallyHidingException) {
6260 6 : LocalContext context;
6261 12 : v8::HandleScope scope(context->GetIsolate());
6262 12 : v8::TryCatch try_catch(context->GetIsolate());
6263 6 : CHECK(!try_catch.HasCaught());
6264 : CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6265 : CompileRun("f({toString: function() { throw 42; }});");
6266 12 : CHECK(!try_catch.HasCaught());
6267 6 : }
6268 :
6269 :
6270 6 : void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6271 6 : v8::TryCatch try_catch(args.GetIsolate());
6272 6 : }
6273 :
6274 :
6275 25881 : THREADED_TEST(TryCatchAndFinally) {
6276 6 : LocalContext context;
6277 6 : v8::Isolate* isolate = context->GetIsolate();
6278 12 : v8::HandleScope scope(isolate);
6279 48 : CHECK(context->Global()
6280 : ->Set(context.local(), v8_str("native_with_try_catch"),
6281 : v8::FunctionTemplate::New(isolate, WithTryCatch)
6282 : ->GetFunction(context.local())
6283 : .ToLocalChecked())
6284 : .FromJust());
6285 12 : v8::TryCatch try_catch(isolate);
6286 6 : CHECK(!try_catch.HasCaught());
6287 : CompileRun(
6288 : "try {\n"
6289 : " throw new Error('a');\n"
6290 : "} finally {\n"
6291 : " native_with_try_catch();\n"
6292 : "}\n");
6293 12 : CHECK(try_catch.HasCaught());
6294 6 : }
6295 :
6296 :
6297 30 : static void TryCatchNested1Helper(int depth) {
6298 30 : if (depth > 0) {
6299 25 : v8::TryCatch try_catch(CcTest::isolate());
6300 25 : try_catch.SetVerbose(true);
6301 25 : TryCatchNested1Helper(depth - 1);
6302 25 : CHECK(try_catch.HasCaught());
6303 25 : try_catch.ReThrow();
6304 : } else {
6305 10 : CcTest::isolate()->ThrowException(v8_str("E1"));
6306 : }
6307 30 : }
6308 :
6309 :
6310 30 : static void TryCatchNested2Helper(int depth) {
6311 30 : if (depth > 0) {
6312 25 : v8::TryCatch try_catch(CcTest::isolate());
6313 25 : try_catch.SetVerbose(true);
6314 25 : TryCatchNested2Helper(depth - 1);
6315 25 : CHECK(try_catch.HasCaught());
6316 25 : try_catch.ReThrow();
6317 : } else {
6318 : CompileRun("throw 'E2';");
6319 : }
6320 30 : }
6321 :
6322 :
6323 25880 : TEST(TryCatchNested) {
6324 5 : v8::V8::Initialize();
6325 5 : LocalContext context;
6326 10 : v8::HandleScope scope(context->GetIsolate());
6327 :
6328 : {
6329 : // Test nested try-catch with a native throw in the end.
6330 5 : v8::TryCatch try_catch(context->GetIsolate());
6331 5 : TryCatchNested1Helper(5);
6332 5 : CHECK(try_catch.HasCaught());
6333 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6334 : try_catch.Exception()),
6335 5 : "E1"));
6336 : }
6337 :
6338 : {
6339 : // Test nested try-catch with a JavaScript throw in the end.
6340 5 : v8::TryCatch try_catch(context->GetIsolate());
6341 5 : TryCatchNested2Helper(5);
6342 5 : CHECK(try_catch.HasCaught());
6343 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6344 : try_catch.Exception()),
6345 5 : "E2"));
6346 5 : }
6347 5 : }
6348 :
6349 :
6350 10 : void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6351 10 : CHECK(try_catch->HasCaught());
6352 10 : Local<Message> message = try_catch->Message();
6353 10 : Local<Value> resource = message->GetScriptOrigin().ResourceName();
6354 10 : CHECK_EQ(
6355 : 0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), resource), "inner"));
6356 20 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), message->Get()),
6357 : "Uncaught Error: a"));
6358 20 : CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6359 : .FromJust());
6360 20 : CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6361 : .FromJust());
6362 10 : }
6363 :
6364 :
6365 5 : void TryCatchMixedNestingHelper(
6366 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6367 5 : ApiTestFuzzer::Fuzz();
6368 5 : v8::TryCatch try_catch(args.GetIsolate());
6369 5 : CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6370 5 : CHECK(try_catch.HasCaught());
6371 5 : TryCatchMixedNestingCheck(&try_catch);
6372 5 : try_catch.ReThrow();
6373 5 : }
6374 :
6375 :
6376 : // This test ensures that an outer TryCatch in the following situation:
6377 : // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6378 : // does not clobber the Message object generated for the inner TryCatch.
6379 : // This exercises the ability of TryCatch.ReThrow() to restore the
6380 : // inner pending Message before throwing the exception again.
6381 25880 : TEST(TryCatchMixedNesting) {
6382 5 : v8::Isolate* isolate = CcTest::isolate();
6383 5 : v8::HandleScope scope(isolate);
6384 5 : v8::V8::Initialize();
6385 10 : v8::TryCatch try_catch(isolate);
6386 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6387 : templ->Set(v8_str("TryCatchMixedNestingHelper"),
6388 15 : v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6389 10 : LocalContext context(nullptr, templ);
6390 5 : CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6391 10 : TryCatchMixedNestingCheck(&try_catch);
6392 5 : }
6393 :
6394 :
6395 15 : void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6396 5 : ApiTestFuzzer::Fuzz();
6397 5 : v8::TryCatch try_catch(args.GetIsolate());
6398 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6399 5 : CHECK(try_catch.HasCaught());
6400 5 : }
6401 :
6402 :
6403 25880 : TEST(TryCatchNative) {
6404 5 : v8::Isolate* isolate = CcTest::isolate();
6405 5 : v8::HandleScope scope(isolate);
6406 5 : v8::V8::Initialize();
6407 10 : v8::TryCatch try_catch(isolate);
6408 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6409 : templ->Set(v8_str("TryCatchNativeHelper"),
6410 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6411 10 : LocalContext context(nullptr, templ);
6412 : CompileRun("TryCatchNativeHelper();");
6413 10 : CHECK(!try_catch.HasCaught());
6414 5 : }
6415 :
6416 :
6417 5 : void TryCatchNativeResetHelper(
6418 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6419 5 : ApiTestFuzzer::Fuzz();
6420 5 : v8::TryCatch try_catch(args.GetIsolate());
6421 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6422 5 : CHECK(try_catch.HasCaught());
6423 5 : try_catch.Reset();
6424 5 : CHECK(!try_catch.HasCaught());
6425 5 : }
6426 :
6427 :
6428 25880 : TEST(TryCatchNativeReset) {
6429 5 : v8::Isolate* isolate = CcTest::isolate();
6430 5 : v8::HandleScope scope(isolate);
6431 5 : v8::V8::Initialize();
6432 10 : v8::TryCatch try_catch(isolate);
6433 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6434 : templ->Set(v8_str("TryCatchNativeResetHelper"),
6435 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6436 10 : LocalContext context(nullptr, templ);
6437 : CompileRun("TryCatchNativeResetHelper();");
6438 10 : CHECK(!try_catch.HasCaught());
6439 5 : }
6440 :
6441 :
6442 25881 : THREADED_TEST(Equality) {
6443 6 : LocalContext context;
6444 6 : v8::Isolate* isolate = context->GetIsolate();
6445 12 : v8::HandleScope scope(context->GetIsolate());
6446 : // Check that equality works at all before relying on CHECK_EQ
6447 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6448 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6449 :
6450 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6451 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6452 18 : CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6453 18 : CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6454 18 : CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6455 :
6456 : // Assume String is not internalized.
6457 18 : CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6458 18 : CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6459 12 : CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6460 12 : CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6461 12 : CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6462 12 : CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6463 6 : Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6464 6 : CHECK(!not_a_number->StrictEquals(not_a_number));
6465 6 : CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6466 6 : CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6467 :
6468 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
6469 : v8::Persistent<v8::Object> alias(isolate, obj);
6470 6 : CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6471 : alias.Reset();
6472 :
6473 18 : CHECK(v8_str("a")->SameValue(v8_str("a")));
6474 18 : CHECK(!v8_str("a")->SameValue(v8_str("b")));
6475 12 : CHECK(!v8_str("5")->SameValue(v8_num(5)));
6476 12 : CHECK(v8_num(1)->SameValue(v8_num(1)));
6477 12 : CHECK(!v8_num(1)->SameValue(v8_num(2)));
6478 12 : CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6479 6 : CHECK(not_a_number->SameValue(not_a_number));
6480 6 : CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6481 12 : CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6482 6 : }
6483 :
6484 25881 : THREADED_TEST(TypeOf) {
6485 6 : LocalContext context;
6486 6 : v8::Isolate* isolate = context->GetIsolate();
6487 12 : v8::HandleScope scope(context->GetIsolate());
6488 :
6489 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6490 12 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6491 :
6492 30 : CHECK(v8::Undefined(isolate)
6493 : ->TypeOf(isolate)
6494 : ->Equals(context.local(), v8_str("undefined"))
6495 : .FromJust());
6496 30 : CHECK(v8::Null(isolate)
6497 : ->TypeOf(isolate)
6498 : ->Equals(context.local(), v8_str("object"))
6499 : .FromJust());
6500 30 : CHECK(v8_str("str")
6501 : ->TypeOf(isolate)
6502 : ->Equals(context.local(), v8_str("string"))
6503 : .FromJust());
6504 30 : CHECK(v8_num(0.0)
6505 : ->TypeOf(isolate)
6506 : ->Equals(context.local(), v8_str("number"))
6507 : .FromJust());
6508 30 : CHECK(v8_num(1)
6509 : ->TypeOf(isolate)
6510 : ->Equals(context.local(), v8_str("number"))
6511 : .FromJust());
6512 30 : CHECK(v8::Object::New(isolate)
6513 : ->TypeOf(isolate)
6514 : ->Equals(context.local(), v8_str("object"))
6515 : .FromJust());
6516 30 : CHECK(v8::Boolean::New(isolate, true)
6517 : ->TypeOf(isolate)
6518 : ->Equals(context.local(), v8_str("boolean"))
6519 : .FromJust());
6520 24 : CHECK(fun->TypeOf(isolate)
6521 : ->Equals(context.local(), v8_str("function"))
6522 6 : .FromJust());
6523 6 : }
6524 :
6525 25881 : THREADED_TEST(InstanceOf) {
6526 6 : LocalContext env;
6527 12 : v8::HandleScope scope(env->GetIsolate());
6528 : CompileRun(
6529 : "var A = {};"
6530 : "var B = {};"
6531 : "var C = {};"
6532 : "B.__proto__ = A;"
6533 : "C.__proto__ = B;"
6534 : "function F() {}"
6535 : "F.prototype = A;"
6536 : "var G = { [Symbol.hasInstance] : null};"
6537 : "var H = { [Symbol.hasInstance] : () => { throw new Error(); } };"
6538 : "var J = { [Symbol.hasInstance] : () => true };"
6539 : "class K {}"
6540 : "var D = new K;"
6541 : "class L extends K {}"
6542 : "var E = new L");
6543 :
6544 6 : v8::Local<v8::Object> f = v8::Local<v8::Object>::Cast(CompileRun("F"));
6545 6 : v8::Local<v8::Object> g = v8::Local<v8::Object>::Cast(CompileRun("G"));
6546 6 : v8::Local<v8::Object> h = v8::Local<v8::Object>::Cast(CompileRun("H"));
6547 6 : v8::Local<v8::Object> j = v8::Local<v8::Object>::Cast(CompileRun("J"));
6548 6 : v8::Local<v8::Object> k = v8::Local<v8::Object>::Cast(CompileRun("K"));
6549 6 : v8::Local<v8::Object> l = v8::Local<v8::Object>::Cast(CompileRun("L"));
6550 : v8::Local<v8::Value> a = v8::Local<v8::Value>::Cast(CompileRun("A"));
6551 : v8::Local<v8::Value> b = v8::Local<v8::Value>::Cast(CompileRun("B"));
6552 : v8::Local<v8::Value> c = v8::Local<v8::Value>::Cast(CompileRun("C"));
6553 : v8::Local<v8::Value> d = v8::Local<v8::Value>::Cast(CompileRun("D"));
6554 : v8::Local<v8::Value> e = v8::Local<v8::Value>::Cast(CompileRun("E"));
6555 :
6556 12 : v8::TryCatch try_catch(env->GetIsolate());
6557 12 : CHECK(!a->InstanceOf(env.local(), f).ToChecked());
6558 12 : CHECK(b->InstanceOf(env.local(), f).ToChecked());
6559 12 : CHECK(c->InstanceOf(env.local(), f).ToChecked());
6560 12 : CHECK(!d->InstanceOf(env.local(), f).ToChecked());
6561 12 : CHECK(!e->InstanceOf(env.local(), f).ToChecked());
6562 6 : CHECK(!try_catch.HasCaught());
6563 :
6564 12 : CHECK(a->InstanceOf(env.local(), g).IsNothing());
6565 6 : CHECK(try_catch.HasCaught());
6566 6 : try_catch.Reset();
6567 :
6568 12 : CHECK(b->InstanceOf(env.local(), h).IsNothing());
6569 6 : CHECK(try_catch.HasCaught());
6570 6 : try_catch.Reset();
6571 :
6572 18 : CHECK(v8_num(1)->InstanceOf(env.local(), j).ToChecked());
6573 6 : CHECK(!try_catch.HasCaught());
6574 :
6575 12 : CHECK(d->InstanceOf(env.local(), k).ToChecked());
6576 12 : CHECK(e->InstanceOf(env.local(), k).ToChecked());
6577 12 : CHECK(!d->InstanceOf(env.local(), l).ToChecked());
6578 12 : CHECK(e->InstanceOf(env.local(), l).ToChecked());
6579 12 : CHECK(!try_catch.HasCaught());
6580 6 : }
6581 :
6582 25881 : THREADED_TEST(MultiRun) {
6583 6 : LocalContext context;
6584 12 : v8::HandleScope scope(context->GetIsolate());
6585 : Local<Script> script = v8_compile("x");
6586 66 : for (int i = 0; i < 10; i++) {
6587 60 : script->Run(context.local()).IsEmpty();
6588 6 : }
6589 6 : }
6590 :
6591 :
6592 204 : static void GetXValue(Local<Name> name,
6593 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6594 204 : ApiTestFuzzer::Fuzz();
6595 816 : CHECK(info.Data()
6596 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6597 : .FromJust());
6598 816 : CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6599 : .FromJust());
6600 : info.GetReturnValue().Set(name);
6601 204 : }
6602 :
6603 :
6604 25881 : THREADED_TEST(SimplePropertyRead) {
6605 6 : LocalContext context;
6606 6 : v8::Isolate* isolate = context->GetIsolate();
6607 12 : v8::HandleScope scope(isolate);
6608 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6609 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6610 36 : CHECK(context->Global()
6611 : ->Set(context.local(), v8_str("obj"),
6612 : templ->NewInstance(context.local()).ToLocalChecked())
6613 : .FromJust());
6614 : Local<Script> script = v8_compile("obj.x");
6615 66 : for (int i = 0; i < 10; i++) {
6616 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
6617 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6618 6 : }
6619 6 : }
6620 :
6621 :
6622 25881 : THREADED_TEST(DefinePropertyOnAPIAccessor) {
6623 6 : LocalContext context;
6624 6 : v8::Isolate* isolate = context->GetIsolate();
6625 12 : v8::HandleScope scope(isolate);
6626 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6627 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6628 36 : CHECK(context->Global()
6629 : ->Set(context.local(), v8_str("obj"),
6630 : templ->NewInstance(context.local()).ToLocalChecked())
6631 : .FromJust());
6632 :
6633 : // Uses getOwnPropertyDescriptor to check the configurable status
6634 : Local<Script> script_desc = v8_compile(
6635 : "var prop = Object.getOwnPropertyDescriptor( "
6636 : "obj, 'x');"
6637 : "prop.configurable;");
6638 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6639 6 : CHECK(result->BooleanValue(isolate));
6640 :
6641 : // Redefine get - but still configurable
6642 : Local<Script> script_define = v8_compile(
6643 : "var desc = { get: function(){return 42; },"
6644 : " configurable: true };"
6645 : "Object.defineProperty(obj, 'x', desc);"
6646 : "obj.x");
6647 6 : result = script_define->Run(context.local()).ToLocalChecked();
6648 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6649 :
6650 : // Check that the accessor is still configurable
6651 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6652 6 : CHECK(result->BooleanValue(isolate));
6653 :
6654 : // Redefine to a non-configurable
6655 : script_define = v8_compile(
6656 : "var desc = { get: function(){return 43; },"
6657 : " configurable: false };"
6658 : "Object.defineProperty(obj, 'x', desc);"
6659 : "obj.x");
6660 6 : result = script_define->Run(context.local()).ToLocalChecked();
6661 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6662 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6663 6 : CHECK(!result->BooleanValue(isolate));
6664 :
6665 : // Make sure that it is not possible to redefine again
6666 12 : v8::TryCatch try_catch(isolate);
6667 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6668 6 : CHECK(try_catch.HasCaught());
6669 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6670 6 : CHECK_EQ(0,
6671 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6672 6 : }
6673 :
6674 :
6675 25881 : THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6676 6 : v8::Isolate* isolate = CcTest::isolate();
6677 6 : v8::HandleScope scope(isolate);
6678 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6679 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6680 12 : LocalContext context;
6681 36 : CHECK(context->Global()
6682 : ->Set(context.local(), v8_str("obj"),
6683 : templ->NewInstance(context.local()).ToLocalChecked())
6684 : .FromJust());
6685 :
6686 : Local<Script> script_desc = v8_compile(
6687 : "var prop ="
6688 : "Object.getOwnPropertyDescriptor( "
6689 : "obj, 'x');"
6690 : "prop.configurable;");
6691 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6692 6 : CHECK(result->BooleanValue(isolate));
6693 :
6694 : Local<Script> script_define = v8_compile(
6695 : "var desc = {get: function(){return 42; },"
6696 : " configurable: true };"
6697 : "Object.defineProperty(obj, 'x', desc);"
6698 : "obj.x");
6699 6 : result = script_define->Run(context.local()).ToLocalChecked();
6700 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6701 :
6702 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6703 6 : CHECK(result->BooleanValue(isolate));
6704 :
6705 : script_define = v8_compile(
6706 : "var desc = {get: function(){return 43; },"
6707 : " configurable: false };"
6708 : "Object.defineProperty(obj, 'x', desc);"
6709 : "obj.x");
6710 6 : result = script_define->Run(context.local()).ToLocalChecked();
6711 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6712 :
6713 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6714 6 : CHECK(!result->BooleanValue(isolate));
6715 :
6716 12 : v8::TryCatch try_catch(isolate);
6717 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6718 6 : CHECK(try_catch.HasCaught());
6719 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6720 6 : CHECK_EQ(0,
6721 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6722 6 : }
6723 :
6724 :
6725 72 : static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6726 : char const* name) {
6727 : return v8::Local<v8::Object>::Cast(
6728 : (*context)
6729 : ->Global()
6730 288 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6731 144 : .ToLocalChecked());
6732 : }
6733 :
6734 :
6735 25881 : THREADED_TEST(DefineAPIAccessorOnObject) {
6736 6 : v8::Isolate* isolate = CcTest::isolate();
6737 6 : v8::HandleScope scope(isolate);
6738 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6739 12 : LocalContext context;
6740 :
6741 42 : CHECK(context->Global()
6742 : ->Set(context.local(), v8_str("obj1"),
6743 : templ->NewInstance(context.local()).ToLocalChecked())
6744 : .FromJust());
6745 : CompileRun("var obj2 = {};");
6746 :
6747 6 : CHECK(CompileRun("obj1.x")->IsUndefined());
6748 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6749 :
6750 30 : CHECK(GetGlobalProperty(&context, "obj1")
6751 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6752 : v8_str("donut"))
6753 : .FromJust());
6754 :
6755 6 : ExpectString("obj1.x", "x");
6756 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6757 :
6758 30 : CHECK(GetGlobalProperty(&context, "obj2")
6759 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6760 : v8_str("donut"))
6761 : .FromJust());
6762 :
6763 6 : ExpectString("obj1.x", "x");
6764 6 : ExpectString("obj2.x", "x");
6765 :
6766 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6767 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6768 :
6769 : CompileRun(
6770 : "Object.defineProperty(obj1, 'x',"
6771 : "{ get: function() { return 'y'; }, configurable: true })");
6772 :
6773 6 : ExpectString("obj1.x", "y");
6774 6 : ExpectString("obj2.x", "x");
6775 :
6776 : CompileRun(
6777 : "Object.defineProperty(obj2, 'x',"
6778 : "{ get: function() { return 'y'; }, configurable: true })");
6779 :
6780 6 : ExpectString("obj1.x", "y");
6781 6 : ExpectString("obj2.x", "y");
6782 :
6783 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6784 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6785 :
6786 30 : CHECK(GetGlobalProperty(&context, "obj1")
6787 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6788 : v8_str("donut"))
6789 : .FromJust());
6790 30 : CHECK(GetGlobalProperty(&context, "obj2")
6791 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6792 : v8_str("donut"))
6793 : .FromJust());
6794 :
6795 6 : ExpectString("obj1.x", "x");
6796 6 : ExpectString("obj2.x", "x");
6797 :
6798 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6799 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6800 :
6801 : // Define getters/setters, but now make them not configurable.
6802 : CompileRun(
6803 : "Object.defineProperty(obj1, 'x',"
6804 : "{ get: function() { return 'z'; }, configurable: false })");
6805 : CompileRun(
6806 : "Object.defineProperty(obj2, 'x',"
6807 : "{ get: function() { return 'z'; }, configurable: false })");
6808 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6809 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6810 :
6811 6 : ExpectString("obj1.x", "z");
6812 6 : ExpectString("obj2.x", "z");
6813 :
6814 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6815 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6816 : v8_str("donut"))
6817 : .FromJust());
6818 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6819 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6820 : v8_str("donut"))
6821 : .FromJust());
6822 :
6823 6 : ExpectString("obj1.x", "z");
6824 12 : ExpectString("obj2.x", "z");
6825 6 : }
6826 :
6827 :
6828 25881 : THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6829 6 : v8::Isolate* isolate = CcTest::isolate();
6830 6 : v8::HandleScope scope(isolate);
6831 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6832 12 : LocalContext context;
6833 :
6834 42 : CHECK(context->Global()
6835 : ->Set(context.local(), v8_str("obj1"),
6836 : templ->NewInstance(context.local()).ToLocalChecked())
6837 : .FromJust());
6838 : CompileRun("var obj2 = {};");
6839 :
6840 30 : CHECK(GetGlobalProperty(&context, "obj1")
6841 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6842 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6843 : .FromJust());
6844 30 : CHECK(GetGlobalProperty(&context, "obj2")
6845 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6846 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6847 : .FromJust());
6848 :
6849 6 : ExpectString("obj1.x", "x");
6850 6 : ExpectString("obj2.x", "x");
6851 :
6852 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6853 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6854 :
6855 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6856 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6857 : v8_str("donut"))
6858 : .FromJust());
6859 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6860 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6861 : v8_str("donut"))
6862 : .FromJust());
6863 :
6864 : {
6865 6 : v8::TryCatch try_catch(isolate);
6866 : CompileRun(
6867 : "Object.defineProperty(obj1, 'x',"
6868 : "{get: function() { return 'func'; }})");
6869 6 : CHECK(try_catch.HasCaught());
6870 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6871 6 : CHECK_EQ(
6872 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6873 : }
6874 : {
6875 6 : v8::TryCatch try_catch(isolate);
6876 : CompileRun(
6877 : "Object.defineProperty(obj2, 'x',"
6878 : "{get: function() { return 'func'; }})");
6879 6 : CHECK(try_catch.HasCaught());
6880 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6881 6 : CHECK_EQ(
6882 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6883 6 : }
6884 6 : }
6885 :
6886 :
6887 24 : static void Get239Value(Local<Name> name,
6888 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6889 24 : ApiTestFuzzer::Fuzz();
6890 96 : CHECK(info.Data()
6891 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6892 : .FromJust());
6893 96 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6894 : .FromJust());
6895 : info.GetReturnValue().Set(name);
6896 24 : }
6897 :
6898 :
6899 25881 : THREADED_TEST(ElementAPIAccessor) {
6900 6 : v8::Isolate* isolate = CcTest::isolate();
6901 6 : v8::HandleScope scope(isolate);
6902 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6903 12 : LocalContext context;
6904 :
6905 42 : CHECK(context->Global()
6906 : ->Set(context.local(), v8_str("obj1"),
6907 : templ->NewInstance(context.local()).ToLocalChecked())
6908 : .FromJust());
6909 : CompileRun("var obj2 = {};");
6910 :
6911 30 : CHECK(GetGlobalProperty(&context, "obj1")
6912 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6913 : v8_str("donut"))
6914 : .FromJust());
6915 30 : CHECK(GetGlobalProperty(&context, "obj2")
6916 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6917 : v8_str("donut"))
6918 : .FromJust());
6919 :
6920 6 : ExpectString("obj1[239]", "239");
6921 6 : ExpectString("obj2[239]", "239");
6922 6 : ExpectString("obj1['239']", "239");
6923 12 : ExpectString("obj2['239']", "239");
6924 6 : }
6925 :
6926 :
6927 25875 : v8::Persistent<Value> xValue;
6928 :
6929 :
6930 120 : static void SetXValue(Local<Name> name, Local<Value> value,
6931 : const v8::PropertyCallbackInfo<void>& info) {
6932 120 : Local<Context> context = info.GetIsolate()->GetCurrentContext();
6933 240 : CHECK(value->Equals(context, v8_num(4)).FromJust());
6934 360 : CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6935 360 : CHECK(name->Equals(context, v8_str("x")).FromJust());
6936 120 : CHECK(xValue.IsEmpty());
6937 : xValue.Reset(info.GetIsolate(), value);
6938 120 : }
6939 :
6940 :
6941 25881 : THREADED_TEST(SimplePropertyWrite) {
6942 6 : v8::Isolate* isolate = CcTest::isolate();
6943 6 : v8::HandleScope scope(isolate);
6944 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6945 18 : templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6946 12 : LocalContext context;
6947 36 : CHECK(context->Global()
6948 : ->Set(context.local(), v8_str("obj"),
6949 : templ->NewInstance(context.local()).ToLocalChecked())
6950 : .FromJust());
6951 : Local<Script> script = v8_compile("obj.x = 4");
6952 66 : for (int i = 0; i < 10; i++) {
6953 60 : CHECK(xValue.IsEmpty());
6954 60 : script->Run(context.local()).ToLocalChecked();
6955 240 : CHECK(v8_num(4)
6956 : ->Equals(context.local(),
6957 : Local<Value>::New(CcTest::isolate(), xValue))
6958 : .FromJust());
6959 : xValue.Reset();
6960 6 : }
6961 6 : }
6962 :
6963 :
6964 25881 : THREADED_TEST(SetterOnly) {
6965 6 : v8::Isolate* isolate = CcTest::isolate();
6966 6 : v8::HandleScope scope(isolate);
6967 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6968 18 : templ->SetAccessor(v8_str("x"), nullptr, SetXValue, v8_str("donut"));
6969 12 : LocalContext context;
6970 36 : CHECK(context->Global()
6971 : ->Set(context.local(), v8_str("obj"),
6972 : templ->NewInstance(context.local()).ToLocalChecked())
6973 : .FromJust());
6974 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
6975 66 : for (int i = 0; i < 10; i++) {
6976 60 : CHECK(xValue.IsEmpty());
6977 60 : script->Run(context.local()).ToLocalChecked();
6978 240 : CHECK(v8_num(4)
6979 : ->Equals(context.local(),
6980 : Local<Value>::New(CcTest::isolate(), xValue))
6981 : .FromJust());
6982 : xValue.Reset();
6983 6 : }
6984 6 : }
6985 :
6986 :
6987 25881 : THREADED_TEST(NoAccessors) {
6988 6 : v8::Isolate* isolate = CcTest::isolate();
6989 6 : v8::HandleScope scope(isolate);
6990 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6991 : templ->SetAccessor(v8_str("x"),
6992 : static_cast<v8::AccessorGetterCallback>(nullptr), nullptr,
6993 12 : v8_str("donut"));
6994 12 : LocalContext context;
6995 36 : CHECK(context->Global()
6996 : ->Set(context.local(), v8_str("obj"),
6997 : templ->NewInstance(context.local()).ToLocalChecked())
6998 : .FromJust());
6999 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
7000 66 : for (int i = 0; i < 10; i++) {
7001 60 : script->Run(context.local()).ToLocalChecked();
7002 6 : }
7003 6 : }
7004 :
7005 :
7006 25881 : THREADED_TEST(MultiContexts) {
7007 6 : v8::Isolate* isolate = CcTest::isolate();
7008 6 : v8::HandleScope scope(isolate);
7009 6 : v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7010 : templ->Set(v8_str("dummy"),
7011 18 : v8::FunctionTemplate::New(isolate, DummyCallHandler));
7012 :
7013 6 : Local<String> password = v8_str("Password");
7014 :
7015 : // Create an environment
7016 12 : LocalContext context0(nullptr, templ);
7017 6 : context0->SetSecurityToken(password);
7018 6 : v8::Local<v8::Object> global0 = context0->Global();
7019 18 : CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
7020 : .FromJust());
7021 24 : CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
7022 : .ToLocalChecked()
7023 : ->Int32Value(context0.local())
7024 : .FromJust());
7025 :
7026 : // Create an independent environment
7027 12 : LocalContext context1(nullptr, templ);
7028 6 : context1->SetSecurityToken(password);
7029 6 : v8::Local<v8::Object> global1 = context1->Global();
7030 18 : CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
7031 : .FromJust());
7032 12 : CHECK(!global0->Equals(context1.local(), global1).FromJust());
7033 24 : CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
7034 : .ToLocalChecked()
7035 : ->Int32Value(context0.local())
7036 : .FromJust());
7037 24 : CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
7038 : .ToLocalChecked()
7039 : ->Int32Value(context1.local())
7040 : .FromJust());
7041 :
7042 : // Now create a new context with the old global
7043 12 : LocalContext context2(nullptr, templ, global1);
7044 6 : context2->SetSecurityToken(password);
7045 6 : v8::Local<v8::Object> global2 = context2->Global();
7046 12 : CHECK(global1->Equals(context2.local(), global2).FromJust());
7047 24 : CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
7048 : .ToLocalChecked()
7049 : ->Int32Value(context1.local())
7050 : .FromJust());
7051 24 : CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
7052 : .ToLocalChecked()
7053 : ->Int32Value(context2.local())
7054 6 : .FromJust());
7055 6 : }
7056 :
7057 :
7058 25881 : THREADED_TEST(FunctionPrototypeAcrossContexts) {
7059 : // Make sure that functions created by cloning boilerplates cannot
7060 : // communicate through their __proto__ field.
7061 :
7062 6 : v8::HandleScope scope(CcTest::isolate());
7063 :
7064 12 : LocalContext env0;
7065 6 : v8::Local<v8::Object> global0 = env0->Global();
7066 18 : v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
7067 6 : .ToLocalChecked()
7068 : .As<v8::Object>();
7069 : v8::Local<v8::Object> tostring0 =
7070 18 : object0->Get(env0.local(), v8_str("toString"))
7071 6 : .ToLocalChecked()
7072 : .As<v8::Object>();
7073 : v8::Local<v8::Object> proto0 =
7074 18 : tostring0->Get(env0.local(), v8_str("__proto__"))
7075 6 : .ToLocalChecked()
7076 : .As<v8::Object>();
7077 18 : CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
7078 :
7079 12 : LocalContext env1;
7080 6 : v8::Local<v8::Object> global1 = env1->Global();
7081 18 : v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
7082 6 : .ToLocalChecked()
7083 : .As<v8::Object>();
7084 : v8::Local<v8::Object> tostring1 =
7085 18 : object1->Get(env1.local(), v8_str("toString"))
7086 6 : .ToLocalChecked()
7087 : .As<v8::Object>();
7088 : v8::Local<v8::Object> proto1 =
7089 18 : tostring1->Get(env1.local(), v8_str("__proto__"))
7090 6 : .ToLocalChecked()
7091 : .As<v8::Object>();
7092 24 : CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
7093 6 : }
7094 :
7095 :
7096 25881 : THREADED_TEST(Regress892105) {
7097 : // Make sure that object and array literals created by cloning
7098 : // boilerplates cannot communicate through their __proto__
7099 : // field. This is rather difficult to check, but we try to add stuff
7100 : // to Object.prototype and Array.prototype and create a new
7101 : // environment. This should succeed.
7102 :
7103 6 : v8::HandleScope scope(CcTest::isolate());
7104 :
7105 : Local<String> source = v8_str(
7106 : "Object.prototype.obj = 1234;"
7107 : "Array.prototype.arr = 4567;"
7108 6 : "8901");
7109 :
7110 12 : LocalContext env0;
7111 6 : Local<Script> script0 = v8_compile(source);
7112 24 : CHECK_EQ(8901.0, script0->Run(env0.local())
7113 : .ToLocalChecked()
7114 : ->NumberValue(env0.local())
7115 : .FromJust());
7116 :
7117 12 : LocalContext env1;
7118 6 : Local<Script> script1 = v8_compile(source);
7119 24 : CHECK_EQ(8901.0, script1->Run(env1.local())
7120 : .ToLocalChecked()
7121 : ->NumberValue(env1.local())
7122 6 : .FromJust());
7123 6 : }
7124 :
7125 60 : static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
7126 : args.GetReturnValue().Set(args.This());
7127 30 : }
7128 :
7129 25881 : THREADED_TEST(UndetectableObject) {
7130 6 : LocalContext env;
7131 12 : v8::HandleScope scope(env->GetIsolate());
7132 :
7133 : Local<v8::FunctionTemplate> desc =
7134 6 : v8::FunctionTemplate::New(env->GetIsolate());
7135 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7136 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7137 :
7138 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7139 6 : .ToLocalChecked()
7140 6 : ->NewInstance(env.local())
7141 : .ToLocalChecked();
7142 30 : CHECK(
7143 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7144 :
7145 6 : ExpectString("undetectable.toString()", "[object Object]");
7146 6 : ExpectString("typeof undetectable", "undefined");
7147 6 : ExpectString("typeof(undetectable)", "undefined");
7148 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
7149 6 : ExpectBoolean("typeof undetectable == 'object'", false);
7150 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7151 6 : ExpectBoolean("!undetectable", true);
7152 :
7153 6 : ExpectObject("true&&undetectable", obj);
7154 6 : ExpectBoolean("false&&undetectable", false);
7155 6 : ExpectBoolean("true||undetectable", true);
7156 6 : ExpectObject("false||undetectable", obj);
7157 :
7158 6 : ExpectObject("undetectable&&true", obj);
7159 6 : ExpectObject("undetectable&&false", obj);
7160 6 : ExpectBoolean("undetectable||true", true);
7161 6 : ExpectBoolean("undetectable||false", false);
7162 :
7163 6 : ExpectBoolean("undetectable==null", true);
7164 6 : ExpectBoolean("null==undetectable", true);
7165 6 : ExpectBoolean("undetectable==undefined", true);
7166 6 : ExpectBoolean("undefined==undetectable", true);
7167 6 : ExpectBoolean("undetectable==undetectable", true);
7168 :
7169 :
7170 6 : ExpectBoolean("undetectable===null", false);
7171 6 : ExpectBoolean("null===undetectable", false);
7172 6 : ExpectBoolean("undetectable===undefined", false);
7173 6 : ExpectBoolean("undefined===undetectable", false);
7174 12 : ExpectBoolean("undetectable===undetectable", true);
7175 6 : }
7176 :
7177 :
7178 25881 : THREADED_TEST(VoidLiteral) {
7179 6 : LocalContext env;
7180 6 : v8::Isolate* isolate = env->GetIsolate();
7181 12 : v8::HandleScope scope(isolate);
7182 :
7183 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7184 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7185 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7186 :
7187 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7188 6 : .ToLocalChecked()
7189 6 : ->NewInstance(env.local())
7190 : .ToLocalChecked();
7191 30 : CHECK(
7192 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7193 :
7194 6 : ExpectBoolean("undefined == void 0", true);
7195 6 : ExpectBoolean("undetectable == void 0", true);
7196 6 : ExpectBoolean("null == void 0", true);
7197 6 : ExpectBoolean("undefined === void 0", true);
7198 6 : ExpectBoolean("undetectable === void 0", false);
7199 6 : ExpectBoolean("null === void 0", false);
7200 :
7201 6 : ExpectBoolean("void 0 == undefined", true);
7202 6 : ExpectBoolean("void 0 == undetectable", true);
7203 6 : ExpectBoolean("void 0 == null", true);
7204 6 : ExpectBoolean("void 0 === undefined", true);
7205 6 : ExpectBoolean("void 0 === undetectable", false);
7206 6 : ExpectBoolean("void 0 === null", false);
7207 :
7208 : ExpectString(
7209 : "(function() {"
7210 : " try {"
7211 : " return x === void 0;"
7212 : " } catch(e) {"
7213 : " return e.toString();"
7214 : " }"
7215 : "})()",
7216 6 : "ReferenceError: x is not defined");
7217 : ExpectString(
7218 : "(function() {"
7219 : " try {"
7220 : " return void 0 === x;"
7221 : " } catch(e) {"
7222 : " return e.toString();"
7223 : " }"
7224 : "})()",
7225 12 : "ReferenceError: x is not defined");
7226 6 : }
7227 :
7228 :
7229 25881 : THREADED_TEST(ExtensibleOnUndetectable) {
7230 6 : LocalContext env;
7231 6 : v8::Isolate* isolate = env->GetIsolate();
7232 12 : v8::HandleScope scope(isolate);
7233 :
7234 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7235 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7236 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7237 :
7238 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7239 6 : .ToLocalChecked()
7240 6 : ->NewInstance(env.local())
7241 : .ToLocalChecked();
7242 30 : CHECK(
7243 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7244 :
7245 : Local<String> source = v8_str(
7246 : "undetectable.x = 42;"
7247 6 : "undetectable.x");
7248 :
7249 6 : Local<Script> script = v8_compile(source);
7250 :
7251 24 : CHECK(v8::Integer::New(isolate, 42)
7252 : ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7253 : .FromJust());
7254 :
7255 6 : ExpectBoolean("Object.isExtensible(undetectable)", true);
7256 :
7257 6 : source = v8_str("Object.preventExtensions(undetectable);");
7258 6 : script = v8_compile(source);
7259 6 : script->Run(env.local()).ToLocalChecked();
7260 6 : ExpectBoolean("Object.isExtensible(undetectable)", false);
7261 :
7262 6 : source = v8_str("undetectable.y = 2000;");
7263 6 : script = v8_compile(source);
7264 6 : script->Run(env.local()).ToLocalChecked();
7265 12 : ExpectBoolean("undetectable.y == undefined", true);
7266 6 : }
7267 :
7268 25881 : THREADED_TEST(ConstructCallWithUndetectable) {
7269 6 : LocalContext env;
7270 6 : v8::Isolate* isolate = env->GetIsolate();
7271 12 : v8::HandleScope scope(isolate);
7272 :
7273 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7274 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7275 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7276 :
7277 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7278 6 : .ToLocalChecked()
7279 6 : ->NewInstance(env.local())
7280 : .ToLocalChecked();
7281 30 : CHECK(
7282 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7283 :
7284 : // Undetectable object cannot be called as constructor.
7285 12 : v8::TryCatch try_catch(env->GetIsolate());
7286 6 : CHECK(CompileRun("new undetectable()").IsEmpty());
7287 6 : CHECK(try_catch.HasCaught());
7288 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
7289 6 : CHECK_EQ(0, strcmp("TypeError: undetectable is not a constructor",
7290 6 : *exception_value));
7291 6 : }
7292 :
7293 : static int increment_callback_counter = 0;
7294 :
7295 12 : static void IncrementCounterConstructCallback(
7296 36 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7297 12 : increment_callback_counter++;
7298 48 : CHECK(Local<Object>::Cast(args.NewTarget())
7299 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("counter"),
7300 : v8_num(increment_callback_counter))
7301 : .FromJust());
7302 : args.GetReturnValue().Set(args.NewTarget());
7303 12 : }
7304 :
7305 25881 : THREADED_TEST(SetCallAsFunctionHandlerConstructor) {
7306 6 : LocalContext env;
7307 6 : v8::Isolate* isolate = env->GetIsolate();
7308 12 : v8::HandleScope scope(isolate);
7309 :
7310 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7311 : desc->InstanceTemplate()->SetCallAsFunctionHandler(
7312 12 : IncrementCounterConstructCallback); // callable
7313 :
7314 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7315 6 : .ToLocalChecked()
7316 6 : ->NewInstance(env.local())
7317 : .ToLocalChecked();
7318 30 : CHECK(env->Global()->Set(env.local(), v8_str("Counter"), obj).FromJust());
7319 :
7320 6 : ExpectInt32("(new Counter()).counter", 1);
7321 6 : CHECK_EQ(1, increment_callback_counter);
7322 6 : ExpectInt32("(new Counter()).counter", 2);
7323 12 : CHECK_EQ(2, increment_callback_counter);
7324 6 : }
7325 : // The point of this test is type checking. We run it only so compilers
7326 : // don't complain about an unused function.
7327 25880 : TEST(PersistentHandles) {
7328 5 : LocalContext env;
7329 5 : v8::Isolate* isolate = CcTest::isolate();
7330 10 : v8::HandleScope scope(isolate);
7331 5 : Local<String> str = v8_str("foo");
7332 : v8::Persistent<String> p_str(isolate, str);
7333 : p_str.Reset();
7334 : Local<Script> scr = v8_compile("");
7335 : v8::Persistent<Script> p_scr(isolate, scr);
7336 : p_scr.Reset();
7337 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7338 : v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7339 5 : p_templ.Reset();
7340 5 : }
7341 :
7342 :
7343 6 : static void HandleLogDelegator(
7344 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7345 6 : ApiTestFuzzer::Fuzz();
7346 6 : }
7347 :
7348 :
7349 25881 : THREADED_TEST(GlobalObjectTemplate) {
7350 6 : v8::Isolate* isolate = CcTest::isolate();
7351 6 : v8::HandleScope handle_scope(isolate);
7352 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7353 : global_template->Set(v8_str("JSNI_Log"),
7354 18 : v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7355 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
7356 : Context::Scope context_scope(context);
7357 6 : CompileRun("JSNI_Log('LOG')");
7358 6 : }
7359 :
7360 :
7361 : static const char* kSimpleExtensionSource =
7362 : "function Foo() {"
7363 : " return 4;"
7364 : "}";
7365 :
7366 :
7367 25880 : TEST(SimpleExtensions) {
7368 5 : v8::HandleScope handle_scope(CcTest::isolate());
7369 : v8::RegisterExtension(
7370 10 : v8::base::make_unique<Extension>("simpletest", kSimpleExtensionSource));
7371 5 : const char* extension_names[] = {"simpletest"};
7372 : v8::ExtensionConfiguration extensions(1, extension_names);
7373 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7374 : Context::Scope lock(context);
7375 : v8::Local<Value> result = CompileRun("Foo()");
7376 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7377 5 : .FromJust());
7378 5 : }
7379 :
7380 :
7381 : static const char* kStackTraceFromExtensionSource =
7382 : "function foo() {"
7383 : " throw new Error();"
7384 : "}"
7385 : "function bar() {"
7386 : " foo();"
7387 : "}";
7388 :
7389 :
7390 25880 : TEST(StackTraceInExtension) {
7391 5 : v8::HandleScope handle_scope(CcTest::isolate());
7392 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7393 10 : "stacktracetest", kStackTraceFromExtensionSource));
7394 5 : const char* extension_names[] = {"stacktracetest"};
7395 : v8::ExtensionConfiguration extensions(1, extension_names);
7396 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7397 : Context::Scope lock(context);
7398 : CompileRun(
7399 : "function user() { bar(); }"
7400 : "var error;"
7401 : "try{ user(); } catch (e) { error = e; }");
7402 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7403 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7404 10 : CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7405 5 : }
7406 :
7407 :
7408 25880 : TEST(NullExtensions) {
7409 5 : v8::HandleScope handle_scope(CcTest::isolate());
7410 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("nulltest", nullptr));
7411 5 : const char* extension_names[] = {"nulltest"};
7412 : v8::ExtensionConfiguration extensions(1, extension_names);
7413 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7414 : Context::Scope lock(context);
7415 : v8::Local<Value> result = CompileRun("1+3");
7416 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7417 5 : .FromJust());
7418 5 : }
7419 :
7420 : static const char* kEmbeddedExtensionSource =
7421 : "function Ret54321(){return 54321;}~~@@$"
7422 : "$%% THIS IS A SERIES OF NON-nullptr-TERMINATED STRINGS.";
7423 : static const int kEmbeddedExtensionSourceValidLen = 34;
7424 :
7425 :
7426 25880 : TEST(ExtensionMissingSourceLength) {
7427 5 : v8::HandleScope handle_scope(CcTest::isolate());
7428 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7429 10 : "srclentest_fail", kEmbeddedExtensionSource));
7430 5 : const char* extension_names[] = {"srclentest_fail"};
7431 : v8::ExtensionConfiguration extensions(1, extension_names);
7432 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7433 5 : CHECK_NULL(*context);
7434 5 : }
7435 :
7436 :
7437 25880 : TEST(ExtensionWithSourceLength) {
7438 40 : for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7439 20 : source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7440 15 : v8::HandleScope handle_scope(CcTest::isolate());
7441 : i::ScopedVector<char> extension_name(32);
7442 15 : i::SNPrintF(extension_name, "ext #%d", source_len);
7443 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7444 : extension_name.start(), kEmbeddedExtensionSource, 0, nullptr,
7445 30 : source_len));
7446 15 : const char* extension_names[1] = {extension_name.start()};
7447 : v8::ExtensionConfiguration extensions(1, extension_names);
7448 15 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7449 15 : if (source_len == kEmbeddedExtensionSourceValidLen) {
7450 : Context::Scope lock(context);
7451 5 : v8::Local<Value> result = CompileRun("Ret54321()");
7452 15 : CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7453 : ->Equals(context, result)
7454 : .FromJust());
7455 : } else {
7456 : // Anything but exactly the right length should fail to compile.
7457 10 : CHECK_NULL(*context);
7458 : }
7459 15 : }
7460 5 : }
7461 :
7462 :
7463 : static const char* kEvalExtensionSource1 =
7464 : "function UseEval1() {"
7465 : " var x = 42;"
7466 : " return eval('x');"
7467 : "}";
7468 :
7469 :
7470 : static const char* kEvalExtensionSource2 =
7471 : "(function() {"
7472 : " var x = 42;"
7473 : " function e() {"
7474 : " return eval('x');"
7475 : " }"
7476 : " this.UseEval2 = e;"
7477 : "})()";
7478 :
7479 :
7480 25880 : TEST(UseEvalFromExtension) {
7481 5 : v8::HandleScope handle_scope(CcTest::isolate());
7482 : v8::RegisterExtension(
7483 10 : v8::base::make_unique<Extension>("evaltest1", kEvalExtensionSource1));
7484 : v8::RegisterExtension(
7485 10 : v8::base::make_unique<Extension>("evaltest2", kEvalExtensionSource2));
7486 5 : const char* extension_names[] = {"evaltest1", "evaltest2"};
7487 : v8::ExtensionConfiguration extensions(2, extension_names);
7488 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7489 : Context::Scope lock(context);
7490 : v8::Local<Value> result = CompileRun("UseEval1()");
7491 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7492 : .FromJust());
7493 : result = CompileRun("UseEval2()");
7494 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7495 5 : .FromJust());
7496 5 : }
7497 :
7498 :
7499 : static const char* kWithExtensionSource1 =
7500 : "function UseWith1() {"
7501 : " var x = 42;"
7502 : " with({x:87}) { return x; }"
7503 : "}";
7504 :
7505 :
7506 : static const char* kWithExtensionSource2 =
7507 : "(function() {"
7508 : " var x = 42;"
7509 : " function e() {"
7510 : " with ({x:87}) { return x; }"
7511 : " }"
7512 : " this.UseWith2 = e;"
7513 : "})()";
7514 :
7515 :
7516 25880 : TEST(UseWithFromExtension) {
7517 5 : v8::HandleScope handle_scope(CcTest::isolate());
7518 : v8::RegisterExtension(
7519 10 : v8::base::make_unique<Extension>("withtest1", kWithExtensionSource1));
7520 : v8::RegisterExtension(
7521 10 : v8::base::make_unique<Extension>("withtest2", kWithExtensionSource2));
7522 5 : const char* extension_names[] = {"withtest1", "withtest2"};
7523 : v8::ExtensionConfiguration extensions(2, extension_names);
7524 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7525 : Context::Scope lock(context);
7526 : v8::Local<Value> result = CompileRun("UseWith1()");
7527 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7528 : .FromJust());
7529 : result = CompileRun("UseWith2()");
7530 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7531 5 : .FromJust());
7532 5 : }
7533 :
7534 :
7535 25880 : TEST(AutoExtensions) {
7536 5 : v8::HandleScope handle_scope(CcTest::isolate());
7537 : auto extension =
7538 5 : v8::base::make_unique<Extension>("autotest", kSimpleExtensionSource);
7539 : extension->set_auto_enable(true);
7540 10 : v8::RegisterExtension(std::move(extension));
7541 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
7542 : Context::Scope lock(context);
7543 : v8::Local<Value> result = CompileRun("Foo()");
7544 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7545 5 : .FromJust());
7546 5 : }
7547 :
7548 :
7549 : static const char* kSyntaxErrorInExtensionSource = "[";
7550 :
7551 :
7552 : // Test that a syntax error in an extension does not cause a fatal
7553 : // error but results in an empty context.
7554 25880 : TEST(SyntaxErrorExtensions) {
7555 5 : v8::HandleScope handle_scope(CcTest::isolate());
7556 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7557 10 : "syntaxerror", kSyntaxErrorInExtensionSource));
7558 5 : const char* extension_names[] = {"syntaxerror"};
7559 : v8::ExtensionConfiguration extensions(1, extension_names);
7560 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7561 5 : CHECK(context.IsEmpty());
7562 5 : }
7563 :
7564 :
7565 : static const char* kExceptionInExtensionSource = "throw 42";
7566 :
7567 :
7568 : // Test that an exception when installing an extension does not cause
7569 : // a fatal error but results in an empty context.
7570 25880 : TEST(ExceptionExtensions) {
7571 5 : v8::HandleScope handle_scope(CcTest::isolate());
7572 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7573 10 : "exception", kExceptionInExtensionSource));
7574 5 : const char* extension_names[] = {"exception"};
7575 : v8::ExtensionConfiguration extensions(1, extension_names);
7576 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7577 5 : CHECK(context.IsEmpty());
7578 5 : }
7579 :
7580 : static const char* kNativeCallInExtensionSource =
7581 : "function call_runtime_last_index_of(x) {"
7582 : " return %StringLastIndexOf(x, 'bob');"
7583 : "}";
7584 :
7585 : static const char* kNativeCallTest =
7586 : "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7587 :
7588 : // Test that a native runtime calls are supported in extensions.
7589 25880 : TEST(NativeCallInExtensions) {
7590 5 : v8::HandleScope handle_scope(CcTest::isolate());
7591 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7592 10 : "nativecall", kNativeCallInExtensionSource));
7593 5 : const char* extension_names[] = {"nativecall"};
7594 : v8::ExtensionConfiguration extensions(1, extension_names);
7595 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7596 : Context::Scope lock(context);
7597 5 : v8::Local<Value> result = CompileRun(kNativeCallTest);
7598 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24))
7599 5 : .FromJust());
7600 5 : }
7601 :
7602 :
7603 30 : class NativeFunctionExtension : public Extension {
7604 : public:
7605 : NativeFunctionExtension(const char* name, const char* source,
7606 : v8::FunctionCallback fun = &Echo)
7607 15 : : Extension(name, source), function_(fun) {}
7608 :
7609 5 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7610 : v8::Isolate* isolate, v8::Local<v8::String> name) override {
7611 5 : return v8::FunctionTemplate::New(isolate, function_);
7612 : }
7613 :
7614 10 : static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7615 5 : if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7616 5 : }
7617 :
7618 : private:
7619 : v8::FunctionCallback function_;
7620 : };
7621 :
7622 :
7623 25880 : TEST(NativeFunctionDeclaration) {
7624 5 : v8::HandleScope handle_scope(CcTest::isolate());
7625 5 : const char* name = "nativedecl";
7626 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7627 20 : name, "native function foo();"));
7628 5 : const char* extension_names[] = {name};
7629 : v8::ExtensionConfiguration extensions(1, extension_names);
7630 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7631 : Context::Scope lock(context);
7632 : v8::Local<Value> result = CompileRun("foo(42);");
7633 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7634 5 : .FromJust());
7635 5 : }
7636 :
7637 :
7638 25880 : TEST(NativeFunctionDeclarationError) {
7639 5 : v8::HandleScope handle_scope(CcTest::isolate());
7640 5 : const char* name = "nativedeclerr";
7641 : // Syntax error in extension code.
7642 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7643 20 : name, "native\nfunction foo();"));
7644 5 : const char* extension_names[] = {name};
7645 : v8::ExtensionConfiguration extensions(1, extension_names);
7646 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7647 5 : CHECK(context.IsEmpty());
7648 5 : }
7649 :
7650 :
7651 25880 : TEST(NativeFunctionDeclarationErrorEscape) {
7652 5 : v8::HandleScope handle_scope(CcTest::isolate());
7653 5 : const char* name = "nativedeclerresc";
7654 : // Syntax error in extension code - escape code in "native" means that
7655 : // it's not treated as a keyword.
7656 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7657 20 : name, "nativ\\u0065 function foo();"));
7658 5 : const char* extension_names[] = {name};
7659 : v8::ExtensionConfiguration extensions(1, extension_names);
7660 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7661 5 : CHECK(context.IsEmpty());
7662 5 : }
7663 :
7664 :
7665 30 : static void CheckDependencies(const char* name, const char* expected) {
7666 30 : v8::HandleScope handle_scope(CcTest::isolate());
7667 : v8::ExtensionConfiguration config(1, &name);
7668 60 : LocalContext context(&config);
7669 210 : CHECK(
7670 : v8_str(expected)
7671 : ->Equals(context.local(), context->Global()
7672 : ->Get(context.local(), v8_str("loaded"))
7673 : .ToLocalChecked())
7674 30 : .FromJust());
7675 30 : }
7676 :
7677 :
7678 : /*
7679 : * Configuration:
7680 : *
7681 : * /-- B <--\
7682 : * A <- -- D <-- E
7683 : * \-- C <--/
7684 : */
7685 25881 : THREADED_TEST(ExtensionDependency) {
7686 : static const char* kEDeps[] = {"D"};
7687 : v8::RegisterExtension(
7688 12 : v8::base::make_unique<Extension>("E", "this.loaded += 'E';", 1, kEDeps));
7689 : static const char* kDDeps[] = {"B", "C"};
7690 : v8::RegisterExtension(
7691 12 : v8::base::make_unique<Extension>("D", "this.loaded += 'D';", 2, kDDeps));
7692 : static const char* kBCDeps[] = {"A"};
7693 : v8::RegisterExtension(
7694 12 : v8::base::make_unique<Extension>("B", "this.loaded += 'B';", 1, kBCDeps));
7695 : v8::RegisterExtension(
7696 12 : v8::base::make_unique<Extension>("C", "this.loaded += 'C';", 1, kBCDeps));
7697 : v8::RegisterExtension(
7698 12 : v8::base::make_unique<Extension>("A", "this.loaded += 'A';"));
7699 6 : CheckDependencies("A", "undefinedA");
7700 6 : CheckDependencies("B", "undefinedAB");
7701 6 : CheckDependencies("C", "undefinedAC");
7702 6 : CheckDependencies("D", "undefinedABCD");
7703 6 : CheckDependencies("E", "undefinedABCDE");
7704 6 : v8::HandleScope handle_scope(CcTest::isolate());
7705 : static const char* exts[2] = {"C", "E"};
7706 : v8::ExtensionConfiguration config(2, exts);
7707 12 : LocalContext context(&config);
7708 42 : CHECK(
7709 : v8_str("undefinedACBDE")
7710 : ->Equals(context.local(), context->Global()
7711 : ->Get(context.local(), v8_str("loaded"))
7712 : .ToLocalChecked())
7713 6 : .FromJust());
7714 6 : }
7715 :
7716 :
7717 : static const char* kExtensionTestScript =
7718 : "native function A();"
7719 : "native function B();"
7720 : "native function C();"
7721 : "function Foo(i) {"
7722 : " if (i == 0) return A();"
7723 : " if (i == 1) return B();"
7724 : " if (i == 2) return C();"
7725 : "}";
7726 :
7727 :
7728 738 : static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7729 198 : ApiTestFuzzer::Fuzz();
7730 198 : if (args.IsConstructCall()) {
7731 720 : CHECK(args.This()
7732 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7733 : args.Data())
7734 : .FromJust());
7735 : args.GetReturnValue().SetNull();
7736 378 : return;
7737 : }
7738 : args.GetReturnValue().Set(args.Data());
7739 : }
7740 :
7741 :
7742 24 : class FunctionExtension : public Extension {
7743 : public:
7744 12 : FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7745 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7746 : v8::Isolate* isolate, v8::Local<String> name) override;
7747 : };
7748 :
7749 :
7750 : static int lookup_count = 0;
7751 33 : v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7752 : v8::Isolate* isolate, v8::Local<String> name) {
7753 33 : lookup_count++;
7754 66 : if (name->StrictEquals(v8_str("A"))) {
7755 : return v8::FunctionTemplate::New(isolate, CallFun,
7756 22 : v8::Integer::New(isolate, 8));
7757 44 : } else if (name->StrictEquals(v8_str("B"))) {
7758 : return v8::FunctionTemplate::New(isolate, CallFun,
7759 22 : v8::Integer::New(isolate, 7));
7760 22 : } else if (name->StrictEquals(v8_str("C"))) {
7761 : return v8::FunctionTemplate::New(isolate, CallFun,
7762 22 : v8::Integer::New(isolate, 6));
7763 : } else {
7764 0 : return v8::Local<v8::FunctionTemplate>();
7765 : }
7766 : }
7767 :
7768 :
7769 25881 : THREADED_TEST(FunctionLookup) {
7770 24 : v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7771 6 : v8::HandleScope handle_scope(CcTest::isolate());
7772 : static const char* exts[1] = {"functiontest"};
7773 : v8::ExtensionConfiguration config(1, exts);
7774 12 : LocalContext context(&config);
7775 6 : CHECK_EQ(3, lookup_count);
7776 18 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7777 : ->Equals(context.local(), CompileRun("Foo(0)"))
7778 : .FromJust());
7779 18 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7780 : ->Equals(context.local(), CompileRun("Foo(1)"))
7781 : .FromJust());
7782 18 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7783 : ->Equals(context.local(), CompileRun("Foo(2)"))
7784 6 : .FromJust());
7785 6 : }
7786 :
7787 :
7788 25881 : THREADED_TEST(NativeFunctionConstructCall) {
7789 24 : v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7790 6 : v8::HandleScope handle_scope(CcTest::isolate());
7791 : static const char* exts[1] = {"functiontest"};
7792 : v8::ExtensionConfiguration config(1, exts);
7793 12 : LocalContext context(&config);
7794 66 : for (int i = 0; i < 10; i++) {
7795 : // Run a few times to ensure that allocation of objects doesn't
7796 : // change behavior of a constructor function.
7797 180 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7798 : ->Equals(context.local(), CompileRun("(new A()).data"))
7799 : .FromJust());
7800 180 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7801 : ->Equals(context.local(), CompileRun("(new B()).data"))
7802 : .FromJust());
7803 180 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7804 : ->Equals(context.local(), CompileRun("(new C()).data"))
7805 : .FromJust());
7806 6 : }
7807 6 : }
7808 :
7809 :
7810 : static const char* last_location;
7811 : static const char* last_message;
7812 10 : void StoringErrorCallback(const char* location, const char* message) {
7813 10 : if (last_location == nullptr) {
7814 10 : last_location = location;
7815 10 : last_message = message;
7816 : }
7817 10 : }
7818 :
7819 :
7820 : // ErrorReporting creates a circular extensions configuration and
7821 : // tests that the fatal error handler gets called. This renders V8
7822 : // unusable and therefore this test cannot be run in parallel.
7823 25880 : TEST(ErrorReporting) {
7824 5 : CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7825 : static const char* aDeps[] = {"B"};
7826 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("A", "", 1, aDeps));
7827 : static const char* bDeps[] = {"A"};
7828 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("B", "", 1, bDeps));
7829 5 : last_location = nullptr;
7830 : v8::ExtensionConfiguration config(1, bDeps);
7831 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7832 5 : CHECK(context.IsEmpty());
7833 5 : CHECK(last_location);
7834 5 : }
7835 :
7836 : static size_t dcheck_count;
7837 0 : void DcheckErrorCallback(const char* file, int line, const char* message) {
7838 0 : last_message = message;
7839 0 : ++dcheck_count;
7840 0 : }
7841 :
7842 25880 : TEST(DcheckErrorHandler) {
7843 5 : V8::SetDcheckErrorHandler(DcheckErrorCallback);
7844 :
7845 5 : last_message = nullptr;
7846 5 : dcheck_count = 0;
7847 :
7848 : DCHECK(false && "w00t");
7849 : #ifdef DEBUG
7850 : CHECK_EQ(dcheck_count, 1);
7851 : CHECK(last_message);
7852 : CHECK(std::string(last_message).find("w00t") != std::string::npos);
7853 : #else
7854 : // The DCHECK should be a noop in non-DEBUG builds.
7855 5 : CHECK_EQ(dcheck_count, 0);
7856 : #endif
7857 5 : }
7858 :
7859 6 : static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7860 : v8::Local<Value> data) {
7861 6 : v8::Isolate* isolate = CcTest::isolate();
7862 6 : Local<Context> context = isolate->GetCurrentContext();
7863 12 : CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7864 18 : CHECK(v8::Undefined(isolate)
7865 : ->Equals(context, message->GetScriptOrigin().ResourceName())
7866 : .FromJust());
7867 12 : message->GetLineNumber(context).FromJust();
7868 6 : message->GetSourceLine(context).ToLocalChecked();
7869 6 : }
7870 :
7871 :
7872 25881 : THREADED_TEST(ErrorWithMissingScriptInfo) {
7873 6 : LocalContext context;
7874 12 : v8::HandleScope scope(context->GetIsolate());
7875 6 : context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7876 : CompileRun("throw Error()");
7877 : context->GetIsolate()->RemoveMessageListeners(
7878 12 : MissingScriptInfoMessageListener);
7879 6 : }
7880 :
7881 :
7882 : struct FlagAndPersistent {
7883 : bool flag;
7884 : v8::Global<v8::Object> handle;
7885 : };
7886 :
7887 80 : static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7888 40 : data.GetParameter()->flag = true;
7889 : data.GetParameter()->handle.Reset();
7890 40 : }
7891 :
7892 20 : static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7893 20 : i::FLAG_stress_incremental_marking = false;
7894 : // Parallel scavenge introduces too much fragmentation.
7895 20 : i::FLAG_parallel_scavenge = false;
7896 20 : v8::Isolate* iso = CcTest::isolate();
7897 20 : v8::HandleScope scope(iso);
7898 20 : v8::Local<Context> context = Context::New(iso);
7899 : Context::Scope context_scope(context);
7900 :
7901 : FlagAndPersistent object_a, object_b;
7902 :
7903 : size_t big_heap_size = 0;
7904 : size_t big_array_size = 0;
7905 :
7906 : {
7907 20 : v8::HandleScope handle_scope(iso);
7908 20 : Local<Object> a(v8::Object::New(iso));
7909 20 : Local<Object> b(v8::Object::New(iso));
7910 : object_a.handle.Reset(iso, a);
7911 : object_b.handle.Reset(iso, b);
7912 20 : if (interlinked) {
7913 30 : a->Set(context, v8_str("x"), b).FromJust();
7914 30 : b->Set(context, v8_str("x"), a).FromJust();
7915 : }
7916 20 : if (global_gc) {
7917 10 : CcTest::CollectAllGarbage();
7918 : } else {
7919 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7920 : }
7921 20 : v8::Local<Value> big_array = v8::Array::New(CcTest::isolate(), 5000);
7922 : // Verify that we created an array where the space was reserved up front.
7923 : big_array_size =
7924 : v8::internal::JSArray::cast(*v8::Utils::OpenHandle(*big_array))
7925 40 : ->elements()
7926 20 : ->Size();
7927 20 : CHECK_LE(20000, big_array_size);
7928 60 : a->Set(context, v8_str("y"), big_array).FromJust();
7929 20 : big_heap_size = CcTest::heap()->SizeOfObjects();
7930 : }
7931 :
7932 20 : object_a.flag = false;
7933 20 : object_b.flag = false;
7934 : object_a.handle.SetWeak(&object_a, &SetFlag,
7935 : v8::WeakCallbackType::kParameter);
7936 : object_b.handle.SetWeak(&object_b, &SetFlag,
7937 : v8::WeakCallbackType::kParameter);
7938 : #if __clang__
7939 : #pragma clang diagnostic push
7940 : #pragma clang diagnostic ignored "-Wdeprecated"
7941 : #endif
7942 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
7943 20 : CHECK(!object_b.handle.IsIndependent());
7944 : object_a.handle.MarkIndependent();
7945 : object_b.handle.MarkIndependent();
7946 20 : CHECK(object_b.handle.IsIndependent());
7947 : #if __clang__
7948 : #pragma clang diagnostic pop
7949 : #endif
7950 20 : if (global_gc) {
7951 10 : CcTest::CollectAllGarbage();
7952 : } else {
7953 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7954 : }
7955 : // A single GC should be enough to reclaim the memory, since we are using
7956 : // phantom handles.
7957 20 : CHECK_GT(big_heap_size - big_array_size, CcTest::heap()->SizeOfObjects());
7958 20 : CHECK(object_a.flag);
7959 40 : CHECK(object_b.flag);
7960 20 : }
7961 :
7962 25880 : TEST(IndependentWeakHandle) {
7963 5 : IndependentWeakHandle(false, false);
7964 5 : IndependentWeakHandle(false, true);
7965 5 : IndependentWeakHandle(true, false);
7966 5 : IndependentWeakHandle(true, true);
7967 5 : }
7968 :
7969 : class Trivial {
7970 : public:
7971 12 : explicit Trivial(int x) : x_(x) {}
7972 :
7973 36 : int x() { return x_; }
7974 12 : void set_x(int x) { x_ = x; }
7975 :
7976 : private:
7977 : int x_;
7978 : };
7979 :
7980 :
7981 : class Trivial2 {
7982 : public:
7983 12 : Trivial2(int x, int y) : y_(y), x_(x) {}
7984 :
7985 : int x() { return x_; }
7986 12 : void set_x(int x) { x_ = x; }
7987 :
7988 : int y() { return y_; }
7989 : void set_y(int y) { y_ = y; }
7990 :
7991 : private:
7992 : int y_;
7993 : int x_;
7994 : };
7995 :
7996 12 : void CheckInternalFields(
7997 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
7998 : v8::Persistent<v8::Object>* handle = data.GetParameter();
7999 : handle->Reset();
8000 : Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
8001 12 : Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
8002 12 : CHECK_EQ(42, t1->x());
8003 12 : CHECK_EQ(103, t2->x());
8004 : t1->set_x(1729);
8005 : t2->set_x(33550336);
8006 12 : }
8007 :
8008 12 : void InternalFieldCallback(bool global_gc) {
8009 12 : LocalContext env;
8010 12 : v8::Isolate* isolate = env->GetIsolate();
8011 24 : v8::HandleScope scope(isolate);
8012 :
8013 12 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
8014 12 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
8015 : Trivial* t1;
8016 24 : Trivial2* t2;
8017 12 : instance_templ->SetInternalFieldCount(2);
8018 : v8::Persistent<v8::Object> handle;
8019 : {
8020 12 : v8::HandleScope scope(isolate);
8021 12 : Local<v8::Object> obj = templ->GetFunction(env.local())
8022 12 : .ToLocalChecked()
8023 12 : ->NewInstance(env.local())
8024 : .ToLocalChecked();
8025 : handle.Reset(isolate, obj);
8026 12 : CHECK_EQ(2, obj->InternalFieldCount());
8027 12 : CHECK(obj->GetInternalField(0)->IsUndefined());
8028 12 : t1 = new Trivial(42);
8029 12 : t2 = new Trivial2(103, 9);
8030 :
8031 12 : obj->SetAlignedPointerInInternalField(0, t1);
8032 : t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
8033 12 : CHECK_EQ(42, t1->x());
8034 :
8035 12 : obj->SetAlignedPointerInInternalField(1, t2);
8036 : t2 =
8037 : reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
8038 12 : CHECK_EQ(103, t2->x());
8039 :
8040 : handle.SetWeak<v8::Persistent<v8::Object>>(
8041 12 : &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
8042 : }
8043 12 : if (global_gc) {
8044 6 : CcTest::CollectAllGarbage();
8045 : } else {
8046 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8047 : }
8048 :
8049 12 : CHECK_EQ(1729, t1->x());
8050 12 : CHECK_EQ(33550336, t2->x());
8051 :
8052 12 : delete t1;
8053 24 : delete t2;
8054 12 : }
8055 :
8056 25881 : THREADED_TEST(InternalFieldCallback) {
8057 6 : InternalFieldCallback(false);
8058 6 : InternalFieldCallback(true);
8059 6 : }
8060 :
8061 24 : static void ResetUseValueAndSetFlag(
8062 48 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8063 : // Blink will reset the handle, and then use the other handle, so they
8064 : // can't use the same backing slot.
8065 : data.GetParameter()->handle.Reset();
8066 24 : data.GetParameter()->flag = true;
8067 24 : }
8068 :
8069 12 : void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) {
8070 : using v8::Context;
8071 : using v8::Local;
8072 : using v8::Object;
8073 :
8074 12 : v8::Isolate* iso = CcTest::isolate();
8075 12 : v8::HandleScope scope(iso);
8076 12 : v8::Local<Context> context = Context::New(iso);
8077 : Context::Scope context_scope(context);
8078 :
8079 : FlagAndPersistent object_a, object_b;
8080 :
8081 : {
8082 12 : v8::HandleScope handle_scope(iso);
8083 12 : Local<Object> a(v8::Object::New(iso));
8084 12 : Local<Object> b(v8::Object::New(iso));
8085 : object_a.handle.Reset(iso, a);
8086 : object_b.handle.Reset(iso, b);
8087 12 : if (global_gc) {
8088 6 : CcTest::PreciseCollectAllGarbage();
8089 : } else {
8090 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8091 12 : }
8092 : }
8093 :
8094 12 : object_a.flag = false;
8095 12 : object_b.flag = false;
8096 : object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
8097 : v8::WeakCallbackType::kParameter);
8098 : object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
8099 : v8::WeakCallbackType::kParameter);
8100 12 : if (!global_gc) {
8101 : #if __clang__
8102 : #pragma clang diagnostic push
8103 : #pragma clang diagnostic ignored "-Wdeprecated"
8104 : #endif
8105 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
8106 : object_a.handle.MarkIndependent();
8107 : object_b.handle.MarkIndependent();
8108 6 : CHECK(object_b.handle.IsIndependent());
8109 : #if __clang__
8110 : #pragma clang diagnostic pop
8111 : #endif
8112 : }
8113 12 : if (global_gc) {
8114 6 : CcTest::PreciseCollectAllGarbage();
8115 : } else {
8116 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8117 : }
8118 12 : CHECK(object_a.flag);
8119 24 : CHECK(object_b.flag);
8120 12 : }
8121 :
8122 25881 : THREADED_HEAP_TEST(ResetWeakHandle) {
8123 6 : v8::internal::heap::HeapTester::ResetWeakHandle(false);
8124 6 : v8::internal::heap::HeapTester::ResetWeakHandle(true);
8125 6 : }
8126 :
8127 24 : static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
8128 :
8129 24 : static void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
8130 :
8131 12 : static void ForceScavenge2(
8132 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8133 12 : data.GetParameter()->flag = true;
8134 : InvokeScavenge();
8135 12 : }
8136 :
8137 12 : static void ForceScavenge1(
8138 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8139 : data.GetParameter()->handle.Reset();
8140 : data.SetSecondPassCallback(ForceScavenge2);
8141 12 : }
8142 :
8143 12 : static void ForceMarkSweep2(
8144 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8145 12 : data.GetParameter()->flag = true;
8146 : InvokeMarkSweep();
8147 12 : }
8148 :
8149 12 : static void ForceMarkSweep1(
8150 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8151 : data.GetParameter()->handle.Reset();
8152 : data.SetSecondPassCallback(ForceMarkSweep2);
8153 12 : }
8154 :
8155 25881 : THREADED_TEST(GCFromWeakCallbacks) {
8156 6 : v8::Isolate* isolate = CcTest::isolate();
8157 6 : v8::Locker locker(CcTest::isolate());
8158 12 : v8::HandleScope scope(isolate);
8159 6 : v8::Local<Context> context = Context::New(isolate);
8160 : Context::Scope context_scope(context);
8161 :
8162 : static const int kNumberOfGCTypes = 2;
8163 : typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
8164 : Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
8165 6 : &ForceMarkSweep1};
8166 :
8167 : typedef void (*GCInvoker)();
8168 6 : GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
8169 :
8170 18 : for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
8171 24 : for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
8172 : FlagAndPersistent object;
8173 : {
8174 24 : v8::HandleScope handle_scope(isolate);
8175 48 : object.handle.Reset(isolate, v8::Object::New(isolate));
8176 : }
8177 24 : object.flag = false;
8178 : object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
8179 24 : v8::WeakCallbackType::kParameter);
8180 : #if __clang__
8181 : #pragma clang diagnostic push
8182 : #pragma clang diagnostic ignored "-Wdeprecated"
8183 : #endif
8184 : // MarkIndependent is marked deprecated but we still rely on it
8185 : // temporarily.
8186 : object.handle.MarkIndependent();
8187 : #if __clang__
8188 : #pragma clang diagnostic pop
8189 : #endif
8190 24 : invoke_gc[outer_gc]();
8191 24 : EmptyMessageQueues(isolate);
8192 24 : CHECK(object.flag);
8193 : }
8194 6 : }
8195 6 : }
8196 :
8197 : v8::Local<Function> args_fun;
8198 :
8199 :
8200 6 : static void ArgumentsTestCallback(
8201 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
8202 6 : ApiTestFuzzer::Fuzz();
8203 : v8::Isolate* isolate = args.GetIsolate();
8204 6 : Local<Context> context = isolate->GetCurrentContext();
8205 6 : CHECK_EQ(3, args.Length());
8206 18 : CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
8207 18 : CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
8208 18 : CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
8209 12 : CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
8210 6 : v8::HandleScope scope(args.GetIsolate());
8211 6 : CcTest::CollectAllGarbage();
8212 6 : }
8213 :
8214 :
8215 25881 : THREADED_TEST(Arguments) {
8216 6 : v8::Isolate* isolate = CcTest::isolate();
8217 6 : v8::HandleScope scope(isolate);
8218 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8219 : global->Set(v8_str("f"),
8220 18 : v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8221 12 : LocalContext context(nullptr, global);
8222 : args_fun = context->Global()
8223 24 : ->Get(context.local(), v8_str("f"))
8224 6 : .ToLocalChecked()
8225 6 : .As<Function>();
8226 18 : v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
8227 6 : }
8228 :
8229 :
8230 : static int p_getter_count;
8231 : static int p_getter_count2;
8232 :
8233 :
8234 240 : static void PGetter(Local<Name> name,
8235 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8236 240 : ApiTestFuzzer::Fuzz();
8237 240 : p_getter_count++;
8238 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8239 240 : v8::Local<v8::Object> global = context->Global();
8240 960 : CHECK(
8241 : info.Holder()
8242 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8243 : .FromJust());
8244 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8245 240 : CHECK(info.This()
8246 : ->Equals(context,
8247 : global->Get(context, v8_str("o1")).ToLocalChecked())
8248 : .FromJust());
8249 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8250 240 : CHECK(info.This()
8251 : ->Equals(context,
8252 : global->Get(context, v8_str("o2")).ToLocalChecked())
8253 : .FromJust());
8254 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8255 240 : CHECK(info.This()
8256 : ->Equals(context,
8257 : global->Get(context, v8_str("o3")).ToLocalChecked())
8258 : .FromJust());
8259 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8260 240 : CHECK(info.This()
8261 : ->Equals(context,
8262 : global->Get(context, v8_str("o4")).ToLocalChecked())
8263 : .FromJust());
8264 : }
8265 240 : }
8266 :
8267 :
8268 12 : static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8269 12 : ApiTestFuzzer::Fuzz();
8270 12 : LocalContext context;
8271 84 : CHECK(context->Global()
8272 : ->Set(context.local(), v8_str("o1"),
8273 : obj->NewInstance(context.local()).ToLocalChecked())
8274 : .FromJust());
8275 : CompileRun(
8276 : "o1.__proto__ = { };"
8277 : "var o2 = { __proto__: o1 };"
8278 : "var o3 = { __proto__: o2 };"
8279 : "var o4 = { __proto__: o3 };"
8280 : "for (var i = 0; i < 10; i++) o4.p4;"
8281 : "for (var i = 0; i < 10; i++) o3.p3;"
8282 : "for (var i = 0; i < 10; i++) o2.p2;"
8283 12 : "for (var i = 0; i < 10; i++) o1.p1;");
8284 12 : }
8285 :
8286 :
8287 240 : static void PGetter2(Local<Name> name,
8288 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8289 240 : ApiTestFuzzer::Fuzz();
8290 240 : p_getter_count2++;
8291 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8292 240 : v8::Local<v8::Object> global = context->Global();
8293 960 : CHECK(
8294 : info.Holder()
8295 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8296 : .FromJust());
8297 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8298 240 : CHECK(info.This()
8299 : ->Equals(context,
8300 : global->Get(context, v8_str("o1")).ToLocalChecked())
8301 : .FromJust());
8302 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8303 240 : CHECK(info.This()
8304 : ->Equals(context,
8305 : global->Get(context, v8_str("o2")).ToLocalChecked())
8306 : .FromJust());
8307 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8308 240 : CHECK(info.This()
8309 : ->Equals(context,
8310 : global->Get(context, v8_str("o3")).ToLocalChecked())
8311 : .FromJust());
8312 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8313 240 : CHECK(info.This()
8314 : ->Equals(context,
8315 : global->Get(context, v8_str("o4")).ToLocalChecked())
8316 : .FromJust());
8317 : }
8318 240 : }
8319 :
8320 :
8321 25881 : THREADED_TEST(GetterHolders) {
8322 6 : v8::Isolate* isolate = CcTest::isolate();
8323 6 : v8::HandleScope scope(isolate);
8324 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8325 12 : obj->SetAccessor(v8_str("p1"), PGetter);
8326 12 : obj->SetAccessor(v8_str("p2"), PGetter);
8327 12 : obj->SetAccessor(v8_str("p3"), PGetter);
8328 12 : obj->SetAccessor(v8_str("p4"), PGetter);
8329 6 : p_getter_count = 0;
8330 6 : RunHolderTest(obj);
8331 6 : CHECK_EQ(40, p_getter_count);
8332 6 : }
8333 :
8334 :
8335 25881 : THREADED_TEST(PreInterceptorHolders) {
8336 6 : v8::Isolate* isolate = CcTest::isolate();
8337 6 : v8::HandleScope scope(isolate);
8338 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8339 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8340 6 : p_getter_count2 = 0;
8341 6 : RunHolderTest(obj);
8342 6 : CHECK_EQ(40, p_getter_count2);
8343 6 : }
8344 :
8345 :
8346 25881 : THREADED_TEST(ObjectInstantiation) {
8347 6 : v8::Isolate* isolate = CcTest::isolate();
8348 6 : v8::HandleScope scope(isolate);
8349 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8350 12 : templ->SetAccessor(v8_str("t"), PGetter2);
8351 12 : LocalContext context;
8352 36 : CHECK(context->Global()
8353 : ->Set(context.local(), v8_str("o"),
8354 : templ->NewInstance(context.local()).ToLocalChecked())
8355 : .FromJust());
8356 600 : for (int i = 0; i < 100; i++) {
8357 600 : v8::HandleScope inner_scope(CcTest::isolate());
8358 : v8::Local<v8::Object> obj =
8359 600 : templ->NewInstance(context.local()).ToLocalChecked();
8360 3600 : CHECK(!obj->Equals(context.local(), context->Global()
8361 : ->Get(context.local(), v8_str("o"))
8362 : .ToLocalChecked())
8363 : .FromJust());
8364 3000 : CHECK(
8365 : context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8366 600 : v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8367 1800 : CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8368 3000 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8369 606 : }
8370 6 : }
8371 :
8372 :
8373 : static int StrCmp16(uint16_t* a, uint16_t* b) {
8374 : while (true) {
8375 168 : if (*a == 0 && *b == 0) return 0;
8376 138 : if (*a != *b) return 0 + *a - *b;
8377 132 : a++;
8378 132 : b++;
8379 : }
8380 : }
8381 :
8382 :
8383 : static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8384 : while (true) {
8385 150 : if (n-- == 0) return 0;
8386 120 : if (*a == 0 && *b == 0) return 0;
8387 120 : if (*a != *b) return 0 + *a - *b;
8388 120 : a++;
8389 120 : b++;
8390 : }
8391 : }
8392 :
8393 552 : int GetUtf8Length(v8::Isolate* isolate, Local<String> str) {
8394 552 : int len = str->Utf8Length(isolate);
8395 552 : if (len < 0) {
8396 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8397 0 : i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8398 0 : i::String::Flatten(i_isolate, istr);
8399 0 : len = str->Utf8Length(isolate);
8400 : }
8401 552 : return len;
8402 : }
8403 :
8404 :
8405 25881 : THREADED_TEST(StringWrite) {
8406 6 : LocalContext context;
8407 6 : v8::Isolate* isolate = context->GetIsolate();
8408 12 : v8::HandleScope scope(isolate);
8409 6 : v8::Local<String> str = v8_str("abcde");
8410 : // abc<Icelandic eth><Unicode snowman>.
8411 6 : v8::Local<String> str2 = v8_str("abc\xC3\xB0\xE2\x98\x83");
8412 : v8::Local<String> str3 =
8413 : v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8414 6 : v8::NewStringType::kNormal, 7)
8415 6 : .ToLocalChecked();
8416 : // "ab" + lead surrogate + "wx" + trail surrogate + "yz"
8417 6 : uint16_t orphans[8] = {0x61, 0x62, 0xD800, 0x77, 0x78, 0xDC00, 0x79, 0x7A};
8418 : v8::Local<String> orphans_str =
8419 : v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8420 6 : v8::NewStringType::kNormal, 8)
8421 6 : .ToLocalChecked();
8422 : // single lead surrogate
8423 6 : uint16_t lead[1] = {0xD800};
8424 : v8::Local<String> lead_str =
8425 : v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8426 6 : v8::NewStringType::kNormal, 1)
8427 6 : .ToLocalChecked();
8428 : // single trail surrogate
8429 6 : uint16_t trail[1] = {0xDC00};
8430 : v8::Local<String> trail_str =
8431 : v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8432 6 : v8::NewStringType::kNormal, 1)
8433 6 : .ToLocalChecked();
8434 : // surrogate pair
8435 6 : uint16_t pair[2] = {0xD800, 0xDC00};
8436 : v8::Local<String> pair_str =
8437 : v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8438 6 : v8::NewStringType::kNormal, 2)
8439 6 : .ToLocalChecked();
8440 : const int kStride = 4; // Must match stride in for loops in JS below.
8441 : CompileRun(
8442 : "var left = '';"
8443 : "for (var i = 0; i < 0xD800; i += 4) {"
8444 : " left = left + String.fromCharCode(i);"
8445 : "}");
8446 : CompileRun(
8447 : "var right = '';"
8448 : "for (var i = 0; i < 0xD800; i += 4) {"
8449 : " right = String.fromCharCode(i) + right;"
8450 : "}");
8451 6 : v8::Local<v8::Object> global = context->Global();
8452 18 : Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8453 6 : .ToLocalChecked()
8454 : .As<String>();
8455 18 : Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8456 6 : .ToLocalChecked()
8457 : .As<String>();
8458 :
8459 6 : CHECK_EQ(5, str2->Length());
8460 6 : CHECK_EQ(0xD800 / kStride, left_tree->Length());
8461 6 : CHECK_EQ(0xD800 / kStride, right_tree->Length());
8462 :
8463 : char buf[100];
8464 : char utf8buf[0xD800 * 3];
8465 : uint16_t wbuf[100];
8466 : int len;
8467 : int charlen;
8468 :
8469 : memset(utf8buf, 0x1, 1000);
8470 : len = v8::String::Empty(isolate)->WriteUtf8(isolate, utf8buf, sizeof(utf8buf),
8471 6 : &charlen);
8472 6 : CHECK_EQ(1, len);
8473 6 : CHECK_EQ(0, charlen);
8474 6 : CHECK_EQ(0, strcmp(utf8buf, ""));
8475 :
8476 : memset(utf8buf, 0x1, 1000);
8477 6 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8478 6 : CHECK_EQ(9, len);
8479 6 : CHECK_EQ(5, charlen);
8480 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8481 :
8482 : memset(utf8buf, 0x1, 1000);
8483 6 : len = str2->WriteUtf8(isolate, utf8buf, 8, &charlen);
8484 6 : CHECK_EQ(8, len);
8485 6 : CHECK_EQ(5, charlen);
8486 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83\x01", 9));
8487 :
8488 : memset(utf8buf, 0x1, 1000);
8489 6 : len = str2->WriteUtf8(isolate, utf8buf, 7, &charlen);
8490 6 : CHECK_EQ(5, len);
8491 6 : CHECK_EQ(4, charlen);
8492 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8493 :
8494 : memset(utf8buf, 0x1, 1000);
8495 6 : len = str2->WriteUtf8(isolate, utf8buf, 6, &charlen);
8496 6 : CHECK_EQ(5, len);
8497 6 : CHECK_EQ(4, charlen);
8498 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8499 :
8500 : memset(utf8buf, 0x1, 1000);
8501 6 : len = str2->WriteUtf8(isolate, utf8buf, 5, &charlen);
8502 6 : CHECK_EQ(5, len);
8503 6 : CHECK_EQ(4, charlen);
8504 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8505 :
8506 : memset(utf8buf, 0x1, 1000);
8507 6 : len = str2->WriteUtf8(isolate, utf8buf, 4, &charlen);
8508 6 : CHECK_EQ(3, len);
8509 6 : CHECK_EQ(3, charlen);
8510 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8511 :
8512 : memset(utf8buf, 0x1, 1000);
8513 6 : len = str2->WriteUtf8(isolate, utf8buf, 3, &charlen);
8514 6 : CHECK_EQ(3, len);
8515 6 : CHECK_EQ(3, charlen);
8516 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8517 :
8518 : memset(utf8buf, 0x1, 1000);
8519 6 : len = str2->WriteUtf8(isolate, utf8buf, 2, &charlen);
8520 6 : CHECK_EQ(2, len);
8521 6 : CHECK_EQ(2, charlen);
8522 6 : CHECK_EQ(0, strncmp(utf8buf, "ab\x01", 3));
8523 :
8524 : // allow orphan surrogates by default
8525 : memset(utf8buf, 0x1, 1000);
8526 6 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8527 6 : CHECK_EQ(13, len);
8528 6 : CHECK_EQ(8, charlen);
8529 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xED\xA0\x80wx\xED\xB0\x80yz"));
8530 :
8531 : // replace orphan surrogates with Unicode replacement character
8532 : memset(utf8buf, 0x1, 1000);
8533 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8534 6 : String::REPLACE_INVALID_UTF8);
8535 6 : CHECK_EQ(13, len);
8536 6 : CHECK_EQ(8, charlen);
8537 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xEF\xBF\xBDwx\xEF\xBF\xBDyz"));
8538 :
8539 : // replace single lead surrogate with Unicode replacement character
8540 : memset(utf8buf, 0x1, 1000);
8541 : len = lead_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8542 6 : String::REPLACE_INVALID_UTF8);
8543 6 : CHECK_EQ(4, len);
8544 6 : CHECK_EQ(1, charlen);
8545 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8546 :
8547 : // replace single trail surrogate with Unicode replacement character
8548 : memset(utf8buf, 0x1, 1000);
8549 : len = trail_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8550 6 : String::REPLACE_INVALID_UTF8);
8551 6 : CHECK_EQ(4, len);
8552 6 : CHECK_EQ(1, charlen);
8553 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8554 :
8555 : // do not replace / write anything if surrogate pair does not fit the buffer
8556 : // space
8557 : memset(utf8buf, 0x1, 1000);
8558 : len = pair_str->WriteUtf8(isolate, utf8buf, 3, &charlen,
8559 6 : String::REPLACE_INVALID_UTF8);
8560 6 : CHECK_EQ(0, len);
8561 6 : CHECK_EQ(0, charlen);
8562 :
8563 : memset(utf8buf, 0x1, sizeof(utf8buf));
8564 6 : len = GetUtf8Length(isolate, left_tree);
8565 : int utf8_expected =
8566 : (0x80 + (0x800 - 0x80) * 2 + (0xD800 - 0x800) * 3) / kStride;
8567 6 : CHECK_EQ(utf8_expected, len);
8568 6 : len = left_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8569 6 : CHECK_EQ(utf8_expected, len);
8570 6 : CHECK_EQ(0xD800 / kStride, charlen);
8571 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8572 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8573 12 : CHECK_EQ(0xC0 - kStride,
8574 : static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8575 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8576 :
8577 : memset(utf8buf, 0x1, sizeof(utf8buf));
8578 6 : len = GetUtf8Length(isolate, right_tree);
8579 6 : CHECK_EQ(utf8_expected, len);
8580 6 : len = right_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8581 6 : CHECK_EQ(utf8_expected, len);
8582 6 : CHECK_EQ(0xD800 / kStride, charlen);
8583 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[0]));
8584 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[1]));
8585 12 : CHECK_EQ(0xC0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8586 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8587 :
8588 : memset(buf, 0x1, sizeof(buf));
8589 : memset(wbuf, 0x1, sizeof(wbuf));
8590 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8591 6 : CHECK_EQ(5, len);
8592 6 : len = str->Write(isolate, wbuf);
8593 6 : CHECK_EQ(5, len);
8594 6 : CHECK_EQ(0, strcmp("abcde", buf));
8595 6 : uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8596 6 : CHECK_EQ(0, StrCmp16(answer1, wbuf));
8597 :
8598 : memset(buf, 0x1, sizeof(buf));
8599 : memset(wbuf, 0x1, sizeof(wbuf));
8600 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 4);
8601 6 : CHECK_EQ(4, len);
8602 6 : len = str->Write(isolate, wbuf, 0, 4);
8603 6 : CHECK_EQ(4, len);
8604 6 : CHECK_EQ(0, strncmp("abcd\x01", buf, 5));
8605 6 : uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8606 6 : CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8607 :
8608 : memset(buf, 0x1, sizeof(buf));
8609 : memset(wbuf, 0x1, sizeof(wbuf));
8610 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 5);
8611 6 : CHECK_EQ(5, len);
8612 6 : len = str->Write(isolate, wbuf, 0, 5);
8613 6 : CHECK_EQ(5, len);
8614 6 : CHECK_EQ(0, strncmp("abcde\x01", buf, 6));
8615 6 : uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8616 6 : CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8617 :
8618 : memset(buf, 0x1, sizeof(buf));
8619 : memset(wbuf, 0x1, sizeof(wbuf));
8620 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6);
8621 6 : CHECK_EQ(5, len);
8622 6 : len = str->Write(isolate, wbuf, 0, 6);
8623 6 : CHECK_EQ(5, len);
8624 6 : CHECK_EQ(0, strcmp("abcde", buf));
8625 6 : uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8626 6 : CHECK_EQ(0, StrCmp16(answer4, wbuf));
8627 :
8628 : memset(buf, 0x1, sizeof(buf));
8629 : memset(wbuf, 0x1, sizeof(wbuf));
8630 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, -1);
8631 6 : CHECK_EQ(1, len);
8632 6 : len = str->Write(isolate, wbuf, 4, -1);
8633 6 : CHECK_EQ(1, len);
8634 6 : CHECK_EQ(0, strcmp("e", buf));
8635 6 : uint16_t answer5[] = {'e', '\0'};
8636 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8637 :
8638 : memset(buf, 0x1, sizeof(buf));
8639 : memset(wbuf, 0x1, sizeof(wbuf));
8640 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 6);
8641 6 : CHECK_EQ(1, len);
8642 6 : len = str->Write(isolate, wbuf, 4, 6);
8643 6 : CHECK_EQ(1, len);
8644 6 : CHECK_EQ(0, strcmp("e", buf));
8645 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8646 :
8647 : memset(buf, 0x1, sizeof(buf));
8648 : memset(wbuf, 0x1, sizeof(wbuf));
8649 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 1);
8650 6 : CHECK_EQ(1, len);
8651 6 : len = str->Write(isolate, wbuf, 4, 1);
8652 6 : CHECK_EQ(1, len);
8653 6 : CHECK_EQ(0, strncmp("e\x01", buf, 2));
8654 6 : uint16_t answer6[] = {'e', 0x101};
8655 6 : CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8656 :
8657 : memset(buf, 0x1, sizeof(buf));
8658 : memset(wbuf, 0x1, sizeof(wbuf));
8659 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 3, 1);
8660 6 : CHECK_EQ(1, len);
8661 6 : len = str->Write(isolate, wbuf, 3, 1);
8662 6 : CHECK_EQ(1, len);
8663 6 : CHECK_EQ(0, strncmp("d\x01", buf, 2));
8664 6 : uint16_t answer7[] = {'d', 0x101};
8665 6 : CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8666 :
8667 : memset(wbuf, 0x1, sizeof(wbuf));
8668 6 : wbuf[5] = 'X';
8669 6 : len = str->Write(isolate, wbuf, 0, 6, String::NO_NULL_TERMINATION);
8670 6 : CHECK_EQ(5, len);
8671 12 : CHECK_EQ('X', wbuf[5]);
8672 6 : uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8673 6 : uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8674 6 : CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8675 6 : CHECK_NE(0, StrCmp16(answer8b, wbuf));
8676 6 : wbuf[5] = '\0';
8677 6 : CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8678 :
8679 : memset(buf, 0x1, sizeof(buf));
8680 6 : buf[5] = 'X';
8681 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6,
8682 6 : String::NO_NULL_TERMINATION);
8683 6 : CHECK_EQ(5, len);
8684 6 : CHECK_EQ('X', buf[5]);
8685 6 : CHECK_EQ(0, strncmp("abcde", buf, 5));
8686 6 : CHECK_NE(0, strcmp("abcde", buf));
8687 6 : buf[5] = '\0';
8688 6 : CHECK_EQ(0, strcmp("abcde", buf));
8689 :
8690 : memset(utf8buf, 0x1, sizeof(utf8buf));
8691 6 : utf8buf[8] = 'X';
8692 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8693 6 : String::NO_NULL_TERMINATION);
8694 6 : CHECK_EQ(8, len);
8695 6 : CHECK_EQ('X', utf8buf[8]);
8696 6 : CHECK_EQ(5, charlen);
8697 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83", 8));
8698 6 : CHECK_NE(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8699 6 : utf8buf[8] = '\0';
8700 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8701 :
8702 : memset(utf8buf, 0x1, sizeof(utf8buf));
8703 6 : utf8buf[5] = 'X';
8704 : len = str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8705 6 : String::NO_NULL_TERMINATION);
8706 6 : CHECK_EQ(5, len);
8707 6 : CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8708 6 : CHECK_EQ(5, charlen);
8709 6 : utf8buf[5] = '\0';
8710 6 : CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8711 :
8712 : memset(buf, 0x1, sizeof(buf));
8713 6 : len = str3->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8714 6 : CHECK_EQ(7, len);
8715 6 : CHECK_EQ(0, strcmp("abc", buf));
8716 6 : CHECK_EQ(0, buf[3]);
8717 6 : CHECK_EQ(0, strcmp("def", buf + 4));
8718 :
8719 6 : CHECK_EQ(0, str->WriteOneByte(isolate, nullptr, 0, 0,
8720 : String::NO_NULL_TERMINATION));
8721 6 : CHECK_EQ(0, str->WriteUtf8(isolate, nullptr, 0, nullptr,
8722 : String::NO_NULL_TERMINATION));
8723 12 : CHECK_EQ(0, str->Write(isolate, nullptr, 0, 0, String::NO_NULL_TERMINATION));
8724 6 : }
8725 :
8726 :
8727 12 : static void Utf16Helper(
8728 : LocalContext& context, // NOLINT
8729 : const char* name,
8730 : const char* lengths_name,
8731 : int len) {
8732 : Local<v8::Array> a = Local<v8::Array>::Cast(
8733 60 : context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8734 : Local<v8::Array> alens =
8735 : Local<v8::Array>::Cast(context->Global()
8736 48 : ->Get(context.local(), v8_str(lengths_name))
8737 12 : .ToLocalChecked());
8738 552 : for (int i = 0; i < len; i++) {
8739 : Local<v8::String> string =
8740 1080 : Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8741 : Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8742 540 : alens->Get(context.local(), i).ToLocalChecked());
8743 540 : int length = GetUtf8Length(context->GetIsolate(), string);
8744 540 : CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8745 : }
8746 12 : }
8747 :
8748 6 : void TestUtf8DecodingAgainstReference(
8749 : v8::Isolate* isolate, const char* cases[],
8750 474 : const std::vector<std::vector<uint16_t>>& unicode_expected) {
8751 132 : for (size_t test_ix = 0; test_ix < unicode_expected.size(); ++test_ix) {
8752 60 : v8::Local<String> str = v8_str(cases[test_ix]);
8753 180 : CHECK_EQ(unicode_expected[test_ix].size(), str->Length());
8754 :
8755 60 : std::unique_ptr<uint16_t[]> buffer(new uint16_t[str->Length()]);
8756 60 : str->Write(isolate, buffer.get(), 0, -1, String::NO_NULL_TERMINATION);
8757 :
8758 1044 : for (size_t i = 0; i < unicode_expected[test_ix].size(); ++i) {
8759 576 : CHECK_EQ(unicode_expected[test_ix][i], buffer[i]);
8760 : }
8761 : }
8762 6 : }
8763 :
8764 25881 : THREADED_TEST(OverlongSequencesAndSurrogates) {
8765 6 : LocalContext context;
8766 12 : v8::HandleScope scope(context->GetIsolate());
8767 :
8768 : const char* cases[] = {
8769 : // Overlong 2-byte sequence.
8770 : "X\xc0\xbfY\0",
8771 : // Another overlong 2-byte sequence.
8772 : "X\xc1\xbfY\0",
8773 : // Overlong 3-byte sequence.
8774 : "X\xe0\x9f\xbfY\0",
8775 : // Overlong 4-byte sequence.
8776 : "X\xf0\x89\xbf\xbfY\0",
8777 : // Invalid 3-byte sequence (reserved for surrogates).
8778 : "X\xed\xa0\x80Y\0",
8779 : // Invalid 4-bytes sequence (value out of range).
8780 : "X\xf4\x90\x80\x80Y\0",
8781 :
8782 : // Start of an overlong 3-byte sequence but not enough continuation bytes.
8783 : "X\xe0\x9fY\0",
8784 : // Start of an overlong 4-byte sequence but not enough continuation bytes.
8785 : "X\xf0\x89\xbfY\0",
8786 : // Start of an invalid 3-byte sequence (reserved for surrogates) but not
8787 : // enough continuation bytes.
8788 : "X\xed\xa0Y\0",
8789 : // Start of an invalid 4-bytes sequence (value out of range) but not
8790 : // enough continuation bytes.
8791 : "X\xf4\x90\x80Y\0",
8792 6 : };
8793 : const std::vector<std::vector<uint16_t>> unicode_expected = {
8794 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8795 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8796 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8797 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8798 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8799 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8800 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8801 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8802 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8803 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8804 12 : };
8805 12 : CHECK_EQ(unicode_expected.size(), arraysize(cases));
8806 : TestUtf8DecodingAgainstReference(context->GetIsolate(), cases,
8807 12 : unicode_expected);
8808 6 : }
8809 :
8810 25881 : THREADED_TEST(Utf16) {
8811 6 : LocalContext context;
8812 12 : v8::HandleScope scope(context->GetIsolate());
8813 : CompileRun(
8814 : "var pad = '01234567890123456789';"
8815 : "var p = [];"
8816 : "var plens = [20, 3, 3];"
8817 : "p.push('01234567890123456789');"
8818 : "var lead = 0xD800;"
8819 : "var trail = 0xDC00;"
8820 : "p.push(String.fromCharCode(0xD800));"
8821 : "p.push(String.fromCharCode(0xDC00));"
8822 : "var a = [];"
8823 : "var b = [];"
8824 : "var c = [];"
8825 : "var alens = [];"
8826 : "for (var i = 0; i < 3; i++) {"
8827 : " p[1] = String.fromCharCode(lead++);"
8828 : " for (var j = 0; j < 3; j++) {"
8829 : " p[2] = String.fromCharCode(trail++);"
8830 : " a.push(p[i] + p[j]);"
8831 : " b.push(p[i] + p[j]);"
8832 : " c.push(p[i] + p[j]);"
8833 : " alens.push(plens[i] + plens[j]);"
8834 : " }"
8835 : "}"
8836 : "alens[5] -= 2;" // Here the surrogate pairs match up.
8837 : "var a2 = [];"
8838 : "var b2 = [];"
8839 : "var c2 = [];"
8840 : "var a2lens = [];"
8841 : "for (var m = 0; m < 9; m++) {"
8842 : " for (var n = 0; n < 9; n++) {"
8843 : " a2.push(a[m] + a[n]);"
8844 : " b2.push(b[m] + b[n]);"
8845 : " var newc = 'x' + c[m] + c[n] + 'y';"
8846 : " c2.push(newc.substring(1, newc.length - 1));"
8847 : " var utf = alens[m] + alens[n];" // And here.
8848 : // The 'n's that start with 0xDC..
8849 : // are 6-8 The 'm's that end with
8850 : // 0xD8.. are 1, 4 and 7
8851 : " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8852 : " a2lens.push(utf);"
8853 : " }"
8854 : "}");
8855 6 : Utf16Helper(context, "a", "alens", 9);
8856 12 : Utf16Helper(context, "a2", "a2lens", 81);
8857 6 : }
8858 :
8859 :
8860 42 : static bool SameSymbol(Local<String> s1, Local<String> s2) {
8861 : i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8862 : i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8863 42 : return *is1 == *is2;
8864 : }
8865 :
8866 :
8867 25881 : THREADED_TEST(Utf16Symbol) {
8868 6 : LocalContext context;
8869 12 : v8::HandleScope scope(context->GetIsolate());
8870 :
8871 : Local<String> symbol1 =
8872 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8873 6 : v8::NewStringType::kInternalized)
8874 12 : .ToLocalChecked();
8875 : Local<String> symbol2 =
8876 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8877 6 : v8::NewStringType::kInternalized)
8878 12 : .ToLocalChecked();
8879 6 : CHECK(SameSymbol(symbol1, symbol2));
8880 :
8881 : CompileRun(
8882 : "var sym0 = 'benedictus';"
8883 : "var sym0b = 'S\xC3\xB8ren';"
8884 : "var sym1 = '\xED\xA0\x81\xED\xB0\x87';"
8885 : "var sym2 = '\xF0\x90\x90\x88';"
8886 : "var sym3 = 'x\xED\xA0\x81\xED\xB0\x87';"
8887 : "var sym4 = 'x\xF0\x90\x90\x88';"
8888 : "if (sym1.length != 2) throw sym1;"
8889 : "if (sym1.charCodeAt(1) != 0xDC07) throw sym1.charCodeAt(1);"
8890 : "if (sym2.length != 2) throw sym2;"
8891 : "if (sym2.charCodeAt(1) != 0xDC08) throw sym2.charCodeAt(2);"
8892 : "if (sym3.length != 3) throw sym3;"
8893 : "if (sym3.charCodeAt(2) != 0xDC07) throw sym1.charCodeAt(2);"
8894 : "if (sym4.length != 3) throw sym4;"
8895 : "if (sym4.charCodeAt(2) != 0xDC08) throw sym2.charCodeAt(2);");
8896 : Local<String> sym0 =
8897 : v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8898 6 : v8::NewStringType::kInternalized)
8899 12 : .ToLocalChecked();
8900 : Local<String> sym0b =
8901 : v8::String::NewFromUtf8(context->GetIsolate(), "S\xC3\xB8ren",
8902 6 : v8::NewStringType::kInternalized)
8903 12 : .ToLocalChecked();
8904 : Local<String> sym1 =
8905 : v8::String::NewFromUtf8(context->GetIsolate(), "\xED\xA0\x81\xED\xB0\x87",
8906 6 : v8::NewStringType::kInternalized)
8907 12 : .ToLocalChecked();
8908 : Local<String> sym2 =
8909 : v8::String::NewFromUtf8(context->GetIsolate(), "\xF0\x90\x90\x88",
8910 6 : v8::NewStringType::kInternalized)
8911 12 : .ToLocalChecked();
8912 : Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8913 : "x\xED\xA0\x81\xED\xB0\x87",
8914 6 : v8::NewStringType::kInternalized)
8915 12 : .ToLocalChecked();
8916 : Local<String> sym4 =
8917 : v8::String::NewFromUtf8(context->GetIsolate(), "x\xF0\x90\x90\x88",
8918 6 : v8::NewStringType::kInternalized)
8919 12 : .ToLocalChecked();
8920 6 : v8::Local<v8::Object> global = context->Global();
8921 : Local<Value> s0 =
8922 18 : global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8923 : Local<Value> s0b =
8924 18 : global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8925 : Local<Value> s1 =
8926 18 : global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8927 : Local<Value> s2 =
8928 18 : global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8929 : Local<Value> s3 =
8930 18 : global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8931 : Local<Value> s4 =
8932 18 : global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8933 6 : CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8934 6 : CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8935 6 : CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8936 6 : CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8937 6 : CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8938 12 : CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8939 6 : }
8940 :
8941 :
8942 25881 : THREADED_TEST(Utf16MissingTrailing) {
8943 6 : LocalContext context;
8944 12 : v8::HandleScope scope(context->GetIsolate());
8945 :
8946 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8947 : int size = 1024 * 64;
8948 6 : uint8_t* buffer = new uint8_t[size];
8949 98310 : for (int i = 0; i < size; i += 4) {
8950 98304 : buffer[i] = 0xF0;
8951 98304 : buffer[i + 1] = 0x9D;
8952 98304 : buffer[i + 2] = 0x80;
8953 98304 : buffer[i + 3] = 0x9E;
8954 : }
8955 :
8956 : // Now invoke the decoder without last 3 bytes
8957 : v8::Local<v8::String> str =
8958 : v8::String::NewFromUtf8(
8959 : context->GetIsolate(), reinterpret_cast<char*>(buffer),
8960 6 : v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8961 : USE(str);
8962 12 : delete[] buffer;
8963 6 : }
8964 :
8965 :
8966 25881 : THREADED_TEST(Utf16Trailing3Byte) {
8967 6 : LocalContext context;
8968 6 : v8::Isolate* isolate = context->GetIsolate();
8969 12 : v8::HandleScope scope(isolate);
8970 :
8971 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8972 : int size = 1024 * 63;
8973 6 : uint8_t* buffer = new uint8_t[size];
8974 129030 : for (int i = 0; i < size; i += 3) {
8975 129024 : buffer[i] = 0xE2;
8976 129024 : buffer[i + 1] = 0x80;
8977 129024 : buffer[i + 2] = 0xA6;
8978 : }
8979 :
8980 : // Now invoke the decoder without last 3 bytes
8981 : v8::Local<v8::String> str =
8982 : v8::String::NewFromUtf8(isolate, reinterpret_cast<char*>(buffer),
8983 : v8::NewStringType::kNormal, size)
8984 6 : .ToLocalChecked();
8985 :
8986 12 : v8::String::Value value(isolate, str);
8987 6 : CHECK_EQ(value.length(), size / 3);
8988 12 : CHECK_EQ((*value)[value.length() - 1], 0x2026);
8989 :
8990 12 : delete[] buffer;
8991 6 : }
8992 :
8993 :
8994 25881 : THREADED_TEST(ToArrayIndex) {
8995 6 : LocalContext context;
8996 6 : v8::Isolate* isolate = context->GetIsolate();
8997 12 : v8::HandleScope scope(isolate);
8998 :
8999 6 : v8::Local<String> str = v8_str("42");
9000 6 : v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
9001 6 : CHECK(!index.IsEmpty());
9002 18 : CHECK_EQ(42.0,
9003 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9004 6 : str = v8_str("42asdf");
9005 6 : index = str->ToArrayIndex(context.local());
9006 6 : CHECK(index.IsEmpty());
9007 6 : str = v8_str("-42");
9008 6 : index = str->ToArrayIndex(context.local());
9009 6 : CHECK(index.IsEmpty());
9010 6 : str = v8_str("4294967294");
9011 6 : index = str->ToArrayIndex(context.local());
9012 6 : CHECK(!index.IsEmpty());
9013 18 : CHECK_EQ(4294967294.0,
9014 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9015 6 : v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
9016 6 : index = num->ToArrayIndex(context.local());
9017 6 : CHECK(!index.IsEmpty());
9018 18 : CHECK_EQ(1.0,
9019 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9020 6 : num = v8::Number::New(isolate, -1);
9021 6 : index = num->ToArrayIndex(context.local());
9022 6 : CHECK(index.IsEmpty());
9023 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
9024 12 : index = obj->ToArrayIndex(context.local());
9025 12 : CHECK(index.IsEmpty());
9026 6 : }
9027 :
9028 6 : static v8::MaybeLocal<Value> PrepareStackTrace42(v8::Local<Context> context,
9029 : v8::Local<Value> error,
9030 : v8::Local<Array> trace) {
9031 6 : return v8::Number::New(context->GetIsolate(), 42);
9032 : }
9033 :
9034 6 : static v8::MaybeLocal<Value> PrepareStackTraceThrow(v8::Local<Context> context,
9035 : v8::Local<Value> error,
9036 : v8::Local<Array> trace) {
9037 6 : v8::Isolate* isolate = context->GetIsolate();
9038 6 : v8::Local<String> message = v8_str("42");
9039 6 : isolate->ThrowException(v8::Exception::Error(message));
9040 6 : return v8::MaybeLocal<Value>();
9041 : }
9042 :
9043 25881 : THREADED_TEST(IsolatePrepareStackTrace) {
9044 6 : LocalContext context;
9045 6 : v8::Isolate* isolate = context->GetIsolate();
9046 12 : v8::HandleScope scope(isolate);
9047 :
9048 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTrace42);
9049 :
9050 : v8::Local<Value> v = CompileRun("new Error().stack");
9051 :
9052 6 : CHECK(v->IsNumber());
9053 18 : CHECK_EQ(v.As<v8::Number>()->Int32Value(context.local()).FromJust(), 42);
9054 6 : }
9055 :
9056 25881 : THREADED_TEST(IsolatePrepareStackTraceThrow) {
9057 6 : LocalContext context;
9058 6 : v8::Isolate* isolate = context->GetIsolate();
9059 12 : v8::HandleScope scope(isolate);
9060 :
9061 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTraceThrow);
9062 :
9063 : v8::Local<Value> v = CompileRun("try { new Error().stack } catch (e) { e }");
9064 :
9065 6 : CHECK(v->IsNativeError());
9066 :
9067 12 : v8::Local<String> message = v8::Exception::CreateMessage(isolate, v)->Get();
9068 :
9069 18 : CHECK(message->StrictEquals(v8_str("Uncaught Error: 42")));
9070 6 : }
9071 :
9072 25881 : THREADED_TEST(ErrorConstruction) {
9073 6 : LocalContext context;
9074 12 : v8::HandleScope scope(context->GetIsolate());
9075 :
9076 6 : v8::Local<String> foo = v8_str("foo");
9077 6 : v8::Local<String> message = v8_str("message");
9078 6 : v8::Local<Value> range_error = v8::Exception::RangeError(foo);
9079 6 : CHECK(range_error->IsObject());
9080 24 : CHECK(range_error.As<v8::Object>()
9081 : ->Get(context.local(), message)
9082 : .ToLocalChecked()
9083 : ->Equals(context.local(), foo)
9084 : .FromJust());
9085 6 : v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
9086 6 : CHECK(reference_error->IsObject());
9087 24 : CHECK(reference_error.As<v8::Object>()
9088 : ->Get(context.local(), message)
9089 : .ToLocalChecked()
9090 : ->Equals(context.local(), foo)
9091 : .FromJust());
9092 6 : v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
9093 6 : CHECK(syntax_error->IsObject());
9094 24 : CHECK(syntax_error.As<v8::Object>()
9095 : ->Get(context.local(), message)
9096 : .ToLocalChecked()
9097 : ->Equals(context.local(), foo)
9098 : .FromJust());
9099 6 : v8::Local<Value> type_error = v8::Exception::TypeError(foo);
9100 6 : CHECK(type_error->IsObject());
9101 24 : CHECK(type_error.As<v8::Object>()
9102 : ->Get(context.local(), message)
9103 : .ToLocalChecked()
9104 : ->Equals(context.local(), foo)
9105 : .FromJust());
9106 6 : v8::Local<Value> error = v8::Exception::Error(foo);
9107 6 : CHECK(error->IsObject());
9108 24 : CHECK(error.As<v8::Object>()
9109 : ->Get(context.local(), message)
9110 : .ToLocalChecked()
9111 : ->Equals(context.local(), foo)
9112 6 : .FromJust());
9113 6 : }
9114 :
9115 :
9116 48 : static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
9117 12 : ApiTestFuzzer::Fuzz();
9118 12 : v8::Local<String> foo = v8_str("foo");
9119 12 : v8::Local<String> message = v8_str("message");
9120 12 : v8::Local<Value> error = v8::Exception::Error(foo);
9121 12 : CHECK(error->IsObject());
9122 12 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9123 36 : CHECK(error.As<v8::Object>()
9124 : ->Get(context, message)
9125 : .ToLocalChecked()
9126 : ->Equals(context, foo)
9127 : .FromJust());
9128 12 : info.GetIsolate()->ThrowException(error);
9129 : info.GetReturnValue().SetUndefined();
9130 12 : }
9131 :
9132 :
9133 25881 : THREADED_TEST(ExceptionCreateMessage) {
9134 6 : LocalContext context;
9135 12 : v8::HandleScope scope(context->GetIsolate());
9136 6 : v8::Local<String> foo_str = v8_str("foo");
9137 6 : v8::Local<String> message_str = v8_str("message");
9138 :
9139 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
9140 :
9141 : Local<v8::FunctionTemplate> fun =
9142 6 : v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
9143 6 : v8::Local<v8::Object> global = context->Global();
9144 36 : CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
9145 : fun->GetFunction(context.local()).ToLocalChecked())
9146 : .FromJust());
9147 :
9148 12 : TryCatch try_catch(context->GetIsolate());
9149 : CompileRun(
9150 : "function f1() {\n"
9151 : " throwV8Exception();\n"
9152 : "};\n"
9153 : "f1();");
9154 6 : CHECK(try_catch.HasCaught());
9155 :
9156 6 : v8::Local<v8::Value> error = try_catch.Exception();
9157 6 : CHECK(error->IsObject());
9158 24 : CHECK(error.As<v8::Object>()
9159 : ->Get(context.local(), message_str)
9160 : .ToLocalChecked()
9161 : ->Equals(context.local(), foo_str)
9162 : .FromJust());
9163 :
9164 : v8::Local<v8::Message> message =
9165 6 : v8::Exception::CreateMessage(context->GetIsolate(), error);
9166 6 : CHECK(!message.IsEmpty());
9167 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9168 12 : CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
9169 :
9170 6 : v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
9171 6 : CHECK(!stackTrace.IsEmpty());
9172 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9173 :
9174 6 : stackTrace = v8::Exception::GetStackTrace(error);
9175 6 : CHECK(!stackTrace.IsEmpty());
9176 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9177 :
9178 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
9179 :
9180 : // Now check message location when SetCaptureStackTraceForUncaughtExceptions
9181 : // is false.
9182 6 : try_catch.Reset();
9183 :
9184 : CompileRun(
9185 : "function f2() {\n"
9186 : " return throwV8Exception();\n"
9187 : "};\n"
9188 : "f2();");
9189 6 : CHECK(try_catch.HasCaught());
9190 :
9191 6 : error = try_catch.Exception();
9192 6 : CHECK(error->IsObject());
9193 24 : CHECK(error.As<v8::Object>()
9194 : ->Get(context.local(), message_str)
9195 : .ToLocalChecked()
9196 : ->Equals(context.local(), foo_str)
9197 : .FromJust());
9198 :
9199 6 : message = v8::Exception::CreateMessage(context->GetIsolate(), error);
9200 6 : CHECK(!message.IsEmpty());
9201 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9202 12 : CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust());
9203 :
9204 : // Should be empty stack trace.
9205 6 : stackTrace = message->GetStackTrace();
9206 6 : CHECK(stackTrace.IsEmpty());
9207 18 : CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9208 6 : }
9209 :
9210 :
9211 25881 : THREADED_TEST(ExceptionCreateMessageLength) {
9212 6 : LocalContext context;
9213 12 : v8::HandleScope scope(context->GetIsolate());
9214 :
9215 : // Test that the message is not truncated.
9216 12 : TryCatch try_catch(context->GetIsolate());
9217 : CompileRun(
9218 : "var message = 'm';"
9219 : "while (message.length < 1000) message += message;"
9220 : "throw message;");
9221 6 : CHECK(try_catch.HasCaught());
9222 :
9223 24 : CHECK_LT(1000, try_catch.Message()->Get()->Length());
9224 6 : }
9225 :
9226 :
9227 0 : static void YGetter(Local<String> name,
9228 : const v8::PropertyCallbackInfo<v8::Value>& info) {
9229 0 : ApiTestFuzzer::Fuzz();
9230 0 : info.GetReturnValue().Set(v8_num(10));
9231 0 : }
9232 :
9233 :
9234 6 : static void YSetter(Local<String> name,
9235 : Local<Value> value,
9236 : const v8::PropertyCallbackInfo<void>& info) {
9237 : Local<Object> this_obj = Local<Object>::Cast(info.This());
9238 6 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9239 12 : if (this_obj->Has(context, name).FromJust())
9240 12 : this_obj->Delete(context, name).FromJust();
9241 12 : CHECK(this_obj->Set(context, name, value).FromJust());
9242 6 : }
9243 :
9244 :
9245 25881 : THREADED_TEST(DeleteAccessor) {
9246 6 : v8::Isolate* isolate = CcTest::isolate();
9247 6 : v8::HandleScope scope(isolate);
9248 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9249 6 : obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9250 12 : LocalContext context;
9251 : v8::Local<v8::Object> holder =
9252 6 : obj->NewInstance(context.local()).ToLocalChecked();
9253 30 : CHECK(context->Global()
9254 : ->Set(context.local(), v8_str("holder"), holder)
9255 : .FromJust());
9256 : v8::Local<Value> result =
9257 : CompileRun("holder.y = 11; holder.y = 12; holder.y");
9258 18 : CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
9259 6 : }
9260 :
9261 :
9262 : static int trouble_nesting = 0;
9263 45 : static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9264 15 : ApiTestFuzzer::Fuzz();
9265 15 : trouble_nesting++;
9266 :
9267 : // Call a JS function that throws an uncaught exception.
9268 15 : Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
9269 15 : Local<v8::Object> arg_this = context->Global();
9270 : Local<Value> trouble_callee =
9271 15 : (trouble_nesting == 3)
9272 30 : ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
9273 60 : : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
9274 15 : CHECK(trouble_callee->IsFunction());
9275 : args.GetReturnValue().Set(Function::Cast(*trouble_callee)
9276 15 : ->Call(context, arg_this, 0, nullptr)
9277 30 : .FromMaybe(v8::Local<v8::Value>()));
9278 15 : }
9279 :
9280 :
9281 : static int report_count = 0;
9282 5 : static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
9283 : v8::Local<Value>) {
9284 5 : report_count++;
9285 5 : }
9286 :
9287 :
9288 : // Counts uncaught exceptions, but other tests running in parallel
9289 : // also have uncaught exceptions.
9290 25880 : TEST(ApiUncaughtException) {
9291 5 : report_count = 0;
9292 5 : LocalContext env;
9293 5 : v8::Isolate* isolate = env->GetIsolate();
9294 10 : v8::HandleScope scope(isolate);
9295 5 : isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
9296 :
9297 : Local<v8::FunctionTemplate> fun =
9298 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9299 5 : v8::Local<v8::Object> global = env->Global();
9300 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9301 : fun->GetFunction(env.local()).ToLocalChecked())
9302 : .FromJust());
9303 :
9304 : CompileRun(
9305 : "function trouble_callee() {"
9306 : " var x = null;"
9307 : " return x.foo;"
9308 : "};"
9309 : "function trouble_caller() {"
9310 : " trouble();"
9311 : "};");
9312 : Local<Value> trouble =
9313 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9314 5 : CHECK(trouble->IsFunction());
9315 : Local<Value> trouble_callee =
9316 15 : global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9317 5 : CHECK(trouble_callee->IsFunction());
9318 : Local<Value> trouble_caller =
9319 15 : global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9320 5 : CHECK(trouble_caller->IsFunction());
9321 : Function::Cast(*trouble_caller)
9322 10 : ->Call(env.local(), global, 0, nullptr)
9323 5 : .FromMaybe(v8::Local<v8::Value>());
9324 5 : CHECK_EQ(1, report_count);
9325 10 : isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9326 5 : }
9327 :
9328 :
9329 : static const char* script_resource_name = "ExceptionInNativeScript.js";
9330 5 : static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9331 : v8::Local<Value>) {
9332 5 : v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9333 10 : CHECK(!name_val.IsEmpty() && name_val->IsString());
9334 : v8::String::Utf8Value name(v8::Isolate::GetCurrent(),
9335 5 : message->GetScriptOrigin().ResourceName());
9336 5 : CHECK_EQ(0, strcmp(script_resource_name, *name));
9337 : v8::Local<v8::Context> context =
9338 5 : v8::Isolate::GetCurrent()->GetCurrentContext();
9339 10 : CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9340 : v8::String::Utf8Value source_line(
9341 : v8::Isolate::GetCurrent(),
9342 15 : message->GetSourceLine(context).ToLocalChecked());
9343 10 : CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9344 5 : }
9345 :
9346 :
9347 25880 : TEST(ExceptionInNativeScript) {
9348 5 : LocalContext env;
9349 5 : v8::Isolate* isolate = env->GetIsolate();
9350 10 : v8::HandleScope scope(isolate);
9351 5 : isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9352 :
9353 : Local<v8::FunctionTemplate> fun =
9354 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9355 5 : v8::Local<v8::Object> global = env->Global();
9356 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9357 : fun->GetFunction(env.local()).ToLocalChecked())
9358 : .FromJust());
9359 :
9360 : CompileRunWithOrigin(
9361 : "function trouble() {\n"
9362 : " var o = {};\n"
9363 : " new o.foo();\n"
9364 : "};",
9365 5 : script_resource_name);
9366 : Local<Value> trouble =
9367 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9368 5 : CHECK(trouble->IsFunction());
9369 10 : CHECK(Function::Cast(*trouble)
9370 : ->Call(env.local(), global, 0, nullptr)
9371 : .IsEmpty());
9372 10 : isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9373 5 : }
9374 :
9375 :
9376 25880 : TEST(CompilationErrorUsingTryCatchHandler) {
9377 5 : LocalContext env;
9378 10 : v8::HandleScope scope(env->GetIsolate());
9379 10 : v8::TryCatch try_catch(env->GetIsolate());
9380 : v8_compile("This doesn't &*&@#$&*^ compile.");
9381 10 : CHECK(*try_catch.Exception());
9382 10 : CHECK(try_catch.HasCaught());
9383 5 : }
9384 :
9385 :
9386 25880 : TEST(TryCatchFinallyUsingTryCatchHandler) {
9387 5 : LocalContext env;
9388 10 : v8::HandleScope scope(env->GetIsolate());
9389 10 : v8::TryCatch try_catch(env->GetIsolate());
9390 : CompileRun("try { throw ''; } catch (e) {}");
9391 5 : CHECK(!try_catch.HasCaught());
9392 : CompileRun("try { throw ''; } finally {}");
9393 5 : CHECK(try_catch.HasCaught());
9394 5 : try_catch.Reset();
9395 : CompileRun(
9396 : "(function() {"
9397 : "try { throw ''; } finally { return; }"
9398 : "})()");
9399 5 : CHECK(!try_catch.HasCaught());
9400 : CompileRun(
9401 : "(function()"
9402 : " { try { throw ''; } finally { throw 0; }"
9403 : "})()");
9404 10 : CHECK(try_catch.HasCaught());
9405 5 : }
9406 :
9407 :
9408 20 : void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9409 10 : v8::HandleScope scope(args.GetIsolate());
9410 : CompileRun(args[0]
9411 10 : ->ToString(args.GetIsolate()->GetCurrentContext())
9412 20 : .ToLocalChecked());
9413 10 : }
9414 :
9415 :
9416 25880 : TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9417 5 : v8::Isolate* isolate = CcTest::isolate();
9418 5 : v8::HandleScope scope(isolate);
9419 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9420 : templ->Set(v8_str("CEvaluate"),
9421 15 : v8::FunctionTemplate::New(isolate, CEvaluate));
9422 10 : LocalContext context(nullptr, templ);
9423 10 : v8::TryCatch try_catch(isolate);
9424 : CompileRun("try {"
9425 : " CEvaluate('throw 1;');"
9426 : "} finally {"
9427 : "}");
9428 5 : CHECK(try_catch.HasCaught());
9429 10 : CHECK(!try_catch.Message().IsEmpty());
9430 10 : String::Utf8Value exception_value(isolate, try_catch.Exception());
9431 5 : CHECK_EQ(0, strcmp(*exception_value, "1"));
9432 5 : try_catch.Reset();
9433 : CompileRun("try {"
9434 : " CEvaluate('throw 1;');"
9435 : "} finally {"
9436 : " throw 2;"
9437 : "}");
9438 5 : CHECK(try_catch.HasCaught());
9439 10 : CHECK(!try_catch.Message().IsEmpty());
9440 10 : String::Utf8Value finally_exception_value(isolate, try_catch.Exception());
9441 10 : CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9442 5 : }
9443 :
9444 :
9445 : // For use within the TestSecurityHandler() test.
9446 : static bool g_security_callback_result = false;
9447 35 : static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9448 : Local<v8::Object> accessed_object,
9449 : Local<v8::Value> data) {
9450 : printf("a\n");
9451 35 : CHECK(!data.IsEmpty() && data->IsInt32());
9452 70 : CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9453 35 : return g_security_callback_result;
9454 : }
9455 :
9456 :
9457 : // SecurityHandler can't be run twice
9458 25880 : TEST(SecurityHandler) {
9459 5 : v8::Isolate* isolate = CcTest::isolate();
9460 5 : v8::HandleScope scope0(isolate);
9461 : v8::Local<v8::ObjectTemplate> global_template =
9462 5 : v8::ObjectTemplate::New(isolate);
9463 10 : global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9464 : // Create an environment
9465 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9466 5 : context0->Enter();
9467 :
9468 5 : v8::Local<v8::Object> global0 = context0->Global();
9469 : v8::Local<Script> script0 = v8_compile("foo = 111");
9470 5 : script0->Run(context0).ToLocalChecked();
9471 15 : CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9472 : v8::Local<Value> foo0 =
9473 15 : global0->Get(context0, v8_str("foo")).ToLocalChecked();
9474 10 : CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9475 15 : v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9476 10 : CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9477 :
9478 : // Create another environment, should fail security checks.
9479 10 : v8::HandleScope scope1(isolate);
9480 :
9481 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, global_template);
9482 5 : context1->Enter();
9483 :
9484 5 : v8::Local<v8::Object> global1 = context1->Global();
9485 15 : global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9486 : // This set will fail the security check.
9487 : v8::Local<Script> script1 =
9488 : v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9489 10 : CHECK(script1->Run(context1).IsEmpty());
9490 5 : g_security_callback_result = true;
9491 : // This read will pass the security check.
9492 : v8::Local<Value> foo1 =
9493 15 : global0->Get(context1, v8_str("foo")).ToLocalChecked();
9494 10 : CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9495 : // This read will pass the security check.
9496 15 : v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9497 10 : CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9498 :
9499 : // Create another environment, should pass security checks.
9500 : {
9501 5 : v8::HandleScope scope2(isolate);
9502 10 : LocalContext context2;
9503 5 : v8::Local<v8::Object> global2 = context2->Global();
9504 20 : CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9505 : .FromJust());
9506 : v8::Local<Script> script2 =
9507 : v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9508 5 : script2->Run(context2.local()).ToLocalChecked();
9509 : v8::Local<Value> foo2 =
9510 15 : global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9511 10 : CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9512 : v8::Local<Value> z2 =
9513 15 : global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9514 15 : CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9515 : }
9516 :
9517 5 : context1->Exit();
9518 10 : context0->Exit();
9519 5 : }
9520 :
9521 :
9522 25881 : THREADED_TEST(SecurityChecks) {
9523 6 : LocalContext env1;
9524 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9525 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9526 :
9527 6 : Local<Value> foo = v8_str("foo");
9528 6 : Local<Value> bar = v8_str("bar");
9529 :
9530 : // Set to the same domain.
9531 6 : env1->SetSecurityToken(foo);
9532 :
9533 : // Create a function in env1.
9534 : CompileRun("spy=function(){return spy;}");
9535 : Local<Value> spy =
9536 30 : env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9537 6 : CHECK(spy->IsFunction());
9538 :
9539 : // Create another function accessing global objects.
9540 : CompileRun("spy2=function(){return new this.Array();}");
9541 : Local<Value> spy2 =
9542 30 : env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9543 6 : CHECK(spy2->IsFunction());
9544 :
9545 : // Switch to env2 in the same domain and invoke spy on env2.
9546 : {
9547 6 : env2->SetSecurityToken(foo);
9548 : // Enter env2
9549 : Context::Scope scope_env2(env2);
9550 : Local<Value> result = Function::Cast(*spy)
9551 12 : ->Call(env2, env2->Global(), 0, nullptr)
9552 6 : .ToLocalChecked();
9553 6 : CHECK(result->IsFunction());
9554 : }
9555 :
9556 : {
9557 6 : env2->SetSecurityToken(bar);
9558 : Context::Scope scope_env2(env2);
9559 :
9560 : // Call cross_domain_call, it should throw an exception
9561 12 : v8::TryCatch try_catch(env1->GetIsolate());
9562 18 : CHECK(Function::Cast(*spy2)
9563 : ->Call(env2, env2->Global(), 0, nullptr)
9564 : .IsEmpty());
9565 6 : CHECK(try_catch.HasCaught());
9566 6 : }
9567 6 : }
9568 :
9569 :
9570 : // Regression test case for issue 1183439.
9571 25881 : THREADED_TEST(SecurityChecksForPrototypeChain) {
9572 6 : LocalContext current;
9573 12 : v8::HandleScope scope(current->GetIsolate());
9574 6 : v8::Local<Context> other = Context::New(current->GetIsolate());
9575 :
9576 : // Change context to be able to get to the Object function in the
9577 : // other context without hitting the security checks.
9578 : v8::Local<Value> other_object;
9579 : { Context::Scope scope(other);
9580 : other_object =
9581 24 : other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9582 18 : CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9583 : }
9584 :
9585 36 : CHECK(current->Global()
9586 : ->Set(current.local(), v8_str("other"), other->Global())
9587 : .FromJust());
9588 30 : CHECK(v8_compile("other")
9589 : ->Run(current.local())
9590 : .ToLocalChecked()
9591 : ->Equals(current.local(), other->Global())
9592 : .FromJust());
9593 :
9594 : // Make sure the security check fails here and we get an undefined
9595 : // result instead of getting the Object function. Repeat in a loop
9596 : // to make sure to exercise the IC code.
9597 : v8::Local<Script> access_other0 = v8_compile("other.Object");
9598 : v8::Local<Script> access_other1 = v8_compile("other[42]");
9599 36 : for (int i = 0; i < 5; i++) {
9600 60 : CHECK(access_other0->Run(current.local()).IsEmpty());
9601 60 : CHECK(access_other1->Run(current.local()).IsEmpty());
9602 : }
9603 :
9604 : // Create an object that has 'other' in its prototype chain and make
9605 : // sure we cannot access the Object function indirectly through
9606 : // that. Repeat in a loop to make sure to exercise the IC code.
9607 : v8_compile(
9608 : "function F() { };"
9609 : "F.prototype = other;"
9610 : "var f = new F();")
9611 6 : ->Run(current.local())
9612 6 : .ToLocalChecked();
9613 : v8::Local<Script> access_f0 = v8_compile("f.Object");
9614 : v8::Local<Script> access_f1 = v8_compile("f[42]");
9615 36 : for (int j = 0; j < 5; j++) {
9616 60 : CHECK(access_f0->Run(current.local()).IsEmpty());
9617 60 : CHECK(access_f1->Run(current.local()).IsEmpty());
9618 : }
9619 :
9620 : // Now it gets hairy: Set the prototype for the other global object
9621 : // to be the current global object. The prototype chain for 'f' now
9622 : // goes through 'other' but ends up in the current global object.
9623 : { Context::Scope scope(other);
9624 30 : CHECK(other->Global()
9625 : ->Set(other, v8_str("__proto__"), current->Global())
9626 : .FromJust());
9627 : }
9628 : // Set a named and an index property on the current global
9629 : // object. To force the lookup to go through the other global object,
9630 : // the properties must not exist in the other global object.
9631 30 : CHECK(current->Global()
9632 : ->Set(current.local(), v8_str("foo"), v8_num(100))
9633 : .FromJust());
9634 24 : CHECK(current->Global()
9635 : ->Set(current.local(), v8_num(99), v8_num(101))
9636 : .FromJust());
9637 : // Try to read the properties from f and make sure that the access
9638 : // gets stopped by the security checks on the other global object.
9639 : Local<Script> access_f2 = v8_compile("f.foo");
9640 : Local<Script> access_f3 = v8_compile("f[99]");
9641 36 : for (int k = 0; k < 5; k++) {
9642 60 : CHECK(access_f2->Run(current.local()).IsEmpty());
9643 60 : CHECK(access_f3->Run(current.local()).IsEmpty());
9644 6 : }
9645 6 : }
9646 :
9647 :
9648 : static bool security_check_with_gc_called;
9649 :
9650 10 : static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9651 : Local<v8::Object> accessed_object,
9652 : Local<v8::Value> data) {
9653 10 : CcTest::CollectAllGarbage();
9654 10 : security_check_with_gc_called = true;
9655 10 : return true;
9656 : }
9657 :
9658 :
9659 25880 : TEST(SecurityTestGCAllowed) {
9660 5 : v8::Isolate* isolate = CcTest::isolate();
9661 5 : v8::HandleScope handle_scope(isolate);
9662 : v8::Local<v8::ObjectTemplate> object_template =
9663 5 : v8::ObjectTemplate::New(isolate);
9664 5 : object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9665 :
9666 5 : v8::Local<Context> context = Context::New(isolate);
9667 : v8::Context::Scope context_scope(context);
9668 :
9669 25 : CHECK(context->Global()
9670 : ->Set(context, v8_str("obj"),
9671 : object_template->NewInstance(context).ToLocalChecked())
9672 : .FromJust());
9673 :
9674 5 : security_check_with_gc_called = false;
9675 : CompileRun("obj[0] = new String(1002);");
9676 5 : CHECK(security_check_with_gc_called);
9677 :
9678 5 : security_check_with_gc_called = false;
9679 20 : CHECK(CompileRun("obj[0]")
9680 : ->ToString(context)
9681 : .ToLocalChecked()
9682 : ->Equals(context, v8_str("1002"))
9683 : .FromJust());
9684 10 : CHECK(security_check_with_gc_called);
9685 5 : }
9686 :
9687 :
9688 25881 : THREADED_TEST(CrossDomainDelete) {
9689 6 : LocalContext env1;
9690 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9691 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9692 :
9693 6 : Local<Value> foo = v8_str("foo");
9694 6 : Local<Value> bar = v8_str("bar");
9695 :
9696 : // Set to the same domain.
9697 6 : env1->SetSecurityToken(foo);
9698 6 : env2->SetSecurityToken(foo);
9699 :
9700 30 : CHECK(
9701 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9702 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9703 :
9704 : // Change env2 to a different domain and delete env1.prop.
9705 6 : env2->SetSecurityToken(bar);
9706 : {
9707 : Context::Scope scope_env2(env2);
9708 : Local<Value> result =
9709 : CompileRun("delete env1.prop");
9710 6 : CHECK(result.IsEmpty());
9711 : }
9712 :
9713 : // Check that env1.prop still exists.
9714 : Local<Value> v =
9715 30 : env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9716 6 : CHECK(v->IsNumber());
9717 18 : CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9718 6 : }
9719 :
9720 :
9721 25881 : THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9722 6 : LocalContext env1;
9723 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9724 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9725 :
9726 6 : Local<Value> foo = v8_str("foo");
9727 6 : Local<Value> bar = v8_str("bar");
9728 :
9729 : // Set to the same domain.
9730 6 : env1->SetSecurityToken(foo);
9731 6 : env2->SetSecurityToken(foo);
9732 :
9733 30 : CHECK(
9734 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9735 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9736 :
9737 : // env1.prop is enumerable in env2.
9738 6 : Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9739 : {
9740 : Context::Scope scope_env2(env2);
9741 6 : Local<Value> result = CompileRun(test);
9742 6 : CHECK(result->IsTrue());
9743 : }
9744 :
9745 : // Change env2 to a different domain and test again.
9746 6 : env2->SetSecurityToken(bar);
9747 : {
9748 : Context::Scope scope_env2(env2);
9749 6 : Local<Value> result = CompileRun(test);
9750 6 : CHECK(result.IsEmpty());
9751 6 : }
9752 6 : }
9753 :
9754 :
9755 25881 : THREADED_TEST(CrossDomainFor) {
9756 6 : LocalContext env1;
9757 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9758 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9759 :
9760 6 : Local<Value> foo = v8_str("foo");
9761 6 : Local<Value> bar = v8_str("bar");
9762 :
9763 : // Set to the same domain.
9764 6 : env1->SetSecurityToken(foo);
9765 6 : env2->SetSecurityToken(foo);
9766 :
9767 30 : CHECK(
9768 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9769 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9770 :
9771 : // Change env2 to a different domain and set env1's global object
9772 : // as the __proto__ of an object in env2 and enumerate properties
9773 : // in for-in. It shouldn't enumerate properties on env1's global
9774 : // object. It shouldn't throw either, just silently ignore them.
9775 6 : env2->SetSecurityToken(bar);
9776 : {
9777 : Context::Scope scope_env2(env2);
9778 : Local<Value> result = CompileRun(
9779 : "(function() {"
9780 : " try {"
9781 : " for (var p in env1) {"
9782 : " if (p == 'prop') return false;"
9783 : " }"
9784 : " return true;"
9785 : " } catch (e) {"
9786 : " return false;"
9787 : " }"
9788 : "})()");
9789 6 : CHECK(result->IsTrue());
9790 6 : }
9791 6 : }
9792 :
9793 :
9794 25881 : THREADED_TEST(CrossDomainForInOnPrototype) {
9795 6 : LocalContext env1;
9796 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9797 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9798 :
9799 6 : Local<Value> foo = v8_str("foo");
9800 6 : Local<Value> bar = v8_str("bar");
9801 :
9802 : // Set to the same domain.
9803 6 : env1->SetSecurityToken(foo);
9804 6 : env2->SetSecurityToken(foo);
9805 :
9806 30 : CHECK(
9807 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9808 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9809 :
9810 : // Change env2 to a different domain and set env1's global object
9811 : // as the __proto__ of an object in env2 and enumerate properties
9812 : // in for-in. It shouldn't enumerate properties on env1's global
9813 : // object.
9814 6 : env2->SetSecurityToken(bar);
9815 : {
9816 : Context::Scope scope_env2(env2);
9817 : Local<Value> result = CompileRun(
9818 : "(function() {"
9819 : " var obj = { '__proto__': env1 };"
9820 : " try {"
9821 : " for (var p in obj) {"
9822 : " if (p == 'prop') return false;"
9823 : " }"
9824 : " return true;"
9825 : " } catch (e) {"
9826 : " return false;"
9827 : " }"
9828 : "})()");
9829 6 : CHECK(result->IsTrue());
9830 6 : }
9831 6 : }
9832 :
9833 :
9834 25880 : TEST(ContextDetachGlobal) {
9835 5 : LocalContext env1;
9836 10 : v8::HandleScope handle_scope(env1->GetIsolate());
9837 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9838 :
9839 :
9840 5 : Local<Value> foo = v8_str("foo");
9841 :
9842 : // Set to the same domain.
9843 5 : env1->SetSecurityToken(foo);
9844 5 : env2->SetSecurityToken(foo);
9845 :
9846 : // Enter env2
9847 5 : env2->Enter();
9848 :
9849 : // Create a function in env2 and add a reference to it in env1.
9850 5 : Local<v8::Object> global2 = env2->Global();
9851 20 : CHECK(global2->Set(env2, v8_str("prop"),
9852 : v8::Integer::New(env2->GetIsolate(), 1))
9853 : .FromJust());
9854 : CompileRun("function getProp() {return prop;}");
9855 :
9856 35 : CHECK(env1->Global()
9857 : ->Set(env1.local(), v8_str("getProp"),
9858 : global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9859 : .FromJust());
9860 :
9861 : // Detach env2's global, and reuse the global object of env2
9862 5 : env2->Exit();
9863 5 : env2->DetachGlobal();
9864 :
9865 : v8::Local<Context> env3 = Context::New(
9866 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9867 10 : env3->SetSecurityToken(v8_str("bar"));
9868 :
9869 5 : env3->Enter();
9870 5 : Local<v8::Object> global3 = env3->Global();
9871 10 : CHECK(global2->Equals(env3, global3).FromJust());
9872 15 : CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9873 15 : CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9874 20 : CHECK(global3->Set(env3, v8_str("prop"),
9875 : v8::Integer::New(env3->GetIsolate(), -1))
9876 : .FromJust());
9877 20 : CHECK(global3->Set(env3, v8_str("prop2"),
9878 : v8::Integer::New(env3->GetIsolate(), 2))
9879 : .FromJust());
9880 5 : env3->Exit();
9881 :
9882 : // Call getProp in env1, and it should return the value 1
9883 : {
9884 5 : Local<v8::Object> global1 = env1->Global();
9885 : Local<Value> get_prop =
9886 20 : global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9887 5 : CHECK(get_prop->IsFunction());
9888 5 : v8::TryCatch try_catch(env1->GetIsolate());
9889 : Local<Value> r = Function::Cast(*get_prop)
9890 10 : ->Call(env1.local(), global1, 0, nullptr)
9891 5 : .ToLocalChecked();
9892 5 : CHECK(!try_catch.HasCaught());
9893 10 : CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9894 : }
9895 :
9896 : // Check that env3 is not accessible from env1
9897 : {
9898 10 : v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9899 5 : CHECK(r.IsEmpty());
9900 5 : }
9901 5 : }
9902 :
9903 :
9904 25880 : TEST(DetachGlobal) {
9905 5 : LocalContext env1;
9906 10 : v8::HandleScope scope(env1->GetIsolate());
9907 :
9908 : // Create second environment.
9909 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9910 :
9911 5 : Local<Value> foo = v8_str("foo");
9912 :
9913 : // Set same security token for env1 and env2.
9914 5 : env1->SetSecurityToken(foo);
9915 5 : env2->SetSecurityToken(foo);
9916 :
9917 : // Create a property on the global object in env2.
9918 : {
9919 : v8::Context::Scope scope(env2);
9920 25 : CHECK(env2->Global()
9921 : ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9922 : .FromJust());
9923 : }
9924 :
9925 : // Create a reference to env2 global from env1 global.
9926 30 : CHECK(env1->Global()
9927 : ->Set(env1.local(), v8_str("other"), env2->Global())
9928 : .FromJust());
9929 :
9930 : // Check that we have access to other.p in env2 from env1.
9931 : Local<Value> result = CompileRun("other.p");
9932 5 : CHECK(result->IsInt32());
9933 10 : CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9934 :
9935 : // Hold on to global from env2 and detach global from env2.
9936 5 : Local<v8::Object> global2 = env2->Global();
9937 5 : env2->DetachGlobal();
9938 :
9939 : // Check that the global has been detached. No other.p property can
9940 : // be found.
9941 : result = CompileRun("other.p");
9942 5 : CHECK(result.IsEmpty());
9943 :
9944 : // Reuse global2 for env3.
9945 : v8::Local<Context> env3 = Context::New(
9946 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9947 15 : CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9948 :
9949 : // Start by using the same security token for env3 as for env1 and env2.
9950 5 : env3->SetSecurityToken(foo);
9951 :
9952 : // Create a property on the global object in env3.
9953 : {
9954 : v8::Context::Scope scope(env3);
9955 25 : CHECK(env3->Global()
9956 : ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9957 : .FromJust());
9958 : }
9959 :
9960 : // Check that other.p is now the property in env3 and that we have access.
9961 : result = CompileRun("other.p");
9962 5 : CHECK(result->IsInt32());
9963 15 : CHECK_EQ(24, result->Int32Value(env3).FromJust());
9964 5 : }
9965 :
9966 :
9967 130 : void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9968 65 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9969 : info.GetReturnValue().Set(
9970 260 : context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9971 65 : }
9972 :
9973 :
9974 25880 : TEST(DetachedAccesses) {
9975 5 : LocalContext env1;
9976 10 : v8::HandleScope scope(env1->GetIsolate());
9977 :
9978 : // Create second environment.
9979 : Local<ObjectTemplate> inner_global_template =
9980 10 : FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9981 : inner_global_template ->SetAccessorProperty(
9982 10 : v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9983 : v8::Local<Context> env2 =
9984 5 : Context::New(env1->GetIsolate(), nullptr, inner_global_template);
9985 :
9986 5 : Local<Value> foo = v8_str("foo");
9987 :
9988 : // Set same security token for env1 and env2.
9989 5 : env1->SetSecurityToken(foo);
9990 5 : env2->SetSecurityToken(foo);
9991 :
9992 30 : CHECK(env1->Global()
9993 : ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
9994 : .FromJust());
9995 :
9996 : {
9997 : v8::Context::Scope scope(env2);
9998 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
9999 : CompileRun(
10000 : "function bound_x() { return x; }"
10001 : "function get_x() { return this.x; }"
10002 : "function get_x_w() { return (function() {return this.x;})(); }");
10003 25 : CHECK(env1->Global()
10004 : ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
10005 : .FromJust());
10006 25 : CHECK(env1->Global()
10007 : ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
10008 : .FromJust());
10009 25 : CHECK(env1->Global()
10010 : ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
10011 : .FromJust());
10012 : env1->Global()
10013 : ->Set(env1.local(), v8_str("this_x"),
10014 20 : CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
10015 10 : .FromJust();
10016 : }
10017 :
10018 5 : Local<Object> env2_global = env2->Global();
10019 5 : env2->DetachGlobal();
10020 :
10021 : Local<Value> result;
10022 : result = CompileRun("bound_x()");
10023 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10024 : result = CompileRun("get_x()");
10025 5 : CHECK(result.IsEmpty());
10026 : result = CompileRun("get_x_w()");
10027 5 : CHECK(result.IsEmpty());
10028 : result = CompileRun("this_x()");
10029 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10030 :
10031 : // Reattach env2's proxy
10032 : env2 = Context::New(env1->GetIsolate(), nullptr,
10033 5 : v8::Local<v8::ObjectTemplate>(), env2_global);
10034 5 : env2->SetSecurityToken(foo);
10035 : {
10036 : v8::Context::Scope scope(env2);
10037 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
10038 25 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
10039 : result = CompileRun(
10040 : "results = [];"
10041 : "for (var i = 0; i < 4; i++ ) {"
10042 : " results.push(env1.bound_x());"
10043 : " results.push(env1.get_x());"
10044 : " results.push(env1.get_x_w());"
10045 : " results.push(env1.this_x());"
10046 : "}"
10047 : "results");
10048 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10049 5 : CHECK_EQ(16u, results->Length());
10050 20 : for (int i = 0; i < 16; i += 4) {
10051 80 : CHECK(v8_str("env2_x")
10052 : ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
10053 : .FromJust());
10054 80 : CHECK(v8_str("env1_x")
10055 : ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
10056 : .FromJust());
10057 80 : CHECK(v8_str("env3_x")
10058 : ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
10059 : .FromJust());
10060 80 : CHECK(v8_str("env2_x")
10061 : ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
10062 : .FromJust());
10063 : }
10064 : }
10065 :
10066 : result = CompileRun(
10067 : "results = [];"
10068 : "for (var i = 0; i < 4; i++ ) {"
10069 : " results.push(bound_x());"
10070 : " results.push(get_x());"
10071 : " results.push(get_x_w());"
10072 : " results.push(this_x());"
10073 : "}"
10074 : "results");
10075 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10076 5 : CHECK_EQ(16u, results->Length());
10077 20 : for (int i = 0; i < 16; i += 4) {
10078 80 : CHECK(v8_str("env2_x")
10079 : ->Equals(env1.local(),
10080 : results->Get(env1.local(), i + 0).ToLocalChecked())
10081 : .FromJust());
10082 80 : CHECK(v8_str("env3_x")
10083 : ->Equals(env1.local(),
10084 : results->Get(env1.local(), i + 1).ToLocalChecked())
10085 : .FromJust());
10086 80 : CHECK(v8_str("env3_x")
10087 : ->Equals(env1.local(),
10088 : results->Get(env1.local(), i + 2).ToLocalChecked())
10089 : .FromJust());
10090 80 : CHECK(v8_str("env2_x")
10091 : ->Equals(env1.local(),
10092 : results->Get(env1.local(), i + 3).ToLocalChecked())
10093 : .FromJust());
10094 : }
10095 :
10096 : result = CompileRun(
10097 : "results = [];"
10098 : "for (var i = 0; i < 4; i++ ) {"
10099 : " results.push(this.bound_x());"
10100 : " results.push(this.get_x());"
10101 : " results.push(this.get_x_w());"
10102 : " results.push(this.this_x());"
10103 : "}"
10104 : "results");
10105 : results = Local<v8::Array>::Cast(result);
10106 5 : CHECK_EQ(16u, results->Length());
10107 20 : for (int i = 0; i < 16; i += 4) {
10108 80 : CHECK(v8_str("env2_x")
10109 : ->Equals(env1.local(),
10110 : results->Get(env1.local(), i + 0).ToLocalChecked())
10111 : .FromJust());
10112 80 : CHECK(v8_str("env1_x")
10113 : ->Equals(env1.local(),
10114 : results->Get(env1.local(), i + 1).ToLocalChecked())
10115 : .FromJust());
10116 80 : CHECK(v8_str("env3_x")
10117 : ->Equals(env1.local(),
10118 : results->Get(env1.local(), i + 2).ToLocalChecked())
10119 : .FromJust());
10120 80 : CHECK(v8_str("env2_x")
10121 : ->Equals(env1.local(),
10122 : results->Get(env1.local(), i + 3).ToLocalChecked())
10123 : .FromJust());
10124 5 : }
10125 5 : }
10126 :
10127 :
10128 : static bool allowed_access = false;
10129 370 : static bool AccessBlocker(Local<v8::Context> accessing_context,
10130 : Local<v8::Object> accessed_object,
10131 : Local<v8::Value> data) {
10132 370 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
10133 1110 : return context->Global()->Equals(context, accessed_object).FromJust() ||
10134 370 : allowed_access;
10135 : }
10136 :
10137 :
10138 : static int g_echo_value = -1;
10139 :
10140 :
10141 15 : static void EchoGetter(
10142 : Local<String> name,
10143 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10144 15 : info.GetReturnValue().Set(v8_num(g_echo_value));
10145 15 : }
10146 :
10147 :
10148 10 : static void EchoSetter(Local<String> name, Local<Value> value,
10149 : const v8::PropertyCallbackInfo<void>& args) {
10150 10 : if (value->IsNumber())
10151 : g_echo_value =
10152 20 : value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
10153 10 : }
10154 :
10155 :
10156 0 : static void UnreachableGetter(
10157 : Local<String> name,
10158 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10159 0 : UNREACHABLE(); // This function should not be called..
10160 : }
10161 :
10162 :
10163 0 : static void UnreachableSetter(Local<String>,
10164 : Local<Value>,
10165 : const v8::PropertyCallbackInfo<void>&) {
10166 0 : UNREACHABLE(); // This function should not be called.
10167 : }
10168 :
10169 :
10170 0 : static void UnreachableFunction(
10171 : const v8::FunctionCallbackInfo<v8::Value>& info) {
10172 0 : UNREACHABLE(); // This function should not be called..
10173 : }
10174 :
10175 :
10176 25880 : TEST(AccessControl) {
10177 5 : v8::Isolate* isolate = CcTest::isolate();
10178 5 : v8::HandleScope handle_scope(isolate);
10179 : v8::Local<v8::ObjectTemplate> global_template =
10180 5 : v8::ObjectTemplate::New(isolate);
10181 :
10182 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10183 :
10184 : // Add an accessor accessible by cross-domain JS code.
10185 : global_template->SetAccessor(
10186 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10187 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10188 :
10189 :
10190 : // Add an accessor that is not accessible by cross-domain JS code.
10191 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10192 : UnreachableSetter, v8::Local<Value>(),
10193 5 : v8::DEFAULT);
10194 :
10195 : global_template->SetAccessorProperty(
10196 : v8_str("blocked_js_prop"),
10197 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10198 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10199 : v8::None,
10200 15 : v8::DEFAULT);
10201 :
10202 : // Create an environment
10203 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10204 5 : context0->Enter();
10205 :
10206 5 : v8::Local<v8::Object> global0 = context0->Global();
10207 :
10208 : // Define a property with JS getter and setter.
10209 : CompileRun(
10210 : "function getter() { return 'getter'; };\n"
10211 : "function setter() { return 'setter'; }\n"
10212 : "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
10213 :
10214 : Local<Value> getter =
10215 15 : global0->Get(context0, v8_str("getter")).ToLocalChecked();
10216 : Local<Value> setter =
10217 15 : global0->Get(context0, v8_str("setter")).ToLocalChecked();
10218 :
10219 : // And define normal element.
10220 15 : CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
10221 :
10222 : // Define an element with JS getter and setter.
10223 : CompileRun(
10224 : "function el_getter() { return 'el_getter'; };\n"
10225 : "function el_setter() { return 'el_setter'; };\n"
10226 : "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
10227 :
10228 : Local<Value> el_getter =
10229 15 : global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
10230 : Local<Value> el_setter =
10231 15 : global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
10232 :
10233 10 : v8::HandleScope scope1(isolate);
10234 :
10235 5 : v8::Local<Context> context1 = Context::New(isolate);
10236 5 : context1->Enter();
10237 :
10238 5 : v8::Local<v8::Object> global1 = context1->Global();
10239 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10240 :
10241 : // Access blocked property.
10242 : CompileRun("other.blocked_prop = 1");
10243 :
10244 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10245 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10246 : .IsEmpty());
10247 5 : CHECK(
10248 : CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
10249 :
10250 : // Access blocked element.
10251 5 : CHECK(CompileRun("other[239] = 1").IsEmpty());
10252 :
10253 5 : CHECK(CompileRun("other[239]").IsEmpty());
10254 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10255 5 : CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10256 :
10257 5 : allowed_access = true;
10258 : // Now we can enumerate the property.
10259 : ExpectTrue("propertyIsEnumerable.call(other, '239')");
10260 5 : allowed_access = false;
10261 :
10262 : // Access a property with JS accessor.
10263 5 : CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10264 :
10265 5 : CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10266 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10267 : .IsEmpty());
10268 :
10269 5 : allowed_access = true;
10270 :
10271 5 : ExpectString("other.js_accessor_p", "getter");
10272 : ExpectObject(
10273 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10274 : ExpectObject(
10275 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10276 : ExpectUndefined(
10277 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10278 :
10279 5 : allowed_access = false;
10280 :
10281 : // Access an element with JS accessor.
10282 5 : CHECK(CompileRun("other[42] = 2").IsEmpty());
10283 :
10284 5 : CHECK(CompileRun("other[42]").IsEmpty());
10285 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10286 :
10287 5 : allowed_access = true;
10288 :
10289 5 : ExpectString("other[42]", "el_getter");
10290 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10291 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10292 5 : ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10293 :
10294 5 : allowed_access = false;
10295 :
10296 : v8::Local<Value> value;
10297 :
10298 : // Access accessible property
10299 : value = CompileRun("other.accessible_prop = 3");
10300 5 : CHECK(value->IsNumber());
10301 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10302 5 : CHECK_EQ(3, g_echo_value);
10303 :
10304 : value = CompileRun("other.accessible_prop");
10305 5 : CHECK(value->IsNumber());
10306 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10307 :
10308 : value = CompileRun(
10309 : "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10310 5 : CHECK(value->IsNumber());
10311 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10312 :
10313 : value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10314 5 : CHECK(value->IsTrue());
10315 :
10316 : // Enumeration doesn't enumerate accessors from inaccessible objects in
10317 : // the prototype chain even if the accessors are in themselves accessible.
10318 : // Enumeration doesn't throw, it silently ignores what it can't access.
10319 : value = CompileRun(
10320 : "(function() {"
10321 : " var obj = { '__proto__': other };"
10322 : " try {"
10323 : " for (var p in obj) {"
10324 : " if (p == 'accessible_prop' ||"
10325 : " p == 'blocked_js_prop' ||"
10326 : " p == 'blocked_js_prop') {"
10327 : " return false;"
10328 : " }"
10329 : " }"
10330 : " return true;"
10331 : " } catch (e) {"
10332 : " return false;"
10333 : " }"
10334 : "})()");
10335 5 : CHECK(value->IsTrue());
10336 :
10337 : // Test that preventExtensions fails on a non-accessible object even if that
10338 : // object is already non-extensible.
10339 20 : CHECK(global1->Set(context1, v8_str("checked_object"),
10340 : global_template->NewInstance(context1).ToLocalChecked())
10341 : .FromJust());
10342 5 : allowed_access = true;
10343 : CompileRun("Object.preventExtensions(checked_object)");
10344 : ExpectFalse("Object.isExtensible(checked_object)");
10345 5 : allowed_access = false;
10346 5 : CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10347 :
10348 5 : context1->Exit();
10349 10 : context0->Exit();
10350 5 : }
10351 :
10352 :
10353 25880 : TEST(AccessControlES5) {
10354 5 : v8::Isolate* isolate = CcTest::isolate();
10355 5 : v8::HandleScope handle_scope(isolate);
10356 : v8::Local<v8::ObjectTemplate> global_template =
10357 5 : v8::ObjectTemplate::New(isolate);
10358 :
10359 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10360 :
10361 : // Add accessible accessor.
10362 : global_template->SetAccessor(
10363 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10364 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10365 :
10366 :
10367 : // Add an accessor that is not accessible by cross-domain JS code.
10368 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10369 : UnreachableSetter, v8::Local<Value>(),
10370 5 : v8::DEFAULT);
10371 :
10372 : // Create an environment
10373 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10374 5 : context0->Enter();
10375 :
10376 5 : v8::Local<v8::Object> global0 = context0->Global();
10377 :
10378 5 : v8::Local<Context> context1 = Context::New(isolate);
10379 5 : context1->Enter();
10380 5 : v8::Local<v8::Object> global1 = context1->Global();
10381 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10382 :
10383 : // Regression test for issue 1154.
10384 5 : CHECK(CompileRun("Object.keys(other).length == 1")->BooleanValue(isolate));
10385 5 : CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10386 : ->BooleanValue(isolate));
10387 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10388 :
10389 : // Regression test for issue 1027.
10390 : CompileRun("Object.defineProperty(\n"
10391 : " other, 'blocked_prop', {configurable: false})");
10392 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10393 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10394 : .IsEmpty());
10395 :
10396 : // Regression test for issue 1171.
10397 : ExpectTrue("Object.isExtensible(other)");
10398 : CompileRun("Object.preventExtensions(other)");
10399 : ExpectTrue("Object.isExtensible(other)");
10400 :
10401 : // Object.seal and Object.freeze.
10402 : CompileRun("Object.freeze(other)");
10403 : ExpectTrue("Object.isExtensible(other)");
10404 :
10405 : CompileRun("Object.seal(other)");
10406 : ExpectTrue("Object.isExtensible(other)");
10407 :
10408 : // Regression test for issue 1250.
10409 : // Make sure that we can set the accessible accessors value using normal
10410 : // assignment.
10411 : CompileRun("other.accessible_prop = 42");
10412 5 : CHECK_EQ(42, g_echo_value);
10413 :
10414 : // [[DefineOwnProperty]] always throws for access-checked objects.
10415 5 : CHECK(
10416 : CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10417 : .IsEmpty());
10418 5 : CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10419 5 : CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10420 5 : }
10421 :
10422 229 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10423 : Local<v8::Object> global,
10424 : Local<v8::Value> data) {
10425 229 : i::PrintF("Access blocked.\n");
10426 229 : return false;
10427 : }
10428 :
10429 5 : static bool AccessAlwaysAllowed(Local<v8::Context> accessing_context,
10430 : Local<v8::Object> global,
10431 : Local<v8::Value> data) {
10432 5 : i::PrintF("Access allowed.\n");
10433 5 : return true;
10434 : }
10435 :
10436 25881 : THREADED_TEST(AccessControlGetOwnPropertyNames) {
10437 6 : v8::Isolate* isolate = CcTest::isolate();
10438 6 : v8::HandleScope handle_scope(isolate);
10439 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10440 :
10441 18 : obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10442 6 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10443 :
10444 : // Add an accessor accessible by cross-domain JS code.
10445 : obj_template->SetAccessor(
10446 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10447 6 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10448 :
10449 : // Create an environment
10450 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
10451 6 : context0->Enter();
10452 :
10453 6 : v8::Local<v8::Object> global0 = context0->Global();
10454 :
10455 12 : v8::HandleScope scope1(CcTest::isolate());
10456 :
10457 6 : v8::Local<Context> context1 = Context::New(isolate);
10458 6 : context1->Enter();
10459 :
10460 6 : v8::Local<v8::Object> global1 = context1->Global();
10461 18 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10462 24 : CHECK(global1->Set(context1, v8_str("object"),
10463 : obj_template->NewInstance(context1).ToLocalChecked())
10464 : .FromJust());
10465 :
10466 : v8::Local<Value> value;
10467 :
10468 : // Attempt to get the property names of the other global object and
10469 : // of an object that requires access checks. Accessing the other
10470 : // global object should be blocked by access checks on the global
10471 : // proxy object. Accessing the object that requires access checks
10472 : // is blocked by the access checks on the object itself.
10473 : value = CompileRun(
10474 : "var names = Object.getOwnPropertyNames(other);"
10475 : "names.length == 1 && names[0] == 'accessible_prop';");
10476 6 : CHECK(value->BooleanValue(isolate));
10477 :
10478 : value = CompileRun(
10479 : "var names = Object.getOwnPropertyNames(object);"
10480 : "names.length == 1 && names[0] == 'accessible_prop';");
10481 6 : CHECK(value->BooleanValue(isolate));
10482 :
10483 6 : context1->Exit();
10484 12 : context0->Exit();
10485 6 : }
10486 :
10487 :
10488 25880 : TEST(Regress470113) {
10489 5 : v8::Isolate* isolate = CcTest::isolate();
10490 5 : v8::HandleScope handle_scope(isolate);
10491 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10492 5 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10493 10 : LocalContext env;
10494 30 : CHECK(env->Global()
10495 : ->Set(env.local(), v8_str("prohibited"),
10496 : obj_template->NewInstance(env.local()).ToLocalChecked())
10497 : .FromJust());
10498 :
10499 : {
10500 5 : v8::TryCatch try_catch(isolate);
10501 : CompileRun(
10502 : "'use strict';\n"
10503 : "class C extends Object {\n"
10504 : " m() { super.powned = 'Powned!'; }\n"
10505 : "}\n"
10506 : "let c = new C();\n"
10507 : "c.m.call(prohibited)");
10508 :
10509 5 : CHECK(try_catch.HasCaught());
10510 5 : }
10511 5 : }
10512 :
10513 :
10514 6 : static void ConstTenGetter(Local<String> name,
10515 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10516 6 : info.GetReturnValue().Set(v8_num(10));
10517 6 : }
10518 :
10519 :
10520 25881 : THREADED_TEST(CrossDomainAccessors) {
10521 6 : v8::Isolate* isolate = CcTest::isolate();
10522 6 : v8::HandleScope handle_scope(isolate);
10523 :
10524 : v8::Local<v8::FunctionTemplate> func_template =
10525 6 : v8::FunctionTemplate::New(isolate);
10526 :
10527 : v8::Local<v8::ObjectTemplate> global_template =
10528 6 : func_template->InstanceTemplate();
10529 :
10530 : v8::Local<v8::ObjectTemplate> proto_template =
10531 6 : func_template->PrototypeTemplate();
10532 :
10533 : // Add an accessor to proto that's accessible by cross-domain JS code.
10534 : proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, nullptr,
10535 12 : v8::Local<Value>(), v8::ALL_CAN_READ);
10536 :
10537 : // Add an accessor that is not accessible by cross-domain JS code.
10538 : global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter,
10539 12 : nullptr, v8::Local<Value>(), v8::DEFAULT);
10540 :
10541 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10542 6 : context0->Enter();
10543 :
10544 6 : Local<v8::Object> global = context0->Global();
10545 : // Add a normal property that shadows 'accessible'
10546 18 : CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10547 :
10548 : // Enter a new context.
10549 12 : v8::HandleScope scope1(CcTest::isolate());
10550 6 : v8::Local<Context> context1 = Context::New(isolate);
10551 6 : context1->Enter();
10552 :
10553 6 : v8::Local<v8::Object> global1 = context1->Global();
10554 18 : CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10555 :
10556 : // Should return 10, instead of 11
10557 : v8::Local<Value> value =
10558 6 : v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10559 6 : CHECK(value->IsNumber());
10560 12 : CHECK_EQ(10, value->Int32Value(context1).FromJust());
10561 :
10562 : v8::MaybeLocal<v8::Value> maybe_value =
10563 6 : v8_compile("other.unreachable")->Run(context1);
10564 6 : CHECK(maybe_value.IsEmpty());
10565 :
10566 6 : context1->Exit();
10567 12 : context0->Exit();
10568 6 : }
10569 :
10570 :
10571 : static int access_count = 0;
10572 :
10573 820 : static bool AccessCounter(Local<v8::Context> accessing_context,
10574 : Local<v8::Object> accessed_object,
10575 : Local<v8::Value> data) {
10576 820 : access_count++;
10577 820 : return true;
10578 : }
10579 :
10580 :
10581 : // This one is too easily disturbed by other tests.
10582 25880 : TEST(AccessControlIC) {
10583 5 : access_count = 0;
10584 :
10585 5 : v8::Isolate* isolate = CcTest::isolate();
10586 5 : v8::HandleScope handle_scope(isolate);
10587 :
10588 : // Create an environment.
10589 5 : v8::Local<Context> context0 = Context::New(isolate);
10590 5 : context0->Enter();
10591 :
10592 : // Create an object that requires access-check functions to be
10593 : // called for cross-domain access.
10594 : v8::Local<v8::ObjectTemplate> object_template =
10595 5 : v8::ObjectTemplate::New(isolate);
10596 5 : object_template->SetAccessCheckCallback(AccessCounter);
10597 : Local<v8::Object> object =
10598 5 : object_template->NewInstance(context0).ToLocalChecked();
10599 :
10600 10 : v8::HandleScope scope1(isolate);
10601 :
10602 : // Create another environment.
10603 5 : v8::Local<Context> context1 = Context::New(isolate);
10604 5 : context1->Enter();
10605 :
10606 : // Make easy access to the object from the other environment.
10607 5 : v8::Local<v8::Object> global1 = context1->Global();
10608 15 : CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10609 :
10610 : v8::Local<Value> value;
10611 :
10612 : // Check that the named access-control function is called every time.
10613 : CompileRun("function testProp(obj) {"
10614 : " for (var i = 0; i < 10; i++) obj.prop = 1;"
10615 : " for (var j = 0; j < 10; j++) obj.prop;"
10616 : " return obj.prop"
10617 : "}");
10618 : value = CompileRun("testProp(obj)");
10619 5 : CHECK(value->IsNumber());
10620 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10621 5 : CHECK_EQ(21, access_count);
10622 :
10623 : // Check that the named access-control function is called every time.
10624 : CompileRun("var p = 'prop';"
10625 : "function testKeyed(obj) {"
10626 : " for (var i = 0; i < 10; i++) obj[p] = 1;"
10627 : " for (var j = 0; j < 10; j++) obj[p];"
10628 : " return obj[p];"
10629 : "}");
10630 : // Use obj which requires access checks. No inline caching is used
10631 : // in that case.
10632 : value = CompileRun("testKeyed(obj)");
10633 5 : CHECK(value->IsNumber());
10634 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10635 5 : CHECK_EQ(42, access_count);
10636 : // Force the inline caches into generic state and try again.
10637 : CompileRun("testKeyed({ a: 0 })");
10638 : CompileRun("testKeyed({ b: 0 })");
10639 : value = CompileRun("testKeyed(obj)");
10640 5 : CHECK(value->IsNumber());
10641 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10642 5 : CHECK_EQ(63, access_count);
10643 :
10644 : // Check that the indexed access-control function is called every time.
10645 5 : access_count = 0;
10646 :
10647 : CompileRun("function testIndexed(obj) {"
10648 : " for (var i = 0; i < 10; i++) obj[0] = 1;"
10649 : " for (var j = 0; j < 10; j++) obj[0];"
10650 : " return obj[0]"
10651 : "}");
10652 : value = CompileRun("testIndexed(obj)");
10653 5 : CHECK(value->IsNumber());
10654 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10655 5 : CHECK_EQ(21, access_count);
10656 : // Force the inline caches into generic state.
10657 : CompileRun("testIndexed(new Array(1))");
10658 : // Test that the indexed access check is called.
10659 : value = CompileRun("testIndexed(obj)");
10660 5 : CHECK(value->IsNumber());
10661 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10662 5 : CHECK_EQ(42, access_count);
10663 :
10664 5 : access_count = 0;
10665 : // Check that the named access check is called when invoking
10666 : // functions on an object that requires access checks.
10667 : CompileRun("obj.f = function() {}");
10668 : CompileRun("function testCallNormal(obj) {"
10669 : " for (var i = 0; i < 10; i++) obj.f();"
10670 : "}");
10671 : CompileRun("testCallNormal(obj)");
10672 5 : printf("%i\n", access_count);
10673 5 : CHECK_EQ(11, access_count);
10674 :
10675 : // Force obj into slow case.
10676 : value = CompileRun("delete obj.prop");
10677 5 : CHECK(value->BooleanValue(isolate));
10678 : // Force inline caches into dictionary probing mode.
10679 : CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10680 : // Test that the named access check is called.
10681 : value = CompileRun("testProp(obj);");
10682 5 : CHECK(value->IsNumber());
10683 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10684 5 : CHECK_EQ(33, access_count);
10685 :
10686 : // Force the call inline cache into dictionary probing mode.
10687 : CompileRun("o.f = function() {}; testCallNormal(o)");
10688 : // Test that the named access check is still called for each
10689 : // invocation of the function.
10690 : value = CompileRun("testCallNormal(obj)");
10691 5 : CHECK_EQ(43, access_count);
10692 :
10693 5 : context1->Exit();
10694 10 : context0->Exit();
10695 5 : }
10696 :
10697 :
10698 25881 : THREADED_TEST(Version) { v8::V8::GetVersion(); }
10699 :
10700 :
10701 18 : static void InstanceFunctionCallback(
10702 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10703 18 : ApiTestFuzzer::Fuzz();
10704 18 : args.GetReturnValue().Set(v8_num(12));
10705 18 : }
10706 :
10707 :
10708 25881 : THREADED_TEST(InstanceProperties) {
10709 6 : LocalContext context;
10710 6 : v8::Isolate* isolate = context->GetIsolate();
10711 12 : v8::HandleScope handle_scope(isolate);
10712 :
10713 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10714 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10715 :
10716 18 : instance->Set(v8_str("x"), v8_num(42));
10717 : instance->Set(v8_str("f"),
10718 18 : v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10719 :
10720 6 : Local<Value> o = t->GetFunction(context.local())
10721 6 : .ToLocalChecked()
10722 6 : ->NewInstance(context.local())
10723 : .ToLocalChecked();
10724 :
10725 30 : CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10726 : Local<Value> value = CompileRun("i.x");
10727 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10728 :
10729 : value = CompileRun("i.f()");
10730 18 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10731 6 : }
10732 :
10733 :
10734 696 : static void GlobalObjectInstancePropertiesGet(
10735 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10736 696 : ApiTestFuzzer::Fuzz();
10737 696 : }
10738 :
10739 :
10740 25881 : THREADED_TEST(GlobalObjectInstanceProperties) {
10741 6 : v8::Isolate* isolate = CcTest::isolate();
10742 6 : v8::HandleScope handle_scope(isolate);
10743 :
10744 : Local<Value> global_object;
10745 :
10746 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10747 : t->InstanceTemplate()->SetHandler(
10748 12 : v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10749 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10750 18 : instance_template->Set(v8_str("x"), v8_num(42));
10751 : instance_template->Set(v8_str("f"),
10752 : v8::FunctionTemplate::New(isolate,
10753 18 : InstanceFunctionCallback));
10754 :
10755 : // The script to check how TurboFan compiles missing global function
10756 : // invocations. function g is not defined and should throw on call.
10757 : const char* script =
10758 : "function wrapper(call) {"
10759 : " var x = 0, y = 1;"
10760 : " for (var i = 0; i < 1000; i++) {"
10761 : " x += i * 100;"
10762 : " y += i * 100;"
10763 : " }"
10764 : " if (call) g();"
10765 : "}"
10766 : "for (var i = 0; i < 17; i++) wrapper(false);"
10767 : "var thrown = 0;"
10768 : "try { wrapper(true); } catch (e) { thrown = 1; };"
10769 : "thrown";
10770 :
10771 : {
10772 6 : LocalContext env(nullptr, instance_template);
10773 : // Hold on to the global object so it can be used again in another
10774 : // environment initialization.
10775 6 : global_object = env->Global();
10776 :
10777 : Local<Value> value = CompileRun("x");
10778 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10779 : value = CompileRun("f()");
10780 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10781 : value = CompileRun(script);
10782 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10783 : }
10784 :
10785 : {
10786 : // Create new environment reusing the global object.
10787 6 : LocalContext env(nullptr, instance_template, global_object);
10788 : Local<Value> value = CompileRun("x");
10789 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10790 : value = CompileRun("f()");
10791 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10792 : value = CompileRun(script);
10793 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10794 6 : }
10795 6 : }
10796 :
10797 25881 : THREADED_TEST(ObjectGetOwnPropertyNames) {
10798 6 : LocalContext context;
10799 6 : v8::Isolate* isolate = context->GetIsolate();
10800 12 : v8::HandleScope handle_scope(isolate);
10801 :
10802 : v8::Local<v8::Object> value = v8::Local<v8::Object>::Cast(
10803 6 : v8::StringObject::New(CcTest::isolate(), v8_str("test")));
10804 : v8::Local<v8::Array> properties;
10805 :
10806 12 : CHECK(value
10807 : ->GetOwnPropertyNames(context.local(),
10808 : static_cast<v8::PropertyFilter>(
10809 : v8::PropertyFilter::ALL_PROPERTIES |
10810 : v8::PropertyFilter::SKIP_SYMBOLS),
10811 : v8::KeyConversionMode::kKeepNumbers)
10812 : .ToLocal(&properties));
10813 6 : CHECK_EQ(5u, properties->Length());
10814 : v8::Local<v8::Value> property;
10815 18 : CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10816 : property->IsString());
10817 18 : CHECK(property.As<v8::String>()
10818 : ->Equals(context.local(), v8_str("length"))
10819 : .FromMaybe(false));
10820 24 : for (int i = 0; i < 4; ++i) {
10821 : v8::Local<v8::Value> property;
10822 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10823 : property->IsInt32());
10824 24 : CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10825 : }
10826 :
10827 12 : CHECK(value
10828 : ->GetOwnPropertyNames(context.local(),
10829 : v8::PropertyFilter::ONLY_ENUMERABLE,
10830 : v8::KeyConversionMode::kKeepNumbers)
10831 : .ToLocal(&properties));
10832 : v8::Local<v8::Array> number_properties;
10833 12 : CHECK(value
10834 : ->GetOwnPropertyNames(context.local(),
10835 : v8::PropertyFilter::ONLY_ENUMERABLE,
10836 : v8::KeyConversionMode::kConvertToString)
10837 : .ToLocal(&number_properties));
10838 6 : CHECK_EQ(4u, properties->Length());
10839 24 : for (int i = 0; i < 4; ++i) {
10840 : v8::Local<v8::Value> property_index;
10841 : v8::Local<v8::Value> property_name;
10842 :
10843 48 : CHECK(number_properties->Get(context.local(), i).ToLocal(&property_name));
10844 24 : CHECK(property_name->IsString());
10845 :
10846 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property_index));
10847 24 : CHECK(property_index->IsInt32());
10848 :
10849 24 : CHECK_EQ(property_index.As<v8::Int32>()->Value(), i);
10850 48 : CHECK_EQ(property_name->ToNumber(context.local())
10851 : .ToLocalChecked()
10852 : .As<v8::Int32>()
10853 : ->Value(),
10854 : i);
10855 : }
10856 :
10857 6 : value = value->GetPrototype().As<v8::Object>();
10858 12 : CHECK(value
10859 : ->GetOwnPropertyNames(context.local(),
10860 : static_cast<v8::PropertyFilter>(
10861 : v8::PropertyFilter::ALL_PROPERTIES |
10862 : v8::PropertyFilter::SKIP_SYMBOLS))
10863 : .ToLocal(&properties));
10864 : bool concat_found = false;
10865 : bool starts_with_found = false;
10866 288 : for (uint32_t i = 0; i < properties->Length(); ++i) {
10867 : v8::Local<v8::Value> property;
10868 576 : CHECK(properties->Get(context.local(), i).ToLocal(&property));
10869 288 : if (!property->IsString()) continue;
10870 288 : if (!concat_found)
10871 : concat_found = property.As<v8::String>()
10872 180 : ->Equals(context.local(), v8_str("concat"))
10873 120 : .FromMaybe(false);
10874 288 : if (!starts_with_found)
10875 : starts_with_found = property.As<v8::String>()
10876 648 : ->Equals(context.local(), v8_str("startsWith"))
10877 432 : .FromMaybe(false);
10878 : }
10879 12 : CHECK(concat_found && starts_with_found);
10880 6 : }
10881 :
10882 25881 : THREADED_TEST(CallKnownGlobalReceiver) {
10883 6 : v8::Isolate* isolate = CcTest::isolate();
10884 6 : v8::HandleScope handle_scope(isolate);
10885 :
10886 : Local<Value> global_object;
10887 :
10888 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10889 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10890 :
10891 : // The script to check that we leave global object not
10892 : // global object proxy on stack when we deoptimize from inside
10893 : // arguments evaluation.
10894 : // To provoke error we need to both force deoptimization
10895 : // from arguments evaluation and to force CallIC to take
10896 : // CallIC_Miss code path that can't cope with global proxy.
10897 : const char* script =
10898 : "function bar(x, y) { try { } finally { } }"
10899 : "function baz(x) { try { } finally { } }"
10900 : "function bom(x) { try { } finally { } }"
10901 : "function foo(x) { bar([x], bom(2)); }"
10902 : "for (var i = 0; i < 10000; i++) foo(1);"
10903 : "foo";
10904 :
10905 : Local<Value> foo;
10906 : {
10907 6 : LocalContext env(nullptr, instance_template);
10908 : // Hold on to the global object so it can be used again in another
10909 : // environment initialization.
10910 6 : global_object = env->Global();
10911 6 : foo = CompileRun(script);
10912 : }
10913 :
10914 : {
10915 : // Create new environment reusing the global object.
10916 6 : LocalContext env(nullptr, instance_template, global_object);
10917 30 : CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10918 6 : CompileRun("foo()");
10919 6 : }
10920 6 : }
10921 :
10922 :
10923 6 : static void ShadowFunctionCallback(
10924 6 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10925 6 : ApiTestFuzzer::Fuzz();
10926 6 : args.GetReturnValue().Set(v8_num(42));
10927 6 : }
10928 :
10929 :
10930 : static int shadow_y;
10931 : static int shadow_y_setter_call_count;
10932 : static int shadow_y_getter_call_count;
10933 :
10934 :
10935 6 : static void ShadowYSetter(Local<String>,
10936 : Local<Value>,
10937 : const v8::PropertyCallbackInfo<void>&) {
10938 6 : shadow_y_setter_call_count++;
10939 6 : shadow_y = 42;
10940 6 : }
10941 :
10942 :
10943 6 : static void ShadowYGetter(Local<String> name,
10944 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10945 6 : ApiTestFuzzer::Fuzz();
10946 6 : shadow_y_getter_call_count++;
10947 6 : info.GetReturnValue().Set(v8_num(shadow_y));
10948 6 : }
10949 :
10950 :
10951 0 : static void ShadowIndexedGet(uint32_t index,
10952 : const v8::PropertyCallbackInfo<v8::Value>&) {
10953 0 : }
10954 :
10955 :
10956 42 : static void ShadowNamedGet(Local<Name> key,
10957 42 : const v8::PropertyCallbackInfo<v8::Value>&) {}
10958 :
10959 25881 : THREADED_TEST(ShadowObject) {
10960 6 : shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10961 6 : v8::Isolate* isolate = CcTest::isolate();
10962 6 : v8::HandleScope handle_scope(isolate);
10963 :
10964 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10965 12 : LocalContext context(nullptr, global_template);
10966 :
10967 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10968 : t->InstanceTemplate()->SetHandler(
10969 12 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10970 : t->InstanceTemplate()->SetHandler(
10971 12 : v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10972 6 : Local<ObjectTemplate> proto = t->PrototypeTemplate();
10973 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10974 :
10975 : proto->Set(v8_str("f"),
10976 : v8::FunctionTemplate::New(isolate,
10977 : ShadowFunctionCallback,
10978 18 : Local<Value>()));
10979 18 : proto->Set(v8_str("x"), v8_num(12));
10980 :
10981 12 : instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10982 :
10983 6 : Local<Value> o = t->GetFunction(context.local())
10984 6 : .ToLocalChecked()
10985 6 : ->NewInstance(context.local())
10986 : .ToLocalChecked();
10987 30 : CHECK(context->Global()
10988 : ->Set(context.local(), v8_str("__proto__"), o)
10989 : .FromJust());
10990 :
10991 : Local<Value> value =
10992 : CompileRun("this.propertyIsEnumerable(0)");
10993 6 : CHECK(value->IsBoolean());
10994 6 : CHECK(!value->BooleanValue(isolate));
10995 :
10996 : value = CompileRun("x");
10997 12 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10998 :
10999 : value = CompileRun("f()");
11000 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11001 :
11002 : CompileRun("y = 43");
11003 6 : CHECK_EQ(1, shadow_y_setter_call_count);
11004 : value = CompileRun("y");
11005 6 : CHECK_EQ(1, shadow_y_getter_call_count);
11006 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11007 6 : }
11008 :
11009 25881 : THREADED_TEST(ShadowObjectAndDataProperty) {
11010 : // Lite mode doesn't make use of feedback vectors, which is what we
11011 : // want to ensure has the correct form.
11012 6 : if (i::FLAG_lite_mode) return;
11013 : // This test mimics the kind of shadow property the Chromium embedder
11014 : // uses for undeclared globals. The IC subsystem has special handling
11015 : // for this case, using a PREMONOMORPHIC state to delay entering
11016 : // MONOMORPHIC state until enough information is available to support
11017 : // efficient access and good feedback for optimization.
11018 6 : v8::Isolate* isolate = CcTest::isolate();
11019 6 : v8::HandleScope handle_scope(isolate);
11020 :
11021 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11022 12 : LocalContext context(nullptr, global_template);
11023 :
11024 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11025 : t->InstanceTemplate()->SetHandler(
11026 12 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11027 :
11028 6 : Local<Value> o = t->GetFunction(context.local())
11029 6 : .ToLocalChecked()
11030 6 : ->NewInstance(context.local())
11031 : .ToLocalChecked();
11032 30 : CHECK(context->Global()
11033 : ->Set(context.local(), v8_str("__proto__"), o)
11034 : .FromJust());
11035 :
11036 : CompileRun(
11037 : "function foo(x) { i = x; }"
11038 : "foo(0)");
11039 :
11040 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11041 : v8::Utils::OpenHandle(*context->Global()
11042 24 : ->Get(context.local(), v8_str("foo"))
11043 12 : .ToLocalChecked())));
11044 6 : CHECK(foo->has_feedback_vector());
11045 : i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11046 12 : i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11047 6 : CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11048 6 : CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11049 : CompileRun("foo(1)");
11050 6 : CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11051 : // We go a bit further, checking that the form of monomorphism is
11052 : // a PropertyCell in the vector. This is because we want to make sure
11053 : // we didn't settle for a "poor man's monomorphism," such as a
11054 : // slow_stub bailout which would mean a trip to the runtime on all
11055 : // subsequent stores, and a lack of feedback for the optimizing
11056 : // compiler downstream.
11057 6 : i::HeapObject heap_object;
11058 6 : CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11059 12 : CHECK(heap_object->IsPropertyCell());
11060 : }
11061 :
11062 25881 : THREADED_TEST(ShadowObjectAndDataPropertyTurbo) {
11063 : // This test is the same as the previous one except that it triggers
11064 : // optimization of {foo} after its first invocation.
11065 6 : i::FLAG_allow_natives_syntax = true;
11066 :
11067 6 : if (i::FLAG_lite_mode) return;
11068 6 : v8::Isolate* isolate = CcTest::isolate();
11069 6 : v8::HandleScope handle_scope(isolate);
11070 :
11071 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11072 12 : LocalContext context(nullptr, global_template);
11073 :
11074 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11075 : t->InstanceTemplate()->SetHandler(
11076 12 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11077 :
11078 6 : Local<Value> o = t->GetFunction(context.local())
11079 6 : .ToLocalChecked()
11080 6 : ->NewInstance(context.local())
11081 : .ToLocalChecked();
11082 30 : CHECK(context->Global()
11083 : ->Set(context.local(), v8_str("__proto__"), o)
11084 : .FromJust());
11085 :
11086 : CompileRun(
11087 : "function foo(x) { i = x; }"
11088 : "foo(0)");
11089 :
11090 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11091 : v8::Utils::OpenHandle(*context->Global()
11092 24 : ->Get(context.local(), v8_str("foo"))
11093 12 : .ToLocalChecked())));
11094 6 : CHECK(foo->has_feedback_vector());
11095 : i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11096 12 : i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11097 6 : CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11098 6 : CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11099 : CompileRun("%OptimizeFunctionOnNextCall(foo); foo(1)");
11100 6 : CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11101 6 : i::HeapObject heap_object;
11102 6 : CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11103 12 : CHECK(heap_object->IsPropertyCell());
11104 : }
11105 :
11106 25881 : THREADED_TEST(SetPrototype) {
11107 6 : LocalContext context;
11108 6 : v8::Isolate* isolate = context->GetIsolate();
11109 12 : v8::HandleScope handle_scope(isolate);
11110 :
11111 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11112 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11113 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11114 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11115 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11116 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11117 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11118 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11119 :
11120 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
11121 6 : .ToLocalChecked()
11122 6 : ->NewInstance(context.local())
11123 : .ToLocalChecked();
11124 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11125 6 : .ToLocalChecked()
11126 6 : ->NewInstance(context.local())
11127 : .ToLocalChecked();
11128 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11129 6 : .ToLocalChecked()
11130 6 : ->NewInstance(context.local())
11131 : .ToLocalChecked();
11132 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11133 6 : .ToLocalChecked()
11134 6 : ->NewInstance(context.local())
11135 : .ToLocalChecked();
11136 :
11137 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11138 : .ToLocalChecked()
11139 : ->Int32Value(context.local())
11140 : .FromJust());
11141 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11142 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11143 : .ToLocalChecked()
11144 : ->Int32Value(context.local())
11145 : .FromJust());
11146 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11147 : .ToLocalChecked()
11148 : ->Int32Value(context.local())
11149 : .FromJust());
11150 12 : CHECK(o1->SetPrototype(context.local(), o2).FromJust());
11151 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11152 : .ToLocalChecked()
11153 : ->Int32Value(context.local())
11154 : .FromJust());
11155 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11156 : .ToLocalChecked()
11157 : ->Int32Value(context.local())
11158 : .FromJust());
11159 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11160 : .ToLocalChecked()
11161 : ->Int32Value(context.local())
11162 : .FromJust());
11163 12 : CHECK(o2->SetPrototype(context.local(), o3).FromJust());
11164 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11165 : .ToLocalChecked()
11166 : ->Int32Value(context.local())
11167 : .FromJust());
11168 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11169 : .ToLocalChecked()
11170 : ->Int32Value(context.local())
11171 : .FromJust());
11172 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11173 : .ToLocalChecked()
11174 : ->Int32Value(context.local())
11175 : .FromJust());
11176 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
11177 : .ToLocalChecked()
11178 : ->Int32Value(context.local())
11179 : .FromJust());
11180 :
11181 : Local<Value> proto =
11182 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
11183 6 : CHECK(proto->IsObject());
11184 12 : CHECK(proto.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11185 :
11186 6 : Local<Value> proto0 = o0->GetPrototype();
11187 6 : CHECK(proto0->IsObject());
11188 12 : CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11189 :
11190 6 : Local<Value> proto1 = o1->GetPrototype();
11191 6 : CHECK(proto1->IsObject());
11192 12 : CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
11193 :
11194 6 : Local<Value> proto2 = o2->GetPrototype();
11195 6 : CHECK(proto2->IsObject());
11196 18 : CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
11197 6 : }
11198 :
11199 :
11200 : // Getting property names of an object with a prototype chain that
11201 : // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11202 : // crash the runtime.
11203 25881 : THREADED_TEST(Regress91517) {
11204 6 : i::FLAG_allow_natives_syntax = true;
11205 6 : LocalContext context;
11206 6 : v8::Isolate* isolate = context->GetIsolate();
11207 12 : v8::HandleScope handle_scope(isolate);
11208 :
11209 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11210 24 : t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11211 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11212 24 : t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11213 12 : t2->InstanceTemplate()->Set(v8_str("objects"),
11214 24 : v8::ObjectTemplate::New(isolate));
11215 24 : t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11216 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11217 24 : t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11218 6 : Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11219 24 : t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11220 :
11221 : // Force dictionary-based properties.
11222 : i::ScopedVector<char> name_buf(1024);
11223 6006 : for (int i = 1; i <= 1000; i++) {
11224 6000 : i::SNPrintF(name_buf, "sdf%d", i);
11225 24000 : t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11226 : }
11227 :
11228 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11229 6 : .ToLocalChecked()
11230 6 : ->NewInstance(context.local())
11231 : .ToLocalChecked();
11232 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11233 6 : .ToLocalChecked()
11234 6 : ->NewInstance(context.local())
11235 : .ToLocalChecked();
11236 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11237 6 : .ToLocalChecked()
11238 6 : ->NewInstance(context.local())
11239 : .ToLocalChecked();
11240 6 : Local<v8::Object> o4 = t4->GetFunction(context.local())
11241 6 : .ToLocalChecked()
11242 6 : ->NewInstance(context.local())
11243 : .ToLocalChecked();
11244 :
11245 12 : CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11246 12 : CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11247 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11248 :
11249 : // Call the runtime version of GetOwnPropertyNames() on the natively
11250 : // created object through JavaScript.
11251 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11252 : // PROPERTY_FILTER_NONE = 0
11253 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11254 :
11255 6 : ExpectInt32("names.length", 1);
11256 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11257 : ExpectFalse("names.indexOf(\"boo\") >= 0");
11258 : ExpectFalse("names.indexOf(\"foo\") >= 0");
11259 : ExpectFalse("names.indexOf(\"fuz1\") >= 0");
11260 : ExpectFalse("names.indexOf(\"objects\") >= 0");
11261 : ExpectFalse("names.indexOf(\"fuz2\") >= 0");
11262 6 : ExpectTrue("names[1005] == undefined");
11263 6 : }
11264 :
11265 :
11266 25881 : THREADED_TEST(FunctionReadOnlyPrototype) {
11267 6 : LocalContext context;
11268 6 : v8::Isolate* isolate = context->GetIsolate();
11269 12 : v8::HandleScope handle_scope(isolate);
11270 :
11271 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11272 24 : t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11273 6 : t1->ReadOnlyPrototype();
11274 36 : CHECK(context->Global()
11275 : ->Set(context.local(), v8_str("func1"),
11276 : t1->GetFunction(context.local()).ToLocalChecked())
11277 : .FromJust());
11278 : // Configured value of ReadOnly flag.
11279 6 : CHECK(
11280 : CompileRun(
11281 : "(function() {"
11282 : " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11283 : " return (descriptor['writable'] == false);"
11284 : "})()")
11285 : ->BooleanValue(isolate));
11286 18 : CHECK_EQ(
11287 : 42,
11288 : CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11289 18 : CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11290 : ->Int32Value(context.local())
11291 : .FromJust());
11292 :
11293 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11294 24 : t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11295 36 : CHECK(context->Global()
11296 : ->Set(context.local(), v8_str("func2"),
11297 : t2->GetFunction(context.local()).ToLocalChecked())
11298 : .FromJust());
11299 : // Default value of ReadOnly flag.
11300 6 : CHECK(
11301 : CompileRun(
11302 : "(function() {"
11303 : " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11304 : " return (descriptor['writable'] == true);"
11305 : "})()")
11306 : ->BooleanValue(isolate));
11307 18 : CHECK_EQ(
11308 : 42,
11309 6 : CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11310 6 : }
11311 :
11312 :
11313 25881 : THREADED_TEST(SetPrototypeThrows) {
11314 6 : LocalContext context;
11315 6 : v8::Isolate* isolate = context->GetIsolate();
11316 12 : v8::HandleScope handle_scope(isolate);
11317 :
11318 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11319 :
11320 6 : Local<v8::Object> o0 = t->GetFunction(context.local())
11321 6 : .ToLocalChecked()
11322 6 : ->NewInstance(context.local())
11323 : .ToLocalChecked();
11324 6 : Local<v8::Object> o1 = t->GetFunction(context.local())
11325 6 : .ToLocalChecked()
11326 6 : ->NewInstance(context.local())
11327 : .ToLocalChecked();
11328 :
11329 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11330 : // If setting the prototype leads to the cycle, SetPrototype should
11331 : // return false and keep VM in sane state.
11332 12 : v8::TryCatch try_catch(isolate);
11333 12 : CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11334 6 : CHECK(!try_catch.HasCaught());
11335 6 : CHECK(!CcTest::i_isolate()->has_pending_exception());
11336 :
11337 18 : CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11338 : ->Int32Value(context.local())
11339 6 : .FromJust());
11340 6 : }
11341 :
11342 :
11343 25881 : THREADED_TEST(FunctionRemovePrototype) {
11344 6 : LocalContext context;
11345 6 : v8::Isolate* isolate = context->GetIsolate();
11346 12 : v8::HandleScope handle_scope(isolate);
11347 :
11348 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11349 6 : t1->RemovePrototype();
11350 6 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11351 6 : CHECK(!fun->IsConstructor());
11352 30 : CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11353 6 : CHECK(!CompileRun("'prototype' in fun")->BooleanValue(isolate));
11354 :
11355 12 : v8::TryCatch try_catch(isolate);
11356 : CompileRun("new fun()");
11357 6 : CHECK(try_catch.HasCaught());
11358 :
11359 6 : try_catch.Reset();
11360 12 : CHECK(fun->NewInstance(context.local()).IsEmpty());
11361 12 : CHECK(try_catch.HasCaught());
11362 6 : }
11363 :
11364 :
11365 25881 : THREADED_TEST(GetterSetterExceptions) {
11366 6 : LocalContext context;
11367 6 : v8::Isolate* isolate = context->GetIsolate();
11368 12 : v8::HandleScope handle_scope(isolate);
11369 : CompileRun(
11370 : "function Foo() { };"
11371 : "function Throw() { throw 5; };"
11372 : "var x = { };"
11373 : "x.__defineSetter__('set', Throw);"
11374 : "x.__defineGetter__('get', Throw);");
11375 : Local<v8::Object> x = Local<v8::Object>::Cast(
11376 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11377 12 : v8::TryCatch try_catch(isolate);
11378 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11379 : .IsNothing());
11380 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11381 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11382 : .IsNothing());
11383 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11384 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11385 : .IsNothing());
11386 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11387 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11388 : .IsNothing());
11389 24 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11390 6 : }
11391 :
11392 :
11393 25881 : THREADED_TEST(Constructor) {
11394 6 : LocalContext context;
11395 6 : v8::Isolate* isolate = context->GetIsolate();
11396 12 : v8::HandleScope handle_scope(isolate);
11397 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11398 6 : templ->SetClassName(v8_str("Fun"));
11399 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11400 30 : CHECK(
11401 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11402 6 : Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11403 : i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11404 12 : CHECK(obj->IsJSObject());
11405 : Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11406 12 : CHECK(value->BooleanValue(isolate));
11407 6 : }
11408 :
11409 :
11410 25881 : THREADED_TEST(FunctionDescriptorException) {
11411 6 : LocalContext context;
11412 6 : v8::Isolate* isolate = context->GetIsolate();
11413 12 : v8::HandleScope handle_scope(isolate);
11414 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11415 6 : templ->SetClassName(v8_str("Fun"));
11416 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11417 30 : CHECK(
11418 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11419 : Local<Value> value = CompileRun(
11420 : "function test() {"
11421 : " try {"
11422 : " (new Fun()).blah()"
11423 : " } catch (e) {"
11424 : " var str = String(e);"
11425 : // " if (str.indexOf('TypeError') == -1) return 1;"
11426 : // " if (str.indexOf('[object Fun]') != -1) return 2;"
11427 : // " if (str.indexOf('#<Fun>') == -1) return 3;"
11428 : " return 0;"
11429 : " }"
11430 : " return 4;"
11431 : "}"
11432 : "test();");
11433 18 : CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11434 6 : }
11435 :
11436 :
11437 25881 : THREADED_TEST(EvalAliasedDynamic) {
11438 6 : LocalContext current;
11439 12 : v8::HandleScope scope(current->GetIsolate());
11440 :
11441 : // Tests where aliased eval can only be resolved dynamically.
11442 : Local<Script> script = v8_compile(
11443 : "function f(x) { "
11444 : " var foo = 2;"
11445 : " with (x) { return eval('foo'); }"
11446 : "}"
11447 : "foo = 0;"
11448 : "result1 = f(new Object());"
11449 : "result2 = f(this);"
11450 : "var x = new Object();"
11451 : "x.eval = function(x) { return 1; };"
11452 : "result3 = f(x);");
11453 6 : script->Run(current.local()).ToLocalChecked();
11454 36 : CHECK_EQ(2, current->Global()
11455 : ->Get(current.local(), v8_str("result1"))
11456 : .ToLocalChecked()
11457 : ->Int32Value(current.local())
11458 : .FromJust());
11459 36 : CHECK_EQ(0, current->Global()
11460 : ->Get(current.local(), v8_str("result2"))
11461 : .ToLocalChecked()
11462 : ->Int32Value(current.local())
11463 : .FromJust());
11464 36 : CHECK_EQ(1, current->Global()
11465 : ->Get(current.local(), v8_str("result3"))
11466 : .ToLocalChecked()
11467 : ->Int32Value(current.local())
11468 : .FromJust());
11469 :
11470 12 : v8::TryCatch try_catch(current->GetIsolate());
11471 : script = v8_compile(
11472 : "function f(x) { "
11473 : " var bar = 2;"
11474 : " with (x) { return eval('bar'); }"
11475 : "}"
11476 : "result4 = f(this)");
11477 6 : script->Run(current.local()).ToLocalChecked();
11478 6 : CHECK(!try_catch.HasCaught());
11479 36 : CHECK_EQ(2, current->Global()
11480 : ->Get(current.local(), v8_str("result4"))
11481 : .ToLocalChecked()
11482 : ->Int32Value(current.local())
11483 : .FromJust());
11484 :
11485 12 : try_catch.Reset();
11486 6 : }
11487 :
11488 :
11489 25881 : THREADED_TEST(CrossEval) {
11490 6 : v8::HandleScope scope(CcTest::isolate());
11491 12 : LocalContext other;
11492 12 : LocalContext current;
11493 :
11494 6 : Local<String> token = v8_str("<security token>");
11495 6 : other->SetSecurityToken(token);
11496 6 : current->SetSecurityToken(token);
11497 :
11498 : // Set up reference from current to other.
11499 36 : CHECK(current->Global()
11500 : ->Set(current.local(), v8_str("other"), other->Global())
11501 : .FromJust());
11502 :
11503 : // Check that new variables are introduced in other context.
11504 : Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11505 6 : script->Run(current.local()).ToLocalChecked();
11506 : Local<Value> foo =
11507 30 : other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11508 12 : CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11509 30 : CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11510 :
11511 : // Check that writing to non-existing properties introduces them in
11512 : // the other context.
11513 : script = v8_compile("other.eval('na = 1234')");
11514 6 : script->Run(current.local()).ToLocalChecked();
11515 36 : CHECK_EQ(1234, other->Global()
11516 : ->Get(current.local(), v8_str("na"))
11517 : .ToLocalChecked()
11518 : ->Int32Value(other.local())
11519 : .FromJust());
11520 30 : CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11521 :
11522 : // Check that global variables in current context are not visible in other
11523 : // context.
11524 12 : v8::TryCatch try_catch(CcTest::isolate());
11525 : script = v8_compile("var bar = 42; other.eval('bar');");
11526 12 : CHECK(script->Run(current.local()).IsEmpty());
11527 6 : CHECK(try_catch.HasCaught());
11528 6 : try_catch.Reset();
11529 :
11530 : // Check that local variables in current context are not visible in other
11531 : // context.
11532 : script = v8_compile(
11533 : "(function() { "
11534 : " var baz = 87;"
11535 : " return other.eval('baz');"
11536 : "})();");
11537 12 : CHECK(script->Run(current.local()).IsEmpty());
11538 6 : CHECK(try_catch.HasCaught());
11539 6 : try_catch.Reset();
11540 :
11541 : // Check that global variables in the other environment are visible
11542 : // when evaluting code.
11543 30 : CHECK(other->Global()
11544 : ->Set(other.local(), v8_str("bis"), v8_num(1234))
11545 : .FromJust());
11546 : script = v8_compile("other.eval('bis')");
11547 18 : CHECK_EQ(1234, script->Run(current.local())
11548 : .ToLocalChecked()
11549 : ->Int32Value(current.local())
11550 : .FromJust());
11551 6 : CHECK(!try_catch.HasCaught());
11552 :
11553 : // Check that the 'this' pointer points to the global object evaluating
11554 : // code.
11555 36 : CHECK(other->Global()
11556 : ->Set(current.local(), v8_str("t"), other->Global())
11557 : .FromJust());
11558 : script = v8_compile("other.eval('this == t')");
11559 6 : Local<Value> result = script->Run(current.local()).ToLocalChecked();
11560 6 : CHECK(result->IsTrue());
11561 6 : CHECK(!try_catch.HasCaught());
11562 :
11563 : // Check that variables introduced in with-statement are not visible in
11564 : // other context.
11565 : script = v8_compile("with({x:2}){other.eval('x')}");
11566 12 : CHECK(script->Run(current.local()).IsEmpty());
11567 6 : CHECK(try_catch.HasCaught());
11568 6 : try_catch.Reset();
11569 :
11570 : // Check that you cannot use 'eval.call' with another object than the
11571 : // current global object.
11572 : script = v8_compile("other.y = 1; eval.call(other, 'y')");
11573 12 : CHECK(script->Run(current.local()).IsEmpty());
11574 12 : CHECK(try_catch.HasCaught());
11575 6 : }
11576 :
11577 :
11578 : // Test that calling eval in a context which has been detached from
11579 : // its global proxy works.
11580 25881 : THREADED_TEST(EvalInDetachedGlobal) {
11581 6 : v8::Isolate* isolate = CcTest::isolate();
11582 6 : v8::HandleScope scope(isolate);
11583 :
11584 6 : v8::Local<Context> context0 = Context::New(isolate);
11585 6 : v8::Local<Context> context1 = Context::New(isolate);
11586 6 : Local<String> token = v8_str("<security token>");
11587 6 : context0->SetSecurityToken(token);
11588 6 : context1->SetSecurityToken(token);
11589 :
11590 : // Set up function in context0 that uses eval from context0.
11591 6 : context0->Enter();
11592 : v8::Local<v8::Value> fun = CompileRun(
11593 : "var x = 42;"
11594 : "(function() {"
11595 : " var e = eval;"
11596 : " return function(s) { return e(s); }"
11597 6 : "})()");
11598 6 : context0->Exit();
11599 :
11600 : // Put the function into context1 and call it before and after
11601 : // detaching the global. Before detaching, the call succeeds and
11602 : // after detaching undefined is returned.
11603 6 : context1->Enter();
11604 24 : CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11605 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11606 12 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11607 6 : context0->DetachGlobal();
11608 : x_value = CompileRun("fun('x')");
11609 6 : CHECK(x_value->IsUndefined());
11610 6 : context1->Exit();
11611 6 : }
11612 :
11613 :
11614 25881 : THREADED_TEST(CrossLazyLoad) {
11615 6 : v8::HandleScope scope(CcTest::isolate());
11616 12 : LocalContext other;
11617 12 : LocalContext current;
11618 :
11619 6 : Local<String> token = v8_str("<security token>");
11620 6 : other->SetSecurityToken(token);
11621 6 : current->SetSecurityToken(token);
11622 :
11623 : // Set up reference from current to other.
11624 36 : CHECK(current->Global()
11625 : ->Set(current.local(), v8_str("other"), other->Global())
11626 : .FromJust());
11627 :
11628 : // Trigger lazy loading in other context.
11629 : Local<Script> script = v8_compile("other.eval('new Date(42)')");
11630 6 : Local<Value> value = script->Run(current.local()).ToLocalChecked();
11631 18 : CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11632 6 : }
11633 :
11634 :
11635 102 : static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11636 48 : ApiTestFuzzer::Fuzz();
11637 48 : if (args.IsConstructCall()) {
11638 6 : if (args[0]->IsInt32()) {
11639 : args.GetReturnValue().Set(
11640 : v8_num(-args[0]
11641 6 : ->Int32Value(args.GetIsolate()->GetCurrentContext())
11642 18 : .FromJust()));
11643 54 : return;
11644 : }
11645 : }
11646 :
11647 : args.GetReturnValue().Set(args[0]);
11648 : }
11649 :
11650 :
11651 : // Test that a call handler can be set for objects which will allow
11652 : // non-function objects created through the API to be called as
11653 : // functions.
11654 25881 : THREADED_TEST(CallAsFunction) {
11655 6 : LocalContext context;
11656 6 : v8::Isolate* isolate = context->GetIsolate();
11657 12 : v8::HandleScope scope(isolate);
11658 :
11659 : {
11660 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11661 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11662 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11663 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11664 6 : .ToLocalChecked()
11665 6 : ->NewInstance(context.local())
11666 : .ToLocalChecked();
11667 30 : CHECK(context->Global()
11668 : ->Set(context.local(), v8_str("obj"), instance)
11669 : .FromJust());
11670 6 : v8::TryCatch try_catch(isolate);
11671 : Local<Value> value;
11672 6 : CHECK(!try_catch.HasCaught());
11673 :
11674 : value = CompileRun("obj(42)");
11675 6 : CHECK(!try_catch.HasCaught());
11676 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11677 :
11678 : value = CompileRun("(function(o){return o(49)})(obj)");
11679 6 : CHECK(!try_catch.HasCaught());
11680 12 : CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11681 :
11682 : // test special case of call as function
11683 : value = CompileRun("[obj]['0'](45)");
11684 6 : CHECK(!try_catch.HasCaught());
11685 12 : CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11686 :
11687 : value = CompileRun(
11688 : "obj.call = Function.prototype.call;"
11689 : "obj.call(null, 87)");
11690 6 : CHECK(!try_catch.HasCaught());
11691 12 : CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11692 :
11693 : // Regression tests for bug #1116356: Calling call through call/apply
11694 : // must work for non-function receivers.
11695 : const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11696 : value = CompileRun(apply_99);
11697 6 : CHECK(!try_catch.HasCaught());
11698 12 : CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11699 :
11700 : const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11701 : value = CompileRun(call_17);
11702 6 : CHECK(!try_catch.HasCaught());
11703 12 : CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11704 :
11705 : // Check that the call-as-function handler can be called through new.
11706 : value = CompileRun("new obj(43)");
11707 6 : CHECK(!try_catch.HasCaught());
11708 12 : CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11709 :
11710 : // Check that the call-as-function handler can be called through
11711 : // the API.
11712 6 : v8::Local<Value> args[] = {v8_num(28)};
11713 12 : value = instance->CallAsFunction(context.local(), instance, 1, args)
11714 6 : .ToLocalChecked();
11715 6 : CHECK(!try_catch.HasCaught());
11716 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11717 : }
11718 :
11719 : {
11720 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11721 6 : Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11722 : USE(instance_template);
11723 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11724 6 : .ToLocalChecked()
11725 6 : ->NewInstance(context.local())
11726 : .ToLocalChecked();
11727 30 : CHECK(context->Global()
11728 : ->Set(context.local(), v8_str("obj2"), instance)
11729 : .FromJust());
11730 6 : v8::TryCatch try_catch(isolate);
11731 : Local<Value> value;
11732 6 : CHECK(!try_catch.HasCaught());
11733 :
11734 : // Call an object without call-as-function handler through the JS
11735 : value = CompileRun("obj2(28)");
11736 6 : CHECK(value.IsEmpty());
11737 6 : CHECK(try_catch.HasCaught());
11738 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11739 : // TODO(verwaest): Better message
11740 6 : CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11741 6 : try_catch.Reset();
11742 :
11743 : // Call an object without call-as-function handler through the API
11744 6 : v8::Local<Value> args[] = {v8_num(28)};
11745 12 : CHECK(
11746 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11747 6 : CHECK(try_catch.HasCaught());
11748 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11749 6 : CHECK_EQ(0,
11750 : strcmp("TypeError: object is not a function", *exception_value2));
11751 12 : try_catch.Reset();
11752 : }
11753 :
11754 : {
11755 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11756 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11757 6 : instance_template->SetCallAsFunctionHandler(ThrowValue);
11758 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11759 6 : .ToLocalChecked()
11760 6 : ->NewInstance(context.local())
11761 : .ToLocalChecked();
11762 30 : CHECK(context->Global()
11763 : ->Set(context.local(), v8_str("obj3"), instance)
11764 : .FromJust());
11765 6 : v8::TryCatch try_catch(isolate);
11766 : Local<Value> value;
11767 6 : CHECK(!try_catch.HasCaught());
11768 :
11769 : // Catch the exception which is thrown by call-as-function handler
11770 : value = CompileRun("obj3(22)");
11771 6 : CHECK(try_catch.HasCaught());
11772 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11773 6 : CHECK_EQ(0, strcmp("22", *exception_value1));
11774 6 : try_catch.Reset();
11775 :
11776 6 : v8::Local<Value> args[] = {v8_num(23)};
11777 12 : CHECK(
11778 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11779 6 : CHECK(try_catch.HasCaught());
11780 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11781 6 : CHECK_EQ(0, strcmp("23", *exception_value2));
11782 12 : try_catch.Reset();
11783 : }
11784 :
11785 : {
11786 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11787 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11788 6 : instance_template->SetCallAsFunctionHandler(ReturnThis);
11789 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11790 6 : .ToLocalChecked()
11791 6 : ->NewInstance(context.local())
11792 : .ToLocalChecked();
11793 :
11794 : Local<v8::Value> a1 =
11795 : instance
11796 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11797 12 : nullptr)
11798 6 : .ToLocalChecked();
11799 6 : CHECK(a1->StrictEquals(instance));
11800 : Local<v8::Value> a2 =
11801 12 : instance->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11802 6 : .ToLocalChecked();
11803 6 : CHECK(a2->StrictEquals(instance));
11804 : Local<v8::Value> a3 =
11805 6 : instance->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11806 6 : .ToLocalChecked();
11807 6 : CHECK(a3->StrictEquals(instance));
11808 : Local<v8::Value> a4 =
11809 18 : instance->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11810 6 : .ToLocalChecked();
11811 6 : CHECK(a4->StrictEquals(instance));
11812 : Local<v8::Value> a5 =
11813 12 : instance->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11814 6 : .ToLocalChecked();
11815 6 : CHECK(a5->StrictEquals(instance));
11816 : }
11817 :
11818 : {
11819 : CompileRun(
11820 : "function ReturnThisSloppy() {"
11821 : " return this;"
11822 : "}"
11823 : "function ReturnThisStrict() {"
11824 : " 'use strict';"
11825 : " return this;"
11826 : "}");
11827 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11828 : context->Global()
11829 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
11830 6 : .ToLocalChecked());
11831 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
11832 : context->Global()
11833 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
11834 6 : .ToLocalChecked());
11835 :
11836 : Local<v8::Value> a1 =
11837 : ReturnThisSloppy
11838 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11839 12 : nullptr)
11840 6 : .ToLocalChecked();
11841 12 : CHECK(a1->StrictEquals(context->Global()));
11842 : Local<v8::Value> a2 =
11843 : ReturnThisSloppy
11844 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11845 6 : .ToLocalChecked();
11846 12 : CHECK(a2->StrictEquals(context->Global()));
11847 : Local<v8::Value> a3 =
11848 : ReturnThisSloppy
11849 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11850 6 : .ToLocalChecked();
11851 6 : CHECK(a3->IsNumberObject());
11852 6 : CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11853 : Local<v8::Value> a4 =
11854 : ReturnThisSloppy
11855 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11856 6 : .ToLocalChecked();
11857 6 : CHECK(a4->IsStringObject());
11858 18 : CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11859 : Local<v8::Value> a5 =
11860 : ReturnThisSloppy
11861 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11862 6 : .ToLocalChecked();
11863 6 : CHECK(a5->IsBooleanObject());
11864 6 : CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11865 :
11866 : Local<v8::Value> a6 =
11867 : ReturnThisStrict
11868 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11869 12 : nullptr)
11870 6 : .ToLocalChecked();
11871 6 : CHECK(a6->IsUndefined());
11872 : Local<v8::Value> a7 =
11873 : ReturnThisStrict
11874 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11875 6 : .ToLocalChecked();
11876 6 : CHECK(a7->IsNull());
11877 : Local<v8::Value> a8 =
11878 : ReturnThisStrict
11879 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11880 6 : .ToLocalChecked();
11881 6 : CHECK(a8->StrictEquals(v8_num(42)));
11882 : Local<v8::Value> a9 =
11883 : ReturnThisStrict
11884 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11885 6 : .ToLocalChecked();
11886 12 : CHECK(a9->StrictEquals(v8_str("hello")));
11887 : Local<v8::Value> a10 =
11888 : ReturnThisStrict
11889 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11890 6 : .ToLocalChecked();
11891 6 : CHECK(a10->StrictEquals(v8::True(isolate)));
11892 6 : }
11893 6 : }
11894 :
11895 :
11896 : // Check whether a non-function object is callable.
11897 25881 : THREADED_TEST(CallableObject) {
11898 6 : LocalContext context;
11899 6 : v8::Isolate* isolate = context->GetIsolate();
11900 12 : v8::HandleScope scope(isolate);
11901 :
11902 : {
11903 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11904 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11905 : Local<Object> instance =
11906 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11907 6 : v8::TryCatch try_catch(isolate);
11908 :
11909 6 : CHECK(instance->IsCallable());
11910 6 : CHECK(!try_catch.HasCaught());
11911 : }
11912 :
11913 : {
11914 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11915 : Local<Object> instance =
11916 12 : instance_template->NewInstance(context.local()).ToLocalChecked();
11917 6 : v8::TryCatch try_catch(isolate);
11918 :
11919 6 : CHECK(!instance->IsCallable());
11920 6 : CHECK(!try_catch.HasCaught());
11921 : }
11922 :
11923 : {
11924 : Local<FunctionTemplate> function_template =
11925 6 : FunctionTemplate::New(isolate, call_as_function);
11926 : Local<Function> function =
11927 12 : function_template->GetFunction(context.local()).ToLocalChecked();
11928 : Local<Object> instance = function;
11929 6 : v8::TryCatch try_catch(isolate);
11930 :
11931 6 : CHECK(instance->IsCallable());
11932 6 : CHECK(!try_catch.HasCaught());
11933 : }
11934 :
11935 : {
11936 6 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11937 : Local<Function> function =
11938 12 : function_template->GetFunction(context.local()).ToLocalChecked();
11939 : Local<Object> instance = function;
11940 6 : v8::TryCatch try_catch(isolate);
11941 :
11942 6 : CHECK(instance->IsCallable());
11943 6 : CHECK(!try_catch.HasCaught());
11944 6 : }
11945 6 : }
11946 :
11947 :
11948 25881 : THREADED_TEST(Regress567998) {
11949 6 : LocalContext env;
11950 12 : v8::HandleScope scope(env->GetIsolate());
11951 :
11952 : Local<v8::FunctionTemplate> desc =
11953 6 : v8::FunctionTemplate::New(env->GetIsolate());
11954 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
11955 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
11956 :
11957 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
11958 6 : .ToLocalChecked()
11959 6 : ->NewInstance(env.local())
11960 : .ToLocalChecked();
11961 30 : CHECK(
11962 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
11963 :
11964 6 : ExpectString("undetectable.toString()", "[object Object]");
11965 6 : ExpectString("typeof undetectable", "undefined");
11966 6 : ExpectString("typeof(undetectable)", "undefined");
11967 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
11968 6 : ExpectBoolean("typeof undetectable == 'object'", false);
11969 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
11970 6 : ExpectBoolean("!undetectable", true);
11971 :
11972 6 : ExpectObject("true&&undetectable", obj);
11973 6 : ExpectBoolean("false&&undetectable", false);
11974 6 : ExpectBoolean("true||undetectable", true);
11975 6 : ExpectObject("false||undetectable", obj);
11976 :
11977 6 : ExpectObject("undetectable&&true", obj);
11978 6 : ExpectObject("undetectable&&false", obj);
11979 6 : ExpectBoolean("undetectable||true", true);
11980 6 : ExpectBoolean("undetectable||false", false);
11981 :
11982 6 : ExpectBoolean("undetectable==null", true);
11983 6 : ExpectBoolean("null==undetectable", true);
11984 6 : ExpectBoolean("undetectable==undefined", true);
11985 6 : ExpectBoolean("undefined==undetectable", true);
11986 6 : ExpectBoolean("undetectable==undetectable", true);
11987 :
11988 6 : ExpectBoolean("undetectable===null", false);
11989 6 : ExpectBoolean("null===undetectable", false);
11990 6 : ExpectBoolean("undetectable===undefined", false);
11991 6 : ExpectBoolean("undefined===undetectable", false);
11992 12 : ExpectBoolean("undetectable===undetectable", true);
11993 6 : }
11994 :
11995 :
11996 1206 : static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11997 1206 : v8::HandleScope scope(isolate);
11998 1206 : if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11999 600000 : for (int i = 0; i < iterations; i++) {
12000 600000 : Local<v8::Number> n(v8::Integer::New(isolate, 42));
12001 : }
12002 1200 : return Recurse(isolate, depth - 1, iterations);
12003 : }
12004 :
12005 :
12006 25881 : THREADED_TEST(HandleIteration) {
12007 : static const int kIterations = 500;
12008 : static const int kNesting = 200;
12009 6 : LocalContext context;
12010 6 : v8::Isolate* isolate = context->GetIsolate();
12011 12 : v8::HandleScope scope0(isolate);
12012 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12013 : {
12014 6 : v8::HandleScope scope1(isolate);
12015 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12016 3006 : for (int i = 0; i < kIterations; i++) {
12017 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12018 3000 : CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12019 : }
12020 :
12021 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12022 : {
12023 6 : v8::HandleScope scope2(CcTest::isolate());
12024 3006 : for (int j = 0; j < kIterations; j++) {
12025 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12026 3000 : CHECK_EQ(j + 1 + kIterations,
12027 : v8::HandleScope::NumberOfHandles(isolate));
12028 6 : }
12029 : }
12030 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12031 : }
12032 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12033 12 : CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12034 6 : }
12035 :
12036 :
12037 1100 : static void InterceptorCallICFastApi(
12038 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12039 1100 : ApiTestFuzzer::Fuzz();
12040 1100 : CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12041 : int* call_count =
12042 1100 : reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12043 1100 : ++(*call_count);
12044 1100 : if ((*call_count) % 20 == 0) {
12045 55 : CcTest::CollectAllGarbage();
12046 : }
12047 1100 : }
12048 :
12049 2200 : static void FastApiCallback_TrivialSignature(
12050 8800 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12051 2200 : ApiTestFuzzer::Fuzz();
12052 2200 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12053 2200 : v8::Isolate* isolate = CcTest::isolate();
12054 2200 : CHECK_EQ(isolate, args.GetIsolate());
12055 6600 : CHECK(args.This()
12056 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12057 : .FromJust());
12058 8800 : CHECK(args.Data()
12059 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12060 : .FromJust());
12061 : args.GetReturnValue().Set(
12062 8800 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12063 2200 : }
12064 :
12065 : static void FastApiCallback_SimpleSignature(
12066 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12067 : ApiTestFuzzer::Fuzz();
12068 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12069 : v8::Isolate* isolate = CcTest::isolate();
12070 : CHECK_EQ(isolate, args.GetIsolate());
12071 : CHECK(args.This()
12072 : ->GetPrototype()
12073 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12074 : .FromJust());
12075 : CHECK(args.Data()
12076 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12077 : .FromJust());
12078 : // Note, we're using HasRealNamedProperty instead of Has to avoid
12079 : // invoking the interceptor again.
12080 : CHECK(args.Holder()
12081 : ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12082 : .FromJust());
12083 : args.GetReturnValue().Set(
12084 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12085 : }
12086 :
12087 :
12088 : // Helper to maximize the odds of object moving.
12089 192 : static void GenerateSomeGarbage() {
12090 : CompileRun(
12091 : "var garbage;"
12092 : "for (var i = 0; i < 1000; i++) {"
12093 : " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12094 : "}"
12095 : "garbage = undefined;");
12096 192 : }
12097 :
12098 :
12099 180 : void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12100 : static int count = 0;
12101 180 : if (count++ % 3 == 0) {
12102 60 : CcTest::CollectAllGarbage();
12103 : // This should move the stub
12104 60 : GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12105 : }
12106 180 : }
12107 :
12108 :
12109 25881 : THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12110 6 : LocalContext context;
12111 6 : v8::Isolate* isolate = context->GetIsolate();
12112 12 : v8::HandleScope scope(isolate);
12113 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12114 6 : v8::ObjectTemplate::New(isolate);
12115 : nativeobject_templ->Set(isolate, "callback",
12116 : v8::FunctionTemplate::New(isolate,
12117 12 : DirectApiCallback));
12118 : v8::Local<v8::Object> nativeobject_obj =
12119 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12120 30 : CHECK(context->Global()
12121 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12122 : .FromJust());
12123 : // call the api function multiple times to ensure direct call stub creation.
12124 : CompileRun(
12125 : "function f() {"
12126 : " for (var i = 1; i <= 30; i++) {"
12127 : " nativeobject.callback();"
12128 : " }"
12129 : "}"
12130 6 : "f();");
12131 6 : }
12132 :
12133 30 : void ThrowingDirectApiCallback(
12134 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12135 60 : args.GetIsolate()->ThrowException(v8_str("g"));
12136 30 : }
12137 :
12138 25881 : THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12139 6 : LocalContext context;
12140 6 : v8::Isolate* isolate = context->GetIsolate();
12141 12 : v8::HandleScope scope(isolate);
12142 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12143 6 : v8::ObjectTemplate::New(isolate);
12144 : nativeobject_templ->Set(
12145 : isolate, "callback",
12146 12 : v8::FunctionTemplate::New(isolate, ThrowingDirectApiCallback));
12147 : v8::Local<v8::Object> nativeobject_obj =
12148 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12149 30 : CHECK(context->Global()
12150 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12151 : .FromJust());
12152 : // call the api function multiple times to ensure direct call stub creation.
12153 : v8::Local<Value> result = CompileRun(
12154 : "var result = '';"
12155 : "function f() {"
12156 : " for (var i = 1; i <= 5; i++) {"
12157 : " try { nativeobject.callback(); } catch (e) { result += e; }"
12158 : " }"
12159 : "}"
12160 6 : "f(); result;");
12161 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12162 6 : }
12163 :
12164 : static int p_getter_count_3;
12165 :
12166 341 : static Local<Value> DoDirectGetter() {
12167 341 : if (++p_getter_count_3 % 3 == 0) {
12168 110 : CcTest::CollectAllGarbage();
12169 110 : GenerateSomeGarbage();
12170 : }
12171 341 : return v8_str("Direct Getter Result");
12172 : }
12173 :
12174 341 : static void DirectGetterCallback(
12175 : Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12176 341 : CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12177 341 : info.GetReturnValue().Set(DoDirectGetter());
12178 341 : }
12179 :
12180 : template <typename Accessor>
12181 11 : static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12182 11 : LocalContext context;
12183 11 : v8::Isolate* isolate = context->GetIsolate();
12184 22 : v8::HandleScope scope(isolate);
12185 11 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12186 11 : obj->SetAccessor(v8_str("p1"), accessor);
12187 66 : CHECK(context->Global()
12188 : ->Set(context.local(), v8_str("o1"),
12189 : obj->NewInstance(context.local()).ToLocalChecked())
12190 : .FromJust());
12191 11 : p_getter_count_3 = 0;
12192 : v8::Local<v8::Value> result = CompileRun(
12193 : "function f() {"
12194 : " for (var i = 0; i < 30; i++) o1.p1;"
12195 : " return o1.p1"
12196 : "}"
12197 11 : "f();");
12198 33 : CHECK(v8_str("Direct Getter Result")
12199 : ->Equals(context.local(), result)
12200 : .FromJust());
12201 22 : CHECK_EQ(31, p_getter_count_3);
12202 11 : }
12203 :
12204 51766 : THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12205 11 : LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12206 11 : }
12207 :
12208 30 : void ThrowingDirectGetterCallback(
12209 : Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12210 60 : info.GetIsolate()->ThrowException(v8_str("g"));
12211 30 : }
12212 :
12213 25881 : THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12214 6 : LocalContext context;
12215 6 : v8::Isolate* isolate = context->GetIsolate();
12216 12 : v8::HandleScope scope(isolate);
12217 6 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12218 6 : obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12219 36 : CHECK(context->Global()
12220 : ->Set(context.local(), v8_str("o1"),
12221 : obj->NewInstance(context.local()).ToLocalChecked())
12222 : .FromJust());
12223 : v8::Local<Value> result = CompileRun(
12224 : "var result = '';"
12225 : "for (var i = 0; i < 5; i++) {"
12226 : " try { o1.p1; } catch (e) { result += e; }"
12227 : "}"
12228 6 : "result;");
12229 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12230 6 : }
12231 :
12232 51766 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12233 11 : int interceptor_call_count = 0;
12234 11 : v8::Isolate* isolate = CcTest::isolate();
12235 11 : v8::HandleScope scope(isolate);
12236 : v8::Local<v8::FunctionTemplate> fun_templ =
12237 11 : v8::FunctionTemplate::New(isolate);
12238 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12239 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12240 22 : v8::Local<v8::Signature>());
12241 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12242 22 : proto_templ->Set(v8_str("method"), method_templ);
12243 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12244 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12245 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12246 22 : v8::External::New(isolate, &interceptor_call_count)));
12247 22 : LocalContext context;
12248 : v8::Local<v8::Function> fun =
12249 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12250 11 : GenerateSomeGarbage();
12251 66 : CHECK(context->Global()
12252 : ->Set(context.local(), v8_str("o"),
12253 : fun->NewInstance(context.local()).ToLocalChecked())
12254 : .FromJust());
12255 : CompileRun(
12256 : "var result = 0;"
12257 : "for (var i = 0; i < 100; i++) {"
12258 : " result = o.method(41);"
12259 : "}");
12260 66 : CHECK_EQ(42, context->Global()
12261 : ->Get(context.local(), v8_str("result"))
12262 : .ToLocalChecked()
12263 : ->Int32Value(context.local())
12264 : .FromJust());
12265 22 : CHECK_EQ(100, interceptor_call_count);
12266 11 : }
12267 :
12268 51766 : THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12269 11 : v8::Isolate* isolate = CcTest::isolate();
12270 11 : v8::HandleScope scope(isolate);
12271 : v8::Local<v8::FunctionTemplate> fun_templ =
12272 11 : v8::FunctionTemplate::New(isolate);
12273 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12274 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12275 22 : v8::Local<v8::Signature>());
12276 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12277 22 : proto_templ->Set(v8_str("method"), method_templ);
12278 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12279 : USE(templ);
12280 22 : LocalContext context;
12281 : v8::Local<v8::Function> fun =
12282 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12283 11 : GenerateSomeGarbage();
12284 66 : CHECK(context->Global()
12285 : ->Set(context.local(), v8_str("o"),
12286 : fun->NewInstance(context.local()).ToLocalChecked())
12287 : .FromJust());
12288 : CompileRun(
12289 : "var result = 0;"
12290 : "for (var i = 0; i < 100; i++) {"
12291 : " result = o.method(41);"
12292 : "}");
12293 :
12294 66 : CHECK_EQ(42, context->Global()
12295 : ->Get(context.local(), v8_str("result"))
12296 : .ToLocalChecked()
12297 : ->Int32Value(context.local())
12298 11 : .FromJust());
12299 11 : }
12300 :
12301 24 : static void ThrowingGetter(Local<String> name,
12302 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12303 24 : ApiTestFuzzer::Fuzz();
12304 24 : info.GetIsolate()->ThrowException(Local<Value>());
12305 : info.GetReturnValue().SetUndefined();
12306 24 : }
12307 :
12308 :
12309 25881 : THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12310 6 : LocalContext context;
12311 12 : HandleScope scope(context->GetIsolate());
12312 :
12313 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12314 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12315 12 : instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12316 :
12317 6 : Local<Object> instance = templ->GetFunction(context.local())
12318 6 : .ToLocalChecked()
12319 6 : ->NewInstance(context.local())
12320 : .ToLocalChecked();
12321 :
12322 6 : Local<Object> another = Object::New(context->GetIsolate());
12323 12 : CHECK(another->SetPrototype(context.local(), instance).FromJust());
12324 :
12325 : Local<Object> with_js_getter = CompileRun(
12326 : "o = {};\n"
12327 : "o.__defineGetter__('f', function() { throw undefined; });\n"
12328 : "o\n").As<Object>();
12329 6 : CHECK(!with_js_getter.IsEmpty());
12330 :
12331 12 : TryCatch try_catch(context->GetIsolate());
12332 :
12333 : v8::MaybeLocal<Value> result =
12334 12 : instance->GetRealNamedProperty(context.local(), v8_str("f"));
12335 6 : CHECK(try_catch.HasCaught());
12336 6 : try_catch.Reset();
12337 6 : CHECK(result.IsEmpty());
12338 :
12339 : Maybe<PropertyAttribute> attr =
12340 12 : instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12341 6 : CHECK(!try_catch.HasCaught());
12342 6 : CHECK(Just(None) == attr);
12343 :
12344 12 : result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12345 6 : CHECK(try_catch.HasCaught());
12346 6 : try_catch.Reset();
12347 6 : CHECK(result.IsEmpty());
12348 :
12349 12 : attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12350 6 : CHECK(!try_catch.HasCaught());
12351 6 : CHECK(Just(None) == attr);
12352 :
12353 : result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12354 12 : v8_str("f"));
12355 6 : CHECK(try_catch.HasCaught());
12356 6 : try_catch.Reset();
12357 6 : CHECK(result.IsEmpty());
12358 :
12359 : attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12360 12 : context.local(), v8_str("f"));
12361 6 : CHECK(!try_catch.HasCaught());
12362 6 : CHECK(Just(None) == attr);
12363 :
12364 12 : result = another->Get(context.local(), v8_str("f"));
12365 6 : CHECK(try_catch.HasCaught());
12366 6 : try_catch.Reset();
12367 6 : CHECK(result.IsEmpty());
12368 :
12369 12 : result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12370 6 : CHECK(try_catch.HasCaught());
12371 6 : try_catch.Reset();
12372 6 : CHECK(result.IsEmpty());
12373 :
12374 : attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12375 12 : v8_str("f"));
12376 6 : CHECK(!try_catch.HasCaught());
12377 6 : CHECK(Just(None) == attr);
12378 :
12379 12 : result = with_js_getter->Get(context.local(), v8_str("f"));
12380 6 : CHECK(try_catch.HasCaught());
12381 6 : try_catch.Reset();
12382 6 : CHECK(result.IsEmpty());
12383 :
12384 : Local<Object> target = CompileRun("({})").As<Object>();
12385 6 : Local<Object> handler = CompileRun("({})").As<Object>();
12386 : Local<v8::Proxy> proxy =
12387 6 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12388 :
12389 12 : result = target->GetRealNamedProperty(context.local(), v8_str("f"));
12390 6 : CHECK(!try_catch.HasCaught());
12391 6 : CHECK(result.IsEmpty());
12392 :
12393 12 : result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
12394 6 : CHECK(!try_catch.HasCaught());
12395 12 : CHECK(result.IsEmpty());
12396 6 : }
12397 :
12398 :
12399 30 : static void ThrowingCallbackWithTryCatch(
12400 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12401 30 : TryCatch try_catch(args.GetIsolate());
12402 : // Verboseness is important: it triggers message delivery which can call into
12403 : // external code.
12404 30 : try_catch.SetVerbose(true);
12405 : CompileRun("throw 'from JS';");
12406 30 : CHECK(try_catch.HasCaught());
12407 30 : CHECK(!CcTest::i_isolate()->has_pending_exception());
12408 30 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12409 30 : }
12410 :
12411 :
12412 : static int call_depth;
12413 :
12414 :
12415 6 : static void WithTryCatch(Local<Message> message, Local<Value> data) {
12416 6 : TryCatch try_catch(CcTest::isolate());
12417 6 : }
12418 :
12419 :
12420 6 : static void ThrowFromJS(Local<Message> message, Local<Value> data) {
12421 6 : if (--call_depth) CompileRun("throw 'ThrowInJS';");
12422 6 : }
12423 :
12424 :
12425 6 : static void ThrowViaApi(Local<Message> message, Local<Value> data) {
12426 12 : if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12427 6 : }
12428 :
12429 :
12430 6 : static void WebKitLike(Local<Message> message, Local<Value> data) {
12431 6 : Local<String> errorMessageString = message->Get();
12432 6 : CHECK(!errorMessageString.IsEmpty());
12433 6 : message->GetStackTrace();
12434 6 : message->GetScriptOrigin().ResourceName();
12435 6 : }
12436 :
12437 :
12438 25881 : THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12439 6 : LocalContext context;
12440 6 : v8::Isolate* isolate = context->GetIsolate();
12441 12 : HandleScope scope(isolate);
12442 :
12443 : Local<Function> func =
12444 6 : FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
12445 18 : ->GetFunction(context.local())
12446 6 : .ToLocalChecked();
12447 30 : CHECK(
12448 : context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
12449 :
12450 : MessageCallback callbacks[] = {nullptr, WebKitLike, ThrowViaApi, ThrowFromJS,
12451 6 : WithTryCatch};
12452 36 : for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12453 30 : MessageCallback callback = callbacks[i];
12454 30 : if (callback != nullptr) {
12455 24 : isolate->AddMessageListener(callback);
12456 : }
12457 : // Some small number to control number of times message handler should
12458 : // throw an exception.
12459 30 : call_depth = 5;
12460 : ExpectFalse(
12461 : "var thrown = false;\n"
12462 : "try { func(); } catch(e) { thrown = true; }\n"
12463 : "thrown\n");
12464 30 : if (callback != nullptr) {
12465 24 : isolate->RemoveMessageListeners(callback);
12466 : }
12467 6 : }
12468 6 : }
12469 :
12470 :
12471 6 : static void ParentGetter(Local<String> name,
12472 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12473 6 : ApiTestFuzzer::Fuzz();
12474 6 : info.GetReturnValue().Set(v8_num(1));
12475 6 : }
12476 :
12477 :
12478 18 : static void ChildGetter(Local<String> name,
12479 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12480 18 : ApiTestFuzzer::Fuzz();
12481 18 : info.GetReturnValue().Set(v8_num(42));
12482 18 : }
12483 :
12484 :
12485 25881 : THREADED_TEST(Overriding) {
12486 6 : LocalContext context;
12487 6 : v8::Isolate* isolate = context->GetIsolate();
12488 12 : v8::HandleScope scope(isolate);
12489 :
12490 : // Parent template.
12491 6 : Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12492 : Local<ObjectTemplate> parent_instance_templ =
12493 6 : parent_templ->InstanceTemplate();
12494 12 : parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12495 :
12496 : // Template that inherits from the parent template.
12497 6 : Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12498 : Local<ObjectTemplate> child_instance_templ =
12499 6 : child_templ->InstanceTemplate();
12500 6 : child_templ->Inherit(parent_templ);
12501 : // Override 'f'. The child version of 'f' should get called for child
12502 : // instances.
12503 6 : child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12504 : // Add 'g' twice. The 'g' added last should get called for instances.
12505 6 : child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12506 6 : child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12507 :
12508 : // Add 'h' as an accessor to the proto template with ReadOnly attributes
12509 : // so 'h' can be shadowed on the instance object.
12510 6 : Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12511 : child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, nullptr,
12512 12 : v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
12513 :
12514 : // Add 'i' as an accessor to the instance template with ReadOnly attributes
12515 : // but the attribute does not have effect because it is duplicated with
12516 : // nullptr setter.
12517 : child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, nullptr,
12518 : v8::Local<Value>(), v8::DEFAULT,
12519 6 : v8::ReadOnly);
12520 :
12521 : // Instantiate the child template.
12522 6 : Local<v8::Object> instance = child_templ->GetFunction(context.local())
12523 6 : .ToLocalChecked()
12524 6 : ->NewInstance(context.local())
12525 : .ToLocalChecked();
12526 :
12527 : // Check that the child function overrides the parent one.
12528 30 : CHECK(context->Global()
12529 : ->Set(context.local(), v8_str("o"), instance)
12530 : .FromJust());
12531 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12532 : // Check that the 'g' that was added last is hit.
12533 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12534 12 : value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
12535 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12536 :
12537 : // Check that 'h' cannot be shadowed.
12538 12 : value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
12539 12 : CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
12540 :
12541 : // Check that 'i' cannot be shadowed or changed.
12542 12 : value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
12543 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12544 6 : }
12545 :
12546 :
12547 24 : static void ShouldThrowOnErrorGetter(
12548 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12549 24 : ApiTestFuzzer::Fuzz();
12550 : v8::Isolate* isolate = info.GetIsolate();
12551 : Local<Boolean> should_throw_on_error =
12552 : Boolean::New(isolate, info.ShouldThrowOnError());
12553 : info.GetReturnValue().Set(should_throw_on_error);
12554 24 : }
12555 :
12556 :
12557 : template <typename T>
12558 24 : static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
12559 : const v8::PropertyCallbackInfo<T>& info) {
12560 24 : ApiTestFuzzer::Fuzz();
12561 : v8::Isolate* isolate = info.GetIsolate();
12562 24 : auto context = isolate->GetCurrentContext();
12563 : Local<Boolean> should_throw_on_error_value =
12564 : Boolean::New(isolate, info.ShouldThrowOnError());
12565 120 : CHECK(context->Global()
12566 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
12567 : should_throw_on_error_value)
12568 : .FromJust());
12569 24 : }
12570 :
12571 :
12572 25881 : THREADED_TEST(AccessorShouldThrowOnError) {
12573 6 : LocalContext context;
12574 6 : v8::Isolate* isolate = context->GetIsolate();
12575 12 : v8::HandleScope scope(isolate);
12576 6 : Local<Object> global = context->Global();
12577 :
12578 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12579 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12580 : instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
12581 12 : ShouldThrowOnErrorSetter<void>);
12582 :
12583 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
12584 6 : .ToLocalChecked()
12585 6 : ->NewInstance(context.local())
12586 : .ToLocalChecked();
12587 :
12588 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12589 :
12590 : // SLOPPY mode
12591 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12592 6 : CHECK(value->IsFalse());
12593 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12594 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12595 6 : .ToLocalChecked();
12596 6 : CHECK(value->IsFalse());
12597 :
12598 : // STRICT mode
12599 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12600 6 : CHECK(value->IsFalse());
12601 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12602 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12603 6 : .ToLocalChecked();
12604 12 : CHECK(value->IsTrue());
12605 6 : }
12606 :
12607 :
12608 0 : static void ShouldThrowOnErrorQuery(
12609 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
12610 0 : ApiTestFuzzer::Fuzz();
12611 : v8::Isolate* isolate = info.GetIsolate();
12612 : info.GetReturnValue().Set(v8::None);
12613 :
12614 0 : auto context = isolate->GetCurrentContext();
12615 : Local<Boolean> should_throw_on_error_value =
12616 : Boolean::New(isolate, info.ShouldThrowOnError());
12617 0 : CHECK(context->Global()
12618 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
12619 : should_throw_on_error_value)
12620 : .FromJust());
12621 0 : }
12622 :
12623 :
12624 12 : static void ShouldThrowOnErrorDeleter(
12625 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
12626 12 : ApiTestFuzzer::Fuzz();
12627 : v8::Isolate* isolate = info.GetIsolate();
12628 : info.GetReturnValue().Set(v8::True(isolate));
12629 :
12630 12 : auto context = isolate->GetCurrentContext();
12631 : Local<Boolean> should_throw_on_error_value =
12632 : Boolean::New(isolate, info.ShouldThrowOnError());
12633 60 : CHECK(context->Global()
12634 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
12635 : should_throw_on_error_value)
12636 : .FromJust());
12637 12 : }
12638 :
12639 :
12640 12 : static void ShouldThrowOnErrorPropertyEnumerator(
12641 : const v8::PropertyCallbackInfo<v8::Array>& info) {
12642 12 : ApiTestFuzzer::Fuzz();
12643 : v8::Isolate* isolate = info.GetIsolate();
12644 12 : Local<v8::Array> names = v8::Array::New(isolate, 1);
12645 36 : CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
12646 : info.GetReturnValue().Set(names);
12647 :
12648 12 : auto context = isolate->GetCurrentContext();
12649 : Local<Boolean> should_throw_on_error_value =
12650 : Boolean::New(isolate, info.ShouldThrowOnError());
12651 60 : CHECK(context->Global()
12652 : ->Set(isolate->GetCurrentContext(),
12653 : v8_str("should_throw_enumerator"),
12654 : should_throw_on_error_value)
12655 : .FromJust());
12656 12 : }
12657 :
12658 :
12659 25881 : THREADED_TEST(InterceptorShouldThrowOnError) {
12660 6 : LocalContext context;
12661 6 : v8::Isolate* isolate = context->GetIsolate();
12662 12 : v8::HandleScope scope(isolate);
12663 6 : Local<Object> global = context->Global();
12664 :
12665 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
12666 : v8::NamedPropertyHandlerConfiguration handler(
12667 : ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
12668 : ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
12669 : ShouldThrowOnErrorPropertyEnumerator);
12670 6 : interceptor_templ->SetHandler(handler);
12671 :
12672 : Local<v8::Object> instance =
12673 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
12674 :
12675 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12676 :
12677 : // SLOPPY mode
12678 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12679 6 : CHECK(value->IsFalse());
12680 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12681 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12682 6 : .ToLocalChecked();
12683 6 : CHECK(value->IsFalse());
12684 :
12685 12 : v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
12686 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
12687 6 : .ToLocalChecked();
12688 6 : CHECK(value->IsFalse());
12689 :
12690 : v8_compile("Object.getOwnPropertyNames(o)")
12691 6 : ->Run(context.local())
12692 6 : .ToLocalChecked();
12693 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12694 6 : .ToLocalChecked();
12695 6 : CHECK(value->IsFalse());
12696 :
12697 : // STRICT mode
12698 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12699 6 : CHECK(value->IsFalse());
12700 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12701 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12702 6 : .ToLocalChecked();
12703 6 : CHECK(value->IsTrue());
12704 :
12705 12 : v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
12706 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
12707 6 : .ToLocalChecked();
12708 6 : CHECK(value->IsTrue());
12709 :
12710 : v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
12711 6 : ->Run(context.local())
12712 6 : .ToLocalChecked();
12713 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12714 6 : .ToLocalChecked();
12715 12 : CHECK(value->IsFalse());
12716 6 : }
12717 :
12718 55 : static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
12719 :
12720 25880 : TEST(CallHandlerHasNoSideEffect) {
12721 5 : v8::Isolate* isolate = CcTest::isolate();
12722 5 : v8::HandleScope scope(isolate);
12723 10 : LocalContext context;
12724 :
12725 : // Function template with call handler.
12726 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12727 5 : templ->SetCallHandler(EmptyHandler);
12728 30 : CHECK(context->Global()
12729 : ->Set(context.local(), v8_str("f"),
12730 : templ->GetFunction(context.local()).ToLocalChecked())
12731 : .FromJust());
12732 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12733 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12734 :
12735 : // Side-effect-free version.
12736 5 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
12737 : templ2->SetCallHandler(EmptyHandler, v8::Local<Value>(),
12738 5 : v8::SideEffectType::kHasNoSideEffect);
12739 30 : CHECK(context->Global()
12740 : ->Set(context.local(), v8_str("f2"),
12741 : templ2->GetFunction(context.local()).ToLocalChecked())
12742 : .FromJust());
12743 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12744 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12745 5 : }
12746 :
12747 25880 : TEST(FunctionTemplateNewHasNoSideEffect) {
12748 5 : v8::Isolate* isolate = CcTest::isolate();
12749 5 : v8::HandleScope scope(isolate);
12750 10 : LocalContext context;
12751 :
12752 : // Function template with call handler.
12753 : Local<v8::FunctionTemplate> templ =
12754 5 : v8::FunctionTemplate::New(isolate, EmptyHandler);
12755 35 : CHECK(context->Global()
12756 : ->Set(context.local(), v8_str("f"),
12757 : templ->GetFunction(context.local()).ToLocalChecked())
12758 : .FromJust());
12759 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12760 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12761 :
12762 : // Side-effect-free version.
12763 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(
12764 : isolate, EmptyHandler, v8::Local<Value>(), v8::Local<v8::Signature>(), 0,
12765 5 : v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasNoSideEffect);
12766 35 : CHECK(context->Global()
12767 : ->Set(context.local(), v8_str("f2"),
12768 : templ2->GetFunction(context.local()).ToLocalChecked())
12769 : .FromJust());
12770 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12771 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12772 5 : }
12773 :
12774 25880 : TEST(FunctionTemplateNewWithCacheHasNoSideEffect) {
12775 5 : v8::Isolate* isolate = CcTest::isolate();
12776 5 : v8::HandleScope scope(isolate);
12777 10 : LocalContext context;
12778 : v8::Local<v8::Private> priv =
12779 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
12780 :
12781 : // Function template with call handler.
12782 : Local<v8::FunctionTemplate> templ =
12783 5 : v8::FunctionTemplate::NewWithCache(isolate, EmptyHandler, priv);
12784 35 : CHECK(context->Global()
12785 : ->Set(context.local(), v8_str("f"),
12786 : templ->GetFunction(context.local()).ToLocalChecked())
12787 : .FromJust());
12788 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12789 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12790 :
12791 : // Side-effect-free version.
12792 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::NewWithCache(
12793 : isolate, EmptyHandler, priv, v8::Local<Value>(),
12794 5 : v8::Local<v8::Signature>(), 0, v8::SideEffectType::kHasNoSideEffect);
12795 35 : CHECK(context->Global()
12796 : ->Set(context.local(), v8_str("f2"),
12797 : templ2->GetFunction(context.local()).ToLocalChecked())
12798 : .FromJust());
12799 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12800 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12801 5 : }
12802 :
12803 25880 : TEST(FunctionNewHasNoSideEffect) {
12804 5 : v8::Isolate* isolate = CcTest::isolate();
12805 5 : v8::HandleScope scope(isolate);
12806 10 : LocalContext context;
12807 :
12808 : // Function with side-effect.
12809 : Local<Function> func =
12810 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
12811 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12812 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12813 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12814 :
12815 : // Side-effect-free version.
12816 : Local<Function> func2 =
12817 : Function::New(context.local(), EmptyHandler, Local<Value>(), 0,
12818 : v8::ConstructorBehavior::kAllow,
12819 10 : v8::SideEffectType::kHasNoSideEffect)
12820 5 : .ToLocalChecked();
12821 25 : CHECK(
12822 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12823 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12824 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12825 5 : }
12826 :
12827 : // These handlers instantiate a function the embedder considers safe in some
12828 : // cases (e.g. "building object wrappers"), but those functions themselves were
12829 : // not explicitly marked as side-effect-free.
12830 5 : static void DefaultConstructHandler(
12831 5 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12832 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12833 : v8::Context::Scope context_scope(context);
12834 5 : v8::MaybeLocal<v8::Object> instance = Function::New(context, EmptyHandler)
12835 5 : .ToLocalChecked()
12836 5 : ->NewInstance(context, 0, nullptr);
12837 : USE(instance);
12838 5 : }
12839 :
12840 10 : static void NoSideEffectConstructHandler(
12841 10 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12842 10 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12843 : v8::Context::Scope context_scope(context);
12844 : v8::MaybeLocal<v8::Object> instance =
12845 10 : Function::New(context, EmptyHandler)
12846 10 : .ToLocalChecked()
12847 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
12848 10 : v8::SideEffectType::kHasNoSideEffect);
12849 : USE(instance);
12850 10 : }
12851 :
12852 5 : static void NoSideEffectAndSideEffectConstructHandler(
12853 5 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12854 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12855 : v8::Context::Scope context_scope(context);
12856 : // Constructs an instance in a side-effect-free way, followed by another with
12857 : // side effects.
12858 : v8::MaybeLocal<v8::Object> instance =
12859 5 : Function::New(context, EmptyHandler)
12860 5 : .ToLocalChecked()
12861 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
12862 5 : v8::SideEffectType::kHasNoSideEffect);
12863 5 : v8::MaybeLocal<v8::Object> instance2 = Function::New(context, EmptyHandler)
12864 5 : .ToLocalChecked()
12865 5 : ->NewInstance(context, 0, nullptr);
12866 : USE(instance);
12867 : USE(instance2);
12868 5 : }
12869 :
12870 25880 : TEST(FunctionNewInstanceHasNoSideEffect) {
12871 5 : v8::Isolate* isolate = CcTest::isolate();
12872 5 : v8::HandleScope scope(isolate);
12873 10 : LocalContext context;
12874 :
12875 : // A whitelisted function that creates a new object with both side-effect
12876 : // free/full instantiations. Should throw.
12877 : Local<Function> func0 =
12878 : Function::New(context.local(), NoSideEffectAndSideEffectConstructHandler,
12879 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12880 10 : v8::SideEffectType::kHasNoSideEffect)
12881 5 : .ToLocalChecked();
12882 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func0).FromJust());
12883 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12884 :
12885 : // A whitelisted function that creates a new object. Should throw.
12886 : Local<Function> func =
12887 : Function::New(context.local(), DefaultConstructHandler, Local<Value>(), 0,
12888 : v8::ConstructorBehavior::kAllow,
12889 10 : v8::SideEffectType::kHasNoSideEffect)
12890 5 : .ToLocalChecked();
12891 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12892 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12893 :
12894 : // A whitelisted function that creates a new object with explicit intent to
12895 : // have no side-effects (e.g. building an "object wrapper"). Should not throw.
12896 : Local<Function> func2 =
12897 : Function::New(context.local(), NoSideEffectConstructHandler,
12898 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12899 10 : v8::SideEffectType::kHasNoSideEffect)
12900 5 : .ToLocalChecked();
12901 25 : CHECK(
12902 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12903 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12904 :
12905 : // Check that side effect skipping did not leak outside to future evaluations.
12906 : Local<Function> func3 =
12907 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
12908 25 : CHECK(
12909 : context->Global()->Set(context.local(), v8_str("f3"), func3).FromJust());
12910 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f3()"), true).IsEmpty());
12911 :
12912 : // Check that using side effect free NewInstance works in normal evaluation
12913 : // (without throwOnSideEffect).
12914 10 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), false).ToLocalChecked();
12915 5 : }
12916 :
12917 25880 : TEST(CallHandlerAsFunctionHasNoSideEffectNotSupported) {
12918 5 : v8::Isolate* isolate = CcTest::isolate();
12919 5 : v8::HandleScope scope(isolate);
12920 10 : LocalContext context;
12921 :
12922 : // Object template with call as function handler.
12923 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12924 5 : templ->SetCallAsFunctionHandler(EmptyHandler);
12925 5 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
12926 25 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
12927 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12928 :
12929 : // Side-effect-free version is not supported.
12930 : i::FunctionTemplateInfo cons = i::FunctionTemplateInfo::cast(
12931 5 : v8::Utils::OpenHandle(*templ)->constructor());
12932 5 : i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
12933 : i::CallHandlerInfo handler_info =
12934 10 : i::CallHandlerInfo::cast(cons->GetInstanceCallHandler());
12935 5 : CHECK(!handler_info->IsSideEffectFreeCallHandlerInfo());
12936 : handler_info->set_map(
12937 5 : i::ReadOnlyRoots(heap).side_effect_free_call_handler_info_map());
12938 15 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12939 5 : }
12940 :
12941 12 : static void IsConstructHandler(
12942 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12943 12 : ApiTestFuzzer::Fuzz();
12944 : args.GetReturnValue().Set(args.IsConstructCall());
12945 12 : }
12946 :
12947 :
12948 25881 : THREADED_TEST(IsConstructCall) {
12949 6 : v8::Isolate* isolate = CcTest::isolate();
12950 6 : v8::HandleScope scope(isolate);
12951 :
12952 : // Function template with call handler.
12953 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12954 6 : templ->SetCallHandler(IsConstructHandler);
12955 :
12956 12 : LocalContext context;
12957 :
12958 36 : CHECK(context->Global()
12959 : ->Set(context.local(), v8_str("f"),
12960 : templ->GetFunction(context.local()).ToLocalChecked())
12961 : .FromJust());
12962 12 : Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
12963 6 : CHECK(!value->BooleanValue(isolate));
12964 12 : value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
12965 12 : CHECK(value->BooleanValue(isolate));
12966 6 : }
12967 :
12968 48 : static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
12969 24 : ApiTestFuzzer::Fuzz();
12970 : args.GetReturnValue().Set(args.NewTarget());
12971 24 : }
12972 :
12973 25881 : THREADED_TEST(NewTargetHandler) {
12974 6 : v8::Isolate* isolate = CcTest::isolate();
12975 6 : v8::HandleScope scope(isolate);
12976 :
12977 : // Function template with call handler.
12978 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12979 6 : templ->SetCallHandler(NewTargetHandler);
12980 :
12981 12 : LocalContext context;
12982 :
12983 : Local<Function> function =
12984 6 : templ->GetFunction(context.local()).ToLocalChecked();
12985 30 : CHECK(context->Global()
12986 : ->Set(context.local(), v8_str("f"), function)
12987 : .FromJust());
12988 : Local<Value> value = CompileRun("f()");
12989 6 : CHECK(value->IsUndefined());
12990 : value = CompileRun("new f()");
12991 6 : CHECK(value->IsFunction());
12992 6 : CHECK(value == function);
12993 : Local<Value> subclass = CompileRun("var g = class extends f { }; g");
12994 6 : CHECK(subclass->IsFunction());
12995 : value = CompileRun("new g()");
12996 6 : CHECK(value->IsFunction());
12997 6 : CHECK(value == subclass);
12998 : value = CompileRun("Reflect.construct(f, [], Array)");
12999 6 : CHECK(value->IsFunction());
13000 30 : CHECK(value ==
13001 : context->Global()
13002 : ->Get(context.local(), v8_str("Array"))
13003 6 : .ToLocalChecked());
13004 6 : }
13005 :
13006 25881 : THREADED_TEST(ObjectProtoToString) {
13007 6 : v8::Isolate* isolate = CcTest::isolate();
13008 6 : v8::HandleScope scope(isolate);
13009 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13010 6 : templ->SetClassName(v8_str("MyClass"));
13011 :
13012 12 : LocalContext context;
13013 :
13014 6 : Local<String> customized_tostring = v8_str("customized toString");
13015 :
13016 : // Replace Object.prototype.toString
13017 : v8_compile(
13018 : "Object.prototype.toString = function() {"
13019 : " return 'customized toString';"
13020 : "}")
13021 6 : ->Run(context.local())
13022 6 : .ToLocalChecked();
13023 :
13024 : // Normal ToString call should call replaced Object.prototype.toString
13025 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13026 6 : .ToLocalChecked()
13027 6 : ->NewInstance(context.local())
13028 : .ToLocalChecked();
13029 6 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13030 18 : CHECK(value->IsString() &&
13031 : value->Equals(context.local(), customized_tostring).FromJust());
13032 :
13033 : // ObjectProtoToString should not call replace toString function.
13034 6 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13035 18 : CHECK(value->IsString() &&
13036 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13037 :
13038 : // Check global
13039 : value =
13040 24 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13041 18 : CHECK(value->IsString() &&
13042 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13043 :
13044 : // Check ordinary object
13045 : Local<Value> object =
13046 12 : v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13047 : value = object.As<v8::Object>()
13048 6 : ->ObjectProtoToString(context.local())
13049 6 : .ToLocalChecked();
13050 18 : CHECK(value->IsString() &&
13051 6 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13052 6 : }
13053 :
13054 :
13055 25880 : TEST(ObjectProtoToStringES6) {
13056 5 : LocalContext context;
13057 5 : v8::Isolate* isolate = CcTest::isolate();
13058 10 : v8::HandleScope scope(isolate);
13059 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13060 5 : templ->SetClassName(v8_str("MyClass"));
13061 :
13062 5 : Local<String> customized_tostring = v8_str("customized toString");
13063 :
13064 : // Replace Object.prototype.toString
13065 : CompileRun(
13066 : "Object.prototype.toString = function() {"
13067 : " return 'customized toString';"
13068 : "}");
13069 :
13070 : // Normal ToString call should call replaced Object.prototype.toString
13071 5 : Local<v8::Object> instance = templ->GetFunction(context.local())
13072 5 : .ToLocalChecked()
13073 5 : ->NewInstance(context.local())
13074 : .ToLocalChecked();
13075 5 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13076 15 : CHECK(value->IsString() &&
13077 : value->Equals(context.local(), customized_tostring).FromJust());
13078 :
13079 : // ObjectProtoToString should not call replace toString function.
13080 5 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13081 15 : CHECK(value->IsString() &&
13082 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13083 :
13084 : // Check global
13085 : value =
13086 20 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13087 15 : CHECK(value->IsString() &&
13088 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13089 :
13090 : // Check ordinary object
13091 : Local<Value> object = CompileRun("new Object()");
13092 : value = object.As<v8::Object>()
13093 5 : ->ObjectProtoToString(context.local())
13094 5 : .ToLocalChecked();
13095 15 : CHECK(value->IsString() &&
13096 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13097 :
13098 : // Check that ES6 semantics using @@toStringTag work
13099 5 : Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13100 :
13101 : #define TEST_TOSTRINGTAG(type, tag, expected) \
13102 : do { \
13103 : object = CompileRun("new " #type "()"); \
13104 : CHECK(object.As<v8::Object>() \
13105 : ->Set(context.local(), toStringTag, v8_str(#tag)) \
13106 : .FromJust()); \
13107 : value = object.As<v8::Object>() \
13108 : ->ObjectProtoToString(context.local()) \
13109 : .ToLocalChecked(); \
13110 : CHECK(value->IsString() && \
13111 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13112 : .FromJust()); \
13113 : } while (false)
13114 :
13115 30 : TEST_TOSTRINGTAG(Array, Object, Object);
13116 30 : TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13117 30 : TEST_TOSTRINGTAG(Object, Array, Array);
13118 30 : TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13119 30 : TEST_TOSTRINGTAG(Object, Date, Date);
13120 30 : TEST_TOSTRINGTAG(Object, Error, Error);
13121 30 : TEST_TOSTRINGTAG(Object, Function, Function);
13122 30 : TEST_TOSTRINGTAG(Object, Number, Number);
13123 30 : TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13124 30 : TEST_TOSTRINGTAG(Object, String, String);
13125 30 : TEST_TOSTRINGTAG(Object, Foo, Foo);
13126 :
13127 : #undef TEST_TOSTRINGTAG
13128 :
13129 : Local<v8::RegExp> valueRegExp =
13130 5 : v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13131 5 : .ToLocalChecked();
13132 5 : Local<Value> valueNumber = v8_num(123);
13133 5 : Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13134 : Local<v8::Function> valueFunction =
13135 : CompileRun("(function fn() {})").As<v8::Function>();
13136 5 : Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13137 5 : Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13138 5 : Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13139 :
13140 : #define TEST_TOSTRINGTAG(type, tagValue, expected) \
13141 : do { \
13142 : object = CompileRun("new " #type "()"); \
13143 : CHECK(object.As<v8::Object>() \
13144 : ->Set(context.local(), toStringTag, tagValue) \
13145 : .FromJust()); \
13146 : value = object.As<v8::Object>() \
13147 : ->ObjectProtoToString(context.local()) \
13148 : .ToLocalChecked(); \
13149 : CHECK(value->IsString() && \
13150 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13151 : .FromJust()); \
13152 : } while (false)
13153 :
13154 : #define TEST_TOSTRINGTAG_TYPES(tagValue) \
13155 : TEST_TOSTRINGTAG(Array, tagValue, Array); \
13156 : TEST_TOSTRINGTAG(Object, tagValue, Object); \
13157 : TEST_TOSTRINGTAG(Function, tagValue, Function); \
13158 : TEST_TOSTRINGTAG(Date, tagValue, Date); \
13159 : TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13160 : TEST_TOSTRINGTAG(Error, tagValue, Error); \
13161 :
13162 : // Test non-String-valued @@toStringTag
13163 150 : TEST_TOSTRINGTAG_TYPES(valueRegExp);
13164 150 : TEST_TOSTRINGTAG_TYPES(valueNumber);
13165 150 : TEST_TOSTRINGTAG_TYPES(valueSymbol);
13166 150 : TEST_TOSTRINGTAG_TYPES(valueFunction);
13167 150 : TEST_TOSTRINGTAG_TYPES(valueObject);
13168 150 : TEST_TOSTRINGTAG_TYPES(valueNull);
13169 150 : TEST_TOSTRINGTAG_TYPES(valueUndef);
13170 :
13171 : #undef TEST_TOSTRINGTAG
13172 : #undef TEST_TOSTRINGTAG_TYPES
13173 :
13174 : // @@toStringTag getter throws
13175 5 : Local<Value> obj = v8::Object::New(isolate);
13176 : obj.As<v8::Object>()
13177 10 : ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13178 10 : .FromJust();
13179 : {
13180 5 : TryCatch try_catch(isolate);
13181 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13182 5 : CHECK(try_catch.HasCaught());
13183 : }
13184 :
13185 : // @@toStringTag getter does not throw
13186 5 : obj = v8::Object::New(isolate);
13187 : obj.As<v8::Object>()
13188 : ->SetAccessor(context.local(), toStringTag,
13189 15 : SymbolAccessorGetterReturnsDefault, nullptr, v8_str("Test"))
13190 10 : .FromJust();
13191 : {
13192 5 : TryCatch try_catch(isolate);
13193 : value = obj.As<v8::Object>()
13194 5 : ->ObjectProtoToString(context.local())
13195 5 : .ToLocalChecked();
13196 15 : CHECK(value->IsString() &&
13197 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13198 5 : CHECK(!try_catch.HasCaught());
13199 : }
13200 :
13201 : // JS @@toStringTag value
13202 : obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13203 : {
13204 5 : TryCatch try_catch(isolate);
13205 : value = obj.As<v8::Object>()
13206 5 : ->ObjectProtoToString(context.local())
13207 5 : .ToLocalChecked();
13208 15 : CHECK(value->IsString() &&
13209 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13210 5 : CHECK(!try_catch.HasCaught());
13211 : }
13212 :
13213 : // JS @@toStringTag getter throws
13214 : obj = CompileRun(
13215 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13216 : " get: function() { throw 'Test'; }"
13217 : "}); obj");
13218 : {
13219 5 : TryCatch try_catch(isolate);
13220 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13221 5 : CHECK(try_catch.HasCaught());
13222 : }
13223 :
13224 : // JS @@toStringTag getter does not throw
13225 : obj = CompileRun(
13226 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13227 : " get: function() { return 'Test'; }"
13228 : "}); obj");
13229 : {
13230 5 : TryCatch try_catch(isolate);
13231 : value = obj.As<v8::Object>()
13232 5 : ->ObjectProtoToString(context.local())
13233 5 : .ToLocalChecked();
13234 15 : CHECK(value->IsString() &&
13235 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13236 5 : CHECK(!try_catch.HasCaught());
13237 5 : }
13238 5 : }
13239 :
13240 :
13241 25881 : THREADED_TEST(ObjectGetConstructorName) {
13242 6 : v8::Isolate* isolate = CcTest::isolate();
13243 6 : LocalContext context;
13244 12 : v8::HandleScope scope(isolate);
13245 : v8_compile(
13246 : "function Parent() {};"
13247 : "function Child() {};"
13248 : "Child.prototype = new Parent();"
13249 : "Child.prototype.constructor = Child;"
13250 : "var outer = { inner: (0, function() { }) };"
13251 : "var p = new Parent();"
13252 : "var c = new Child();"
13253 : "var x = new outer.inner();"
13254 : "var proto = Child.prototype;")
13255 6 : ->Run(context.local())
13256 6 : .ToLocalChecked();
13257 :
13258 : Local<v8::Value> p =
13259 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13260 30 : CHECK(p->IsObject() &&
13261 : p->ToObject(context.local())
13262 : .ToLocalChecked()
13263 : ->GetConstructorName()
13264 : ->Equals(context.local(), v8_str("Parent"))
13265 : .FromJust());
13266 :
13267 : Local<v8::Value> c =
13268 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13269 30 : CHECK(c->IsObject() &&
13270 : c->ToObject(context.local())
13271 : .ToLocalChecked()
13272 : ->GetConstructorName()
13273 : ->Equals(context.local(), v8_str("Child"))
13274 : .FromJust());
13275 :
13276 : Local<v8::Value> x =
13277 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13278 30 : CHECK(x->IsObject() &&
13279 : x->ToObject(context.local())
13280 : .ToLocalChecked()
13281 : ->GetConstructorName()
13282 : ->Equals(context.local(), v8_str("outer.inner"))
13283 : .FromJust());
13284 :
13285 : Local<v8::Value> child_prototype =
13286 30 : context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13287 30 : CHECK(child_prototype->IsObject() &&
13288 : child_prototype->ToObject(context.local())
13289 : .ToLocalChecked()
13290 : ->GetConstructorName()
13291 : ->Equals(context.local(), v8_str("Parent"))
13292 6 : .FromJust());
13293 6 : }
13294 :
13295 :
13296 25881 : THREADED_TEST(SubclassGetConstructorName) {
13297 6 : v8::Isolate* isolate = CcTest::isolate();
13298 6 : LocalContext context;
13299 12 : v8::HandleScope scope(isolate);
13300 : v8_compile(
13301 : "\"use strict\";"
13302 : "class Parent {}"
13303 : "class Child extends Parent {}"
13304 : "var p = new Parent();"
13305 : "var c = new Child();")
13306 6 : ->Run(context.local())
13307 6 : .ToLocalChecked();
13308 :
13309 : Local<v8::Value> p =
13310 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13311 30 : CHECK(p->IsObject() &&
13312 : p->ToObject(context.local())
13313 : .ToLocalChecked()
13314 : ->GetConstructorName()
13315 : ->Equals(context.local(), v8_str("Parent"))
13316 : .FromJust());
13317 :
13318 : Local<v8::Value> c =
13319 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13320 30 : CHECK(c->IsObject() &&
13321 : c->ToObject(context.local())
13322 : .ToLocalChecked()
13323 : ->GetConstructorName()
13324 : ->Equals(context.local(), v8_str("Child"))
13325 6 : .FromJust());
13326 6 : }
13327 :
13328 :
13329 : bool ApiTestFuzzer::fuzzing_ = false;
13330 25875 : v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13331 : int ApiTestFuzzer::active_tests_;
13332 : int ApiTestFuzzer::tests_being_run_;
13333 : int ApiTestFuzzer::current_;
13334 :
13335 :
13336 : // We are in a callback and want to switch to another thread (if we
13337 : // are currently running the thread fuzzing test).
13338 460722 : void ApiTestFuzzer::Fuzz() {
13339 921444 : if (!fuzzing_) return;
13340 76307 : ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13341 76307 : test->ContextSwitch();
13342 : }
13343 :
13344 :
13345 : // Let the next thread go. Since it is also waiting on the V8 lock it may
13346 : // not start immediately.
13347 76775 : bool ApiTestFuzzer::NextThread() {
13348 76775 : int test_position = GetNextTestNumber();
13349 76775 : const char* test_name = RegisterThreadedTest::nth(current_)->name();
13350 76775 : if (test_position == current_) {
13351 : if (kLogThreading)
13352 : printf("Stay with %s\n", test_name);
13353 : return false;
13354 : }
13355 : if (kLogThreading) {
13356 : printf("Switch from %s to %s\n",
13357 : test_name,
13358 : RegisterThreadedTest::nth(test_position)->name());
13359 : }
13360 22718 : current_ = test_position;
13361 22718 : RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13362 22718 : return true;
13363 : }
13364 :
13365 :
13366 468 : void ApiTestFuzzer::Run() {
13367 : // When it is our turn...
13368 468 : gate_.Wait();
13369 : {
13370 : // ... get the V8 lock and start running the test.
13371 468 : v8::Locker locker(CcTest::isolate());
13372 468 : CallTest();
13373 : }
13374 : // This test finished.
13375 468 : active_ = false;
13376 468 : active_tests_--;
13377 : // If it was the last then signal that fact.
13378 468 : if (active_tests_ == 0) {
13379 8 : all_tests_done_.Signal();
13380 : } else {
13381 : // Otherwise select a new test and start that.
13382 460 : NextThread();
13383 : }
13384 468 : }
13385 :
13386 :
13387 : static unsigned linear_congruential_generator;
13388 :
13389 :
13390 8 : void ApiTestFuzzer::SetUp(PartOfTest part) {
13391 8 : linear_congruential_generator = i::FLAG_testing_prng_seed;
13392 8 : fuzzing_ = true;
13393 : int count = RegisterThreadedTest::count();
13394 8 : int start = count * part / (LAST_PART + 1);
13395 8 : int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13396 8 : active_tests_ = tests_being_run_ = end - start + 1;
13397 476 : for (int i = 0; i < tests_being_run_; i++) {
13398 468 : RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13399 : }
13400 468 : for (int i = 0; i < active_tests_; i++) {
13401 468 : RegisterThreadedTest::nth(i)->fuzzer_->Start();
13402 : }
13403 8 : }
13404 :
13405 :
13406 : static void CallTestNumber(int test_number) {
13407 468 : (RegisterThreadedTest::nth(test_number)->callback())();
13408 : }
13409 :
13410 :
13411 0 : void ApiTestFuzzer::RunAllTests() {
13412 : // Set off the first test.
13413 8 : current_ = -1;
13414 8 : NextThread();
13415 : // Wait till they are all done.
13416 8 : all_tests_done_.Wait();
13417 0 : }
13418 :
13419 :
13420 76775 : int ApiTestFuzzer::GetNextTestNumber() {
13421 : int next_test;
13422 3133158 : do {
13423 3133158 : next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13424 3133158 : linear_congruential_generator *= 1664525u;
13425 3133158 : linear_congruential_generator += 1013904223u;
13426 3133158 : } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13427 76775 : return next_test;
13428 : }
13429 :
13430 :
13431 76307 : void ApiTestFuzzer::ContextSwitch() {
13432 : // If the new thread is the same as the current thread there is nothing to do.
13433 76307 : if (NextThread()) {
13434 : // Now it can start.
13435 22250 : v8::Unlocker unlocker(CcTest::isolate());
13436 : // Wait till someone starts us again.
13437 22250 : gate_.Wait();
13438 : // And we're off.
13439 : }
13440 76307 : }
13441 :
13442 :
13443 8 : void ApiTestFuzzer::TearDown() {
13444 8 : fuzzing_ = false;
13445 7504 : for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13446 3744 : ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13447 3744 : if (fuzzer != nullptr) fuzzer->Join();
13448 : }
13449 8 : }
13450 :
13451 468 : void ApiTestFuzzer::CallTest() {
13452 468 : v8::Isolate::Scope scope(CcTest::isolate());
13453 : if (kLogThreading)
13454 : printf("Start test %s #%d\n",
13455 : RegisterThreadedTest::nth(test_number_)->name(), test_number_);
13456 468 : CallTestNumber(test_number_);
13457 : if (kLogThreading)
13458 : printf("End test %s #%d\n", RegisterThreadedTest::nth(test_number_)->name(),
13459 : test_number_);
13460 468 : }
13461 :
13462 : #define THREADING_TEST(INDEX, NAME) \
13463 : TEST(Threading##INDEX) { \
13464 : ApiTestFuzzer::SetUp(ApiTestFuzzer::NAME); \
13465 : ApiTestFuzzer::RunAllTests(); \
13466 : ApiTestFuzzer::TearDown(); \
13467 : }
13468 :
13469 25877 : THREADING_TEST(1, FIRST_PART)
13470 25877 : THREADING_TEST(2, SECOND_PART)
13471 25877 : THREADING_TEST(3, THIRD_PART)
13472 25877 : THREADING_TEST(4, FOURTH_PART)
13473 25877 : THREADING_TEST(5, FIFTH_PART)
13474 25877 : THREADING_TEST(6, SIXTH_PART)
13475 25877 : THREADING_TEST(7, SEVENTH_PART)
13476 25877 : THREADING_TEST(8, EIGHTH_PART)
13477 :
13478 : #undef THREADING_TEST
13479 :
13480 10 : static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13481 : v8::Isolate* isolate = args.GetIsolate();
13482 5 : CHECK(v8::Locker::IsLocked(isolate));
13483 5 : ApiTestFuzzer::Fuzz();
13484 : v8::Unlocker unlocker(isolate);
13485 : const char* code = "throw 7;";
13486 : {
13487 : v8::Locker nested_locker(isolate);
13488 10 : v8::HandleScope scope(isolate);
13489 : v8::Local<Value> exception;
13490 : {
13491 5 : v8::TryCatch try_catch(isolate);
13492 : v8::Local<Value> value = CompileRun(code);
13493 5 : CHECK(value.IsEmpty());
13494 5 : CHECK(try_catch.HasCaught());
13495 : // Make sure to wrap the exception in a new handle because
13496 : // the handle returned from the TryCatch is destroyed
13497 : // when the TryCatch is destroyed.
13498 10 : exception = Local<Value>::New(isolate, try_catch.Exception());
13499 : }
13500 10 : args.GetIsolate()->ThrowException(exception);
13501 5 : }
13502 5 : }
13503 :
13504 :
13505 15 : static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13506 5 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13507 5 : ApiTestFuzzer::Fuzz();
13508 5 : v8::Unlocker unlocker(CcTest::isolate());
13509 : const char* code = "throw 7;";
13510 : {
13511 5 : v8::Locker nested_locker(CcTest::isolate());
13512 10 : v8::HandleScope scope(args.GetIsolate());
13513 : v8::Local<Value> value = CompileRun(code);
13514 5 : CHECK(value.IsEmpty());
13515 10 : args.GetReturnValue().Set(v8_str("foo"));
13516 5 : }
13517 5 : }
13518 :
13519 :
13520 : // These are locking tests that don't need to be run again
13521 : // as part of the locking aggregation tests.
13522 25880 : TEST(NestedLockers) {
13523 5 : v8::Isolate* isolate = CcTest::isolate();
13524 : v8::Locker locker(isolate);
13525 5 : CHECK(v8::Locker::IsLocked(isolate));
13526 10 : LocalContext env;
13527 10 : v8::HandleScope scope(env->GetIsolate());
13528 : Local<v8::FunctionTemplate> fun_templ =
13529 5 : v8::FunctionTemplate::New(isolate, ThrowInJS);
13530 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13531 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13532 : Local<Script> script = v8_compile("(function () {"
13533 : " try {"
13534 : " throw_in_js();"
13535 : " return 42;"
13536 : " } catch (e) {"
13537 : " return e * 13;"
13538 : " }"
13539 : "})();");
13540 15 : CHECK_EQ(91, script->Run(env.local())
13541 : .ToLocalChecked()
13542 : ->Int32Value(env.local())
13543 5 : .FromJust());
13544 5 : }
13545 :
13546 :
13547 : // These are locking tests that don't need to be run again
13548 : // as part of the locking aggregation tests.
13549 25880 : TEST(NestedLockersNoTryCatch) {
13550 5 : v8::Locker locker(CcTest::isolate());
13551 10 : LocalContext env;
13552 10 : v8::HandleScope scope(env->GetIsolate());
13553 : Local<v8::FunctionTemplate> fun_templ =
13554 5 : v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13555 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13556 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13557 : Local<Script> script = v8_compile("(function () {"
13558 : " try {"
13559 : " throw_in_js();"
13560 : " return 42;"
13561 : " } catch (e) {"
13562 : " return e * 13;"
13563 : " }"
13564 : "})();");
13565 15 : CHECK_EQ(91, script->Run(env.local())
13566 : .ToLocalChecked()
13567 : ->Int32Value(env.local())
13568 5 : .FromJust());
13569 5 : }
13570 :
13571 :
13572 25881 : THREADED_TEST(RecursiveLocking) {
13573 6 : v8::Locker locker(CcTest::isolate());
13574 : {
13575 6 : v8::Locker locker2(CcTest::isolate());
13576 6 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13577 6 : }
13578 6 : }
13579 :
13580 :
13581 12 : static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13582 12 : ApiTestFuzzer::Fuzz();
13583 24 : v8::Unlocker unlocker(CcTest::isolate());
13584 12 : }
13585 :
13586 :
13587 25881 : THREADED_TEST(LockUnlockLock) {
13588 : {
13589 6 : v8::Locker locker(CcTest::isolate());
13590 12 : v8::HandleScope scope(CcTest::isolate());
13591 12 : LocalContext env;
13592 : Local<v8::FunctionTemplate> fun_templ =
13593 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13594 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13595 30 : CHECK(env->Global()
13596 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13597 : .FromJust());
13598 : Local<Script> script = v8_compile("(function () {"
13599 : " unlock_for_a_moment();"
13600 : " return 42;"
13601 : "})();");
13602 18 : CHECK_EQ(42, script->Run(env.local())
13603 : .ToLocalChecked()
13604 : ->Int32Value(env.local())
13605 6 : .FromJust());
13606 : }
13607 : {
13608 6 : v8::Locker locker(CcTest::isolate());
13609 12 : v8::HandleScope scope(CcTest::isolate());
13610 12 : LocalContext env;
13611 : Local<v8::FunctionTemplate> fun_templ =
13612 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13613 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13614 30 : CHECK(env->Global()
13615 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13616 : .FromJust());
13617 : Local<Script> script = v8_compile("(function () {"
13618 : " unlock_for_a_moment();"
13619 : " return 42;"
13620 : "})();");
13621 18 : CHECK_EQ(42, script->Run(env.local())
13622 : .ToLocalChecked()
13623 : ->Int32Value(env.local())
13624 6 : .FromJust());
13625 : }
13626 6 : }
13627 :
13628 :
13629 130 : static int GetGlobalObjectsCount() {
13630 : int count = 0;
13631 130 : i::HeapIterator it(CcTest::heap());
13632 1400958 : for (i::HeapObject object = it.next(); !object.is_null();
13633 : object = it.next()) {
13634 700349 : if (object->IsJSGlobalObject()) {
13635 30 : i::JSGlobalObject g = i::JSGlobalObject::cast(object);
13636 : // Skip dummy global object.
13637 30 : if (g->global_dictionary()->NumberOfElements() != 0) {
13638 30 : count++;
13639 : }
13640 : }
13641 : }
13642 130 : return count;
13643 : }
13644 :
13645 :
13646 100 : static void CheckSurvivingGlobalObjectsCount(int expected) {
13647 : // We need to collect all garbage twice to be sure that everything
13648 : // has been collected. This is because inline caches are cleared in
13649 : // the first garbage collection but some of the maps have already
13650 : // been marked at that point. Therefore some of the maps are not
13651 : // collected until the second garbage collection.
13652 100 : CcTest::CollectAllGarbage();
13653 100 : CcTest::CollectAllGarbage();
13654 100 : int count = GetGlobalObjectsCount();
13655 100 : CHECK_EQ(expected, count);
13656 100 : }
13657 :
13658 :
13659 25880 : TEST(DontLeakGlobalObjects) {
13660 : // Regression test for issues 1139850 and 1174891.
13661 :
13662 5 : i::FLAG_expose_gc = true;
13663 5 : v8::V8::Initialize();
13664 :
13665 30 : for (int i = 0; i < 5; i++) {
13666 25 : { v8::HandleScope scope(CcTest::isolate());
13667 25 : LocalContext context;
13668 : }
13669 25 : CcTest::isolate()->ContextDisposedNotification();
13670 25 : CheckSurvivingGlobalObjectsCount(0);
13671 :
13672 25 : { v8::HandleScope scope(CcTest::isolate());
13673 50 : LocalContext context;
13674 75 : v8_compile("Date")->Run(context.local()).ToLocalChecked();
13675 : }
13676 25 : CcTest::isolate()->ContextDisposedNotification();
13677 25 : CheckSurvivingGlobalObjectsCount(0);
13678 :
13679 25 : { v8::HandleScope scope(CcTest::isolate());
13680 50 : LocalContext context;
13681 75 : v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
13682 : }
13683 25 : CcTest::isolate()->ContextDisposedNotification();
13684 25 : CheckSurvivingGlobalObjectsCount(0);
13685 :
13686 25 : { v8::HandleScope scope(CcTest::isolate());
13687 25 : const char* extension_list[] = { "v8/gc" };
13688 : v8::ExtensionConfiguration extensions(1, extension_list);
13689 50 : LocalContext context(&extensions);
13690 75 : v8_compile("gc();")->Run(context.local()).ToLocalChecked();
13691 : }
13692 25 : CcTest::isolate()->ContextDisposedNotification();
13693 25 : CheckSurvivingGlobalObjectsCount(0);
13694 : }
13695 5 : }
13696 :
13697 :
13698 25880 : TEST(CopyablePersistent) {
13699 5 : LocalContext context;
13700 5 : v8::Isolate* isolate = context->GetIsolate();
13701 25 : i::GlobalHandles* globals =
13702 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13703 : size_t initial_handles = globals->handles_count();
13704 : typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13705 : CopyableObject;
13706 : {
13707 : CopyableObject handle1;
13708 : {
13709 5 : v8::HandleScope scope(isolate);
13710 10 : handle1.Reset(isolate, v8::Object::New(isolate));
13711 : }
13712 5 : CHECK_EQ(initial_handles + 1, globals->handles_count());
13713 : CopyableObject handle2;
13714 : handle2 = handle1;
13715 5 : CHECK(handle1 == handle2);
13716 5 : CHECK_EQ(initial_handles + 2, globals->handles_count());
13717 : CopyableObject handle3(handle2);
13718 5 : CHECK(handle1 == handle3);
13719 5 : CHECK_EQ(initial_handles + 3, globals->handles_count());
13720 : }
13721 : // Verify autodispose
13722 5 : CHECK_EQ(initial_handles, globals->handles_count());
13723 5 : }
13724 :
13725 :
13726 5 : static void WeakApiCallback(
13727 10 : const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
13728 : data.GetParameter()->Reset();
13729 5 : delete data.GetParameter();
13730 5 : }
13731 :
13732 :
13733 25880 : TEST(WeakCallbackApi) {
13734 5 : LocalContext context;
13735 5 : v8::Isolate* isolate = context->GetIsolate();
13736 10 : i::GlobalHandles* globals =
13737 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13738 : size_t initial_handles = globals->handles_count();
13739 : {
13740 5 : v8::HandleScope scope(isolate);
13741 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
13742 25 : CHECK(
13743 : obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
13744 : .FromJust());
13745 : v8::Persistent<v8::Object>* handle =
13746 5 : new v8::Persistent<v8::Object>(isolate, obj);
13747 : handle->SetWeak<v8::Persistent<v8::Object>>(
13748 5 : handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
13749 : }
13750 5 : CcTest::PreciseCollectAllGarbage();
13751 : // Verify disposed.
13752 5 : CHECK_EQ(initial_handles, globals->handles_count());
13753 5 : }
13754 :
13755 :
13756 25875 : v8::Persistent<v8::Object> some_object;
13757 25875 : v8::Persistent<v8::Object> bad_handle;
13758 :
13759 :
13760 6 : void NewPersistentHandleCallback2(
13761 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13762 6 : v8::HandleScope scope(data.GetIsolate());
13763 6 : bad_handle.Reset(data.GetIsolate(), some_object);
13764 6 : }
13765 :
13766 :
13767 6 : void NewPersistentHandleCallback1(
13768 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13769 : data.GetParameter()->Reset();
13770 : data.SetSecondPassCallback(NewPersistentHandleCallback2);
13771 6 : }
13772 :
13773 :
13774 25881 : THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13775 6 : LocalContext context;
13776 6 : v8::Isolate* isolate = context->GetIsolate();
13777 :
13778 : v8::Persistent<v8::Object> handle1, handle2;
13779 : {
13780 6 : v8::HandleScope scope(isolate);
13781 12 : some_object.Reset(isolate, v8::Object::New(isolate));
13782 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13783 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13784 : }
13785 : // Note: order is implementation dependent alas: currently
13786 : // global handle nodes are processed by PostGarbageCollectionProcessing
13787 : // in reverse allocation order, so if second allocated handle is deleted,
13788 : // weak callback of the first handle would be able to 'reallocate' it.
13789 : handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
13790 : v8::WeakCallbackType::kParameter);
13791 : handle2.Reset();
13792 6 : CcTest::CollectAllGarbage();
13793 6 : }
13794 :
13795 :
13796 25875 : v8::Persistent<v8::Object> to_be_disposed;
13797 :
13798 :
13799 6 : void DisposeAndForceGcCallback2(
13800 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13801 : to_be_disposed.Reset();
13802 6 : CcTest::CollectAllGarbage();
13803 6 : }
13804 :
13805 :
13806 6 : void DisposeAndForceGcCallback1(
13807 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13808 : data.GetParameter()->Reset();
13809 : data.SetSecondPassCallback(DisposeAndForceGcCallback2);
13810 6 : }
13811 :
13812 :
13813 25881 : THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13814 6 : LocalContext context;
13815 6 : v8::Isolate* isolate = context->GetIsolate();
13816 :
13817 : v8::Persistent<v8::Object> handle1, handle2;
13818 : {
13819 6 : v8::HandleScope scope(isolate);
13820 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13821 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13822 : }
13823 : handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
13824 : v8::WeakCallbackType::kParameter);
13825 : to_be_disposed.Reset(isolate, handle2);
13826 6 : CcTest::CollectAllGarbage();
13827 6 : }
13828 :
13829 6 : void DisposingCallback(
13830 6 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13831 : data.GetParameter()->Reset();
13832 6 : }
13833 :
13834 6 : void HandleCreatingCallback2(
13835 18 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13836 6 : v8::HandleScope scope(data.GetIsolate());
13837 12 : v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
13838 6 : }
13839 :
13840 :
13841 6 : void HandleCreatingCallback1(
13842 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13843 : data.GetParameter()->Reset();
13844 : data.SetSecondPassCallback(HandleCreatingCallback2);
13845 6 : }
13846 :
13847 :
13848 25881 : THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13849 6 : v8::Locker locker(CcTest::isolate());
13850 12 : LocalContext context;
13851 6 : v8::Isolate* isolate = context->GetIsolate();
13852 :
13853 : v8::Persistent<v8::Object> handle1, handle2, handle3;
13854 : {
13855 6 : v8::HandleScope scope(isolate);
13856 12 : handle3.Reset(isolate, v8::Object::New(isolate));
13857 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13858 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13859 : }
13860 : handle2.SetWeak(&handle2, DisposingCallback,
13861 : v8::WeakCallbackType::kParameter);
13862 : handle3.SetWeak(&handle3, HandleCreatingCallback1,
13863 : v8::WeakCallbackType::kParameter);
13864 6 : CcTest::CollectAllGarbage();
13865 12 : EmptyMessageQueues(isolate);
13866 6 : }
13867 :
13868 :
13869 25881 : THREADED_TEST(CheckForCrossContextObjectLiterals) {
13870 6 : v8::V8::Initialize();
13871 :
13872 : const int nof = 2;
13873 : const char* sources[nof] = {
13874 : "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13875 : "Object()"
13876 6 : };
13877 :
13878 18 : for (int i = 0; i < nof; i++) {
13879 12 : const char* source = sources[i];
13880 12 : { v8::HandleScope scope(CcTest::isolate());
13881 24 : LocalContext context;
13882 12 : CompileRun(source);
13883 : }
13884 12 : { v8::HandleScope scope(CcTest::isolate());
13885 24 : LocalContext context;
13886 12 : CompileRun(source);
13887 : }
13888 : }
13889 6 : }
13890 :
13891 :
13892 6 : static v8::Local<Value> NestedScope(v8::Local<Context> env) {
13893 6 : v8::EscapableHandleScope inner(env->GetIsolate());
13894 6 : env->Enter();
13895 6 : v8::Local<Value> three = v8_num(3);
13896 : v8::Local<Value> value = inner.Escape(three);
13897 6 : env->Exit();
13898 12 : return value;
13899 : }
13900 :
13901 :
13902 25881 : THREADED_TEST(NestedHandleScopeAndContexts) {
13903 6 : v8::Isolate* isolate = CcTest::isolate();
13904 6 : v8::HandleScope outer(isolate);
13905 6 : v8::Local<Context> env = Context::New(isolate);
13906 6 : env->Enter();
13907 6 : v8::Local<Value> value = NestedScope(env);
13908 6 : v8::Local<String> str(value->ToString(env).ToLocalChecked());
13909 6 : CHECK(!str.IsEmpty());
13910 6 : env->Exit();
13911 6 : }
13912 :
13913 : static v8::base::HashMap* code_map = nullptr;
13914 : static v8::base::HashMap* jitcode_line_info = nullptr;
13915 : static int saw_bar = 0;
13916 : static int move_events = 0;
13917 :
13918 :
13919 5361 : static bool FunctionNameIs(const char* expected,
13920 : const v8::JitCodeEvent* event) {
13921 : // Log lines for functions are of the general form:
13922 : // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
13923 : // where the type is one of "*", "~" or "".
13924 : static const char* kPreamble;
13925 5361 : if (!i::FLAG_lazy) {
13926 0 : kPreamble = "Function:";
13927 : } else {
13928 5361 : kPreamble = "LazyCompile:";
13929 : }
13930 5361 : static size_t kPreambleLen = strlen(kPreamble);
13931 :
13932 10667 : if (event->name.len < kPreambleLen ||
13933 5306 : strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13934 : return false;
13935 : }
13936 :
13937 153 : const char* tail = event->name.str + kPreambleLen;
13938 153 : size_t tail_len = event->name.len - kPreambleLen;
13939 153 : size_t expected_len = strlen(expected);
13940 153 : if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13941 148 : --tail_len;
13942 148 : ++tail;
13943 : }
13944 :
13945 : // Check for tails like 'bar :1'.
13946 285 : if (tail_len > expected_len + 2 &&
13947 264 : tail[expected_len] == ' ' &&
13948 264 : tail[expected_len + 1] == ':' &&
13949 264 : tail[expected_len + 2] &&
13950 132 : !strncmp(tail, expected, expected_len)) {
13951 : return true;
13952 : }
13953 :
13954 87 : if (tail_len != expected_len)
13955 : return false;
13956 :
13957 21 : return strncmp(tail, expected, expected_len) == 0;
13958 : }
13959 :
13960 :
13961 7688 : static void event_handler(const v8::JitCodeEvent* event) {
13962 7688 : CHECK_NOT_NULL(event);
13963 7688 : CHECK_NOT_NULL(code_map);
13964 7688 : CHECK_NOT_NULL(jitcode_line_info);
13965 :
13966 : class DummyJitCodeLineInfo {
13967 : };
13968 :
13969 7688 : switch (event->type) {
13970 : case v8::JitCodeEvent::CODE_ADDED: {
13971 5361 : CHECK_NOT_NULL(event->code_start);
13972 5361 : CHECK_NE(0, static_cast<int>(event->code_len));
13973 5361 : CHECK_NOT_NULL(event->name.str);
13974 : v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
13975 5361 : event->code_start, i::ComputePointerHash(event->code_start));
13976 5361 : entry->value = reinterpret_cast<void*>(event->code_len);
13977 :
13978 5361 : if (FunctionNameIs("bar", event)) {
13979 66 : ++saw_bar;
13980 : }
13981 : }
13982 : break;
13983 :
13984 : case v8::JitCodeEvent::CODE_MOVED: {
13985 197 : uint32_t hash = i::ComputePointerHash(event->code_start);
13986 : // We would like to never see code move that we haven't seen before,
13987 : // but the code creation event does not happen until the line endings
13988 : // have been calculated (this is so that we can report the line in the
13989 : // script at which the function source is found, see
13990 : // Compiler::RecordFunctionCompilation) and the line endings
13991 : // calculations can cause a GC, which can move the newly created code
13992 : // before its existence can be logged.
13993 : v8::base::HashMap::Entry* entry =
13994 197 : code_map->Lookup(event->code_start, hash);
13995 197 : if (entry != nullptr) {
13996 197 : ++move_events;
13997 :
13998 197 : CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
13999 197 : code_map->Remove(event->code_start, hash);
14000 :
14001 : entry = code_map->LookupOrInsert(
14002 : event->new_code_start,
14003 394 : i::ComputePointerHash(event->new_code_start));
14004 197 : entry->value = reinterpret_cast<void*>(event->code_len);
14005 : }
14006 : }
14007 : break;
14008 :
14009 : case v8::JitCodeEvent::CODE_REMOVED:
14010 : // Object/code removal events are currently not dispatched from the GC.
14011 0 : UNREACHABLE();
14012 :
14013 : // For CODE_START_LINE_INFO_RECORDING event, we will create one
14014 : // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14015 : // record it in jitcode_line_info.
14016 : case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14017 180 : DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14018 : v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14019 180 : temp_event->user_data = line_info;
14020 : v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14021 360 : line_info, i::ComputePointerHash(line_info));
14022 180 : entry->value = reinterpret_cast<void*>(line_info);
14023 : }
14024 180 : break;
14025 : // For these two events, we will check whether the event->user_data
14026 : // data structure is created before during CODE_START_LINE_INFO_RECORDING
14027 : // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14028 : case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14029 180 : CHECK_NOT_NULL(event->user_data);
14030 : uint32_t hash = i::ComputePointerHash(event->user_data);
14031 : v8::base::HashMap::Entry* entry =
14032 180 : jitcode_line_info->Lookup(event->user_data, hash);
14033 180 : CHECK_NOT_NULL(entry);
14034 180 : delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14035 : }
14036 180 : break;
14037 :
14038 : case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14039 1770 : CHECK_NOT_NULL(event->user_data);
14040 : uint32_t hash = i::ComputePointerHash(event->user_data);
14041 : v8::base::HashMap::Entry* entry =
14042 1770 : jitcode_line_info->Lookup(event->user_data, hash);
14043 1770 : CHECK_NOT_NULL(entry);
14044 : }
14045 : break;
14046 :
14047 : default:
14048 : // Impossible event.
14049 0 : UNREACHABLE();
14050 : }
14051 7688 : }
14052 :
14053 :
14054 25880 : UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14055 5 : i::FLAG_stress_compaction = true;
14056 5 : i::FLAG_incremental_marking = false;
14057 5 : if (i::FLAG_never_compact) return;
14058 : const char* script =
14059 : "function bar() {"
14060 : " var sum = 0;"
14061 : " for (i = 0; i < 10; ++i)"
14062 : " sum = foo(i);"
14063 : " return sum;"
14064 : "}"
14065 : "function foo(i) { return i; };"
14066 : "bar();";
14067 :
14068 : // Run this test in a new isolate to make sure we don't
14069 : // have remnants of state from other code.
14070 : v8::Isolate::CreateParams create_params;
14071 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14072 55 : v8::Isolate* isolate = v8::Isolate::New(create_params);
14073 5 : isolate->Enter();
14074 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14075 5 : i::Heap* heap = i_isolate->heap();
14076 :
14077 : // Start with a clean slate.
14078 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14079 :
14080 : {
14081 5 : v8::HandleScope scope(isolate);
14082 : v8::base::HashMap code;
14083 5 : code_map = &code;
14084 :
14085 : v8::base::HashMap lineinfo;
14086 5 : jitcode_line_info = &lineinfo;
14087 :
14088 5 : saw_bar = 0;
14089 5 : move_events = 0;
14090 :
14091 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14092 :
14093 : // Generate new code objects sparsely distributed across several
14094 : // different fragmented code-space pages.
14095 : const int kIterations = 10;
14096 55 : for (int i = 0; i < kIterations; ++i) {
14097 : LocalContext env(isolate);
14098 : i::AlwaysAllocateScope always_allocate(i_isolate);
14099 : CompileRun(script);
14100 :
14101 : // Keep a strong reference to the code object in the handle scope.
14102 : i::Handle<i::JSFunction> bar(i::Handle<i::JSFunction>::cast(
14103 : v8::Utils::OpenHandle(*env->Global()
14104 200 : ->Get(env.local(), v8_str("bar"))
14105 100 : .ToLocalChecked())));
14106 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
14107 : v8::Utils::OpenHandle(*env->Global()
14108 200 : ->Get(env.local(), v8_str("foo"))
14109 100 : .ToLocalChecked())));
14110 :
14111 : i::PagedSpace* foo_owning_space = reinterpret_cast<i::PagedSpace*>(
14112 100 : i::Page::FromHeapObject(foo->abstract_code())->owner());
14113 : i::PagedSpace* bar_owning_space = reinterpret_cast<i::PagedSpace*>(
14114 100 : i::Page::FromHeapObject(bar->abstract_code())->owner());
14115 50 : CHECK_EQ(foo_owning_space, bar_owning_space);
14116 50 : i::heap::SimulateFullSpace(foo_owning_space);
14117 :
14118 : // Clear the compilation cache to get more wastage.
14119 50 : reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14120 50 : }
14121 :
14122 : // Force code movement.
14123 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14124 :
14125 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14126 :
14127 5 : CHECK_LE(kIterations, saw_bar);
14128 5 : CHECK_LT(0, move_events);
14129 :
14130 5 : code_map = nullptr;
14131 10 : jitcode_line_info = nullptr;
14132 : }
14133 :
14134 5 : isolate->Exit();
14135 5 : isolate->Dispose();
14136 :
14137 : // Do this in a new isolate.
14138 5 : isolate = v8::Isolate::New(create_params);
14139 5 : isolate->Enter();
14140 :
14141 : // Verify that we get callbacks for existing code objects when we
14142 : // request enumeration of existing code.
14143 : {
14144 5 : v8::HandleScope scope(isolate);
14145 5 : LocalContext env(isolate);
14146 : CompileRun(script);
14147 :
14148 : // Now get code through initial iteration.
14149 : v8::base::HashMap code;
14150 5 : code_map = &code;
14151 :
14152 : v8::base::HashMap lineinfo;
14153 5 : jitcode_line_info = &lineinfo;
14154 :
14155 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14156 5 : event_handler);
14157 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14158 :
14159 5 : jitcode_line_info = nullptr;
14160 : // We expect that we got some events. Note that if we could get code removal
14161 : // notifications, we could compare two collections, one created by listening
14162 : // from the time of creation of an isolate, and the other by subscribing
14163 : // with EnumExisting.
14164 5 : CHECK_LT(0u, code.occupancy());
14165 :
14166 10 : code_map = nullptr;
14167 : }
14168 :
14169 5 : isolate->Exit();
14170 5 : isolate->Dispose();
14171 : }
14172 :
14173 25880 : TEST(ExternalAllocatedMemory) {
14174 5 : v8::Isolate* isolate = CcTest::isolate();
14175 5 : v8::HandleScope outer(isolate);
14176 5 : v8::Local<Context> env(Context::New(isolate));
14177 5 : CHECK(!env.IsEmpty());
14178 : const int64_t kSize = 1024*1024;
14179 : int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14180 5 : CHECK_EQ(baseline + kSize,
14181 : isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14182 5 : CHECK_EQ(baseline,
14183 : isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14184 : const int64_t kTriggerGCSize =
14185 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14186 5 : CHECK_EQ(baseline + kTriggerGCSize,
14187 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14188 10 : CHECK_EQ(baseline,
14189 5 : isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14190 5 : }
14191 :
14192 :
14193 25880 : TEST(Regress51719) {
14194 5 : i::FLAG_incremental_marking = false;
14195 5 : CcTest::InitializeVM();
14196 :
14197 : const int64_t kTriggerGCSize =
14198 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14199 5 : v8::Isolate* isolate = CcTest::isolate();
14200 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14201 5 : }
14202 :
14203 : // Regression test for issue 54, object templates with embedder fields
14204 : // but no accessors or interceptors did not get their embedder field
14205 : // count set on instances.
14206 25881 : THREADED_TEST(Regress54) {
14207 6 : LocalContext context;
14208 6 : v8::Isolate* isolate = context->GetIsolate();
14209 12 : v8::HandleScope outer(isolate);
14210 12 : static v8::Persistent<v8::ObjectTemplate> templ;
14211 6 : if (templ.IsEmpty()) {
14212 6 : v8::EscapableHandleScope inner(isolate);
14213 6 : v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14214 6 : local->SetInternalFieldCount(1);
14215 : templ.Reset(isolate, inner.Escape(local));
14216 : }
14217 : v8::Local<v8::Object> result =
14218 : v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14219 6 : ->NewInstance(context.local())
14220 6 : .ToLocalChecked();
14221 12 : CHECK_EQ(1, result->InternalFieldCount());
14222 6 : }
14223 :
14224 :
14225 : // If part of the threaded tests, this test makes ThreadingTest fail
14226 : // on mac.
14227 25880 : TEST(CatchStackOverflow) {
14228 5 : LocalContext context;
14229 10 : v8::HandleScope scope(context->GetIsolate());
14230 10 : v8::TryCatch try_catch(context->GetIsolate());
14231 : v8::Local<v8::Value> result = CompileRun(
14232 : "function f() {"
14233 : " return f();"
14234 : "}"
14235 : ""
14236 : "f();");
14237 10 : CHECK(result.IsEmpty());
14238 5 : }
14239 :
14240 :
14241 18 : static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14242 : const char* resource_name,
14243 : int line_offset) {
14244 18 : v8::HandleScope scope(CcTest::isolate());
14245 36 : v8::TryCatch try_catch(CcTest::isolate());
14246 18 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14247 36 : CHECK(script->Run(context).IsEmpty());
14248 18 : CHECK(try_catch.HasCaught());
14249 18 : v8::Local<v8::Message> message = try_catch.Message();
14250 18 : CHECK(!message.IsEmpty());
14251 36 : CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14252 18 : CHECK_EQ(91, message->GetStartPosition());
14253 18 : CHECK_EQ(92, message->GetEndPosition());
14254 36 : CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14255 36 : CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14256 : v8::String::Utf8Value line(CcTest::isolate(),
14257 54 : message->GetSourceLine(context).ToLocalChecked());
14258 18 : CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14259 : v8::String::Utf8Value name(CcTest::isolate(),
14260 36 : message->GetScriptOrigin().ResourceName());
14261 36 : CHECK_EQ(0, strcmp(resource_name, *name));
14262 18 : }
14263 :
14264 :
14265 25881 : THREADED_TEST(TryCatchSourceInfo) {
14266 6 : LocalContext context;
14267 12 : v8::HandleScope scope(context->GetIsolate());
14268 : v8::Local<v8::String> source = v8_str(
14269 : "function Foo() {\n"
14270 : " return Bar();\n"
14271 : "}\n"
14272 : "\n"
14273 : "function Bar() {\n"
14274 : " return Baz();\n"
14275 : "}\n"
14276 : "\n"
14277 : "function Baz() {\n"
14278 : " throw 'nirk';\n"
14279 : "}\n"
14280 : "\n"
14281 6 : "Foo();\n");
14282 :
14283 : const char* resource_name;
14284 : v8::Local<v8::Script> script;
14285 : resource_name = "test.js";
14286 6 : script = CompileWithOrigin(source, resource_name);
14287 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14288 :
14289 : resource_name = "test1.js";
14290 6 : v8::ScriptOrigin origin1(v8_str(resource_name));
14291 : script =
14292 12 : v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
14293 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14294 :
14295 : resource_name = "test2.js";
14296 : v8::ScriptOrigin origin2(v8_str(resource_name),
14297 6 : v8::Integer::New(context->GetIsolate(), 7));
14298 : script =
14299 12 : v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
14300 12 : CheckTryCatchSourceInfo(script, resource_name, 7);
14301 6 : }
14302 :
14303 :
14304 25881 : THREADED_TEST(TryCatchSourceInfoForEOSError) {
14305 6 : LocalContext context;
14306 12 : v8::HandleScope scope(context->GetIsolate());
14307 12 : v8::TryCatch try_catch(context->GetIsolate());
14308 12 : CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
14309 6 : CHECK(try_catch.HasCaught());
14310 6 : v8::Local<v8::Message> message = try_catch.Message();
14311 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
14312 18 : CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
14313 6 : }
14314 :
14315 :
14316 25881 : THREADED_TEST(CompilationCache) {
14317 6 : LocalContext context;
14318 12 : v8::HandleScope scope(context->GetIsolate());
14319 6 : v8::Local<v8::String> source0 = v8_str("1234");
14320 6 : v8::Local<v8::String> source1 = v8_str("1234");
14321 : v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14322 : v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14323 6 : v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
14324 6 : .ToLocalChecked(); // different origin
14325 18 : CHECK_EQ(1234, script0->Run(context.local())
14326 : .ToLocalChecked()
14327 : ->Int32Value(context.local())
14328 : .FromJust());
14329 18 : CHECK_EQ(1234, script1->Run(context.local())
14330 : .ToLocalChecked()
14331 : ->Int32Value(context.local())
14332 : .FromJust());
14333 18 : CHECK_EQ(1234, script2->Run(context.local())
14334 : .ToLocalChecked()
14335 : ->Int32Value(context.local())
14336 6 : .FromJust());
14337 6 : }
14338 :
14339 :
14340 0 : static void FunctionNameCallback(
14341 0 : const v8::FunctionCallbackInfo<v8::Value>& args) {
14342 0 : ApiTestFuzzer::Fuzz();
14343 0 : args.GetReturnValue().Set(v8_num(42));
14344 0 : }
14345 :
14346 :
14347 25881 : THREADED_TEST(CallbackFunctionName) {
14348 6 : LocalContext context;
14349 6 : v8::Isolate* isolate = context->GetIsolate();
14350 12 : v8::HandleScope scope(isolate);
14351 6 : Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14352 : t->Set(v8_str("asdf"),
14353 18 : v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14354 36 : CHECK(context->Global()
14355 : ->Set(context.local(), v8_str("obj"),
14356 : t->NewInstance(context.local()).ToLocalChecked())
14357 : .FromJust());
14358 : v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
14359 6 : CHECK(value->IsString());
14360 12 : v8::String::Utf8Value name(isolate, value);
14361 12 : CHECK_EQ(0, strcmp("asdf", *name));
14362 6 : }
14363 :
14364 :
14365 25881 : THREADED_TEST(DateAccess) {
14366 6 : LocalContext context;
14367 12 : v8::HandleScope scope(context->GetIsolate());
14368 : v8::Local<v8::Value> date =
14369 6 : v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
14370 6 : CHECK(date->IsDate());
14371 12 : CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14372 6 : }
14373 :
14374 48 : void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14375 : unsigned index, const char* name) {
14376 48 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14377 : v8::Local<v8::Value> value =
14378 96 : properties->Get(context, v8::Integer::New(isolate, index))
14379 48 : .ToLocalChecked();
14380 48 : CHECK(value->IsSymbol());
14381 : v8::String::Utf8Value symbol_name(isolate,
14382 48 : Local<Symbol>::Cast(value)->Name());
14383 48 : if (strcmp(name, *symbol_name) != 0) {
14384 : FATAL("properties[%u] was Symbol('%s') instead of Symbol('%s').", index,
14385 0 : name, *symbol_name);
14386 48 : }
14387 48 : }
14388 :
14389 150 : void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14390 : unsigned length, const char* names[]) {
14391 150 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14392 150 : CHECK_EQ(length, properties->Length());
14393 924 : for (unsigned i = 0; i < length; i++) {
14394 : v8::Local<v8::Value> value =
14395 2772 : properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
14396 924 : if (names[i] == nullptr) {
14397 : DCHECK(value->IsSymbol());
14398 : } else {
14399 876 : v8::String::Utf8Value elm(isolate, value);
14400 876 : if (strcmp(names[i], *elm) != 0) {
14401 0 : FATAL("properties[%u] was '%s' instead of '%s'.", i, *elm, names[i]);
14402 876 : }
14403 : }
14404 : }
14405 150 : }
14406 :
14407 42 : void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14408 : unsigned length, const char* names[]) {
14409 42 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14410 : v8::Local<v8::Object> obj = val.As<v8::Object>();
14411 84 : v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
14412 42 : CheckStringArray(isolate, props, length, names);
14413 42 : }
14414 :
14415 :
14416 24 : void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14417 : unsigned elmc, const char* elmv[]) {
14418 24 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14419 : v8::Local<v8::Object> obj = val.As<v8::Object>();
14420 : v8::Local<v8::Array> props =
14421 24 : obj->GetOwnPropertyNames(context).ToLocalChecked();
14422 24 : CHECK_EQ(elmc, props->Length());
14423 42 : for (unsigned i = 0; i < elmc; i++) {
14424 : v8::String::Utf8Value elm(
14425 : isolate,
14426 126 : props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
14427 42 : CHECK_EQ(0, strcmp(elmv[i], *elm));
14428 42 : }
14429 24 : }
14430 :
14431 :
14432 25881 : THREADED_TEST(PropertyEnumeration) {
14433 6 : LocalContext context;
14434 6 : v8::Isolate* isolate = context->GetIsolate();
14435 12 : v8::HandleScope scope(isolate);
14436 : v8::Local<v8::Value> obj = CompileRun(
14437 : "var result = [];"
14438 : "result[0] = {};"
14439 : "result[1] = {a: 1, b: 2};"
14440 : "result[2] = [1, 2, 3];"
14441 : "var proto = {x: 1, y: 2, z: 3};"
14442 : "var x = { __proto__: proto, w: 0, z: 1 };"
14443 : "result[3] = x;"
14444 : "result[4] = {21350:1};"
14445 : "x = Object.create(null);"
14446 : "x.a = 1; x[12345678] = 1;"
14447 : "result[5] = x;"
14448 : "result;");
14449 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
14450 6 : CHECK_EQ(6u, elms->Length());
14451 : int elmc0 = 0;
14452 : const char** elmv0 = nullptr;
14453 : CheckProperties(
14454 : isolate,
14455 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14456 12 : elmc0, elmv0);
14457 : CheckOwnProperties(
14458 : isolate,
14459 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14460 12 : elmc0, elmv0);
14461 : int elmc1 = 2;
14462 6 : const char* elmv1[] = {"a", "b"};
14463 : CheckProperties(
14464 : isolate,
14465 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14466 12 : elmc1, elmv1);
14467 : CheckOwnProperties(
14468 : isolate,
14469 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14470 12 : elmc1, elmv1);
14471 : int elmc2 = 3;
14472 6 : const char* elmv2[] = {"0", "1", "2"};
14473 : CheckProperties(
14474 : isolate,
14475 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14476 12 : elmc2, elmv2);
14477 : CheckOwnProperties(
14478 : isolate,
14479 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14480 12 : elmc2, elmv2);
14481 : int elmc3 = 4;
14482 6 : const char* elmv3[] = {"w", "z", "x", "y"};
14483 : CheckProperties(
14484 : isolate,
14485 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14486 12 : elmc3, elmv3);
14487 : int elmc4 = 2;
14488 6 : const char* elmv4[] = {"w", "z"};
14489 : CheckOwnProperties(
14490 : isolate,
14491 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14492 12 : elmc4, elmv4);
14493 : // Dictionary elements.
14494 : int elmc5 = 1;
14495 6 : const char* elmv5[] = {"21350"};
14496 : CheckProperties(
14497 : isolate,
14498 18 : elms->Get(context.local(), v8::Integer::New(isolate, 4)).ToLocalChecked(),
14499 12 : elmc5, elmv5);
14500 : // Dictionary properties.
14501 : int elmc6 = 2;
14502 6 : const char* elmv6[] = {"12345678", "a"};
14503 : CheckProperties(
14504 : isolate,
14505 18 : elms->Get(context.local(), v8::Integer::New(isolate, 5)).ToLocalChecked(),
14506 18 : elmc6, elmv6);
14507 6 : }
14508 :
14509 :
14510 25881 : THREADED_TEST(PropertyEnumeration2) {
14511 6 : LocalContext context;
14512 6 : v8::Isolate* isolate = context->GetIsolate();
14513 12 : v8::HandleScope scope(isolate);
14514 : v8::Local<v8::Value> obj = CompileRun(
14515 : "var result = [];"
14516 : "result[0] = {};"
14517 : "result[1] = {a: 1, b: 2};"
14518 : "result[2] = [1, 2, 3];"
14519 : "var proto = {x: 1, y: 2, z: 3};"
14520 : "var x = { __proto__: proto, w: 0, z: 1 };"
14521 : "result[3] = x;"
14522 : "result;");
14523 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
14524 6 : CHECK_EQ(4u, elms->Length());
14525 : int elmc0 = 0;
14526 : const char** elmv0 = nullptr;
14527 : CheckProperties(
14528 : isolate,
14529 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14530 12 : elmc0, elmv0);
14531 :
14532 : v8::Local<v8::Value> val =
14533 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
14534 : v8::Local<v8::Array> props =
14535 6 : val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
14536 6 : CHECK_EQ(0u, props->Length());
14537 0 : for (uint32_t i = 0; i < props->Length(); i++) {
14538 : printf("p[%u]\n", i);
14539 6 : }
14540 6 : }
14541 :
14542 25881 : THREADED_TEST(GetPropertyNames) {
14543 6 : LocalContext context;
14544 6 : v8::Isolate* isolate = context->GetIsolate();
14545 12 : v8::HandleScope scope(isolate);
14546 : v8::Local<v8::Value> result = CompileRun(
14547 : "var result = {0: 0, 1: 1, a: 2, b: 3};"
14548 : "result[2**32] = '4294967296';"
14549 : "result[2**32-1] = '4294967295';"
14550 : "result[2**32-2] = '4294967294';"
14551 : "result[Symbol('symbol')] = true;"
14552 : "result.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14553 : "result;");
14554 : v8::Local<v8::Object> object = result.As<v8::Object>();
14555 : v8::PropertyFilter default_filter =
14556 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14557 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14558 :
14559 : v8::Local<v8::Array> properties =
14560 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
14561 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14562 : "b", "4294967296", "4294967295", "2",
14563 6 : "3", "c", "d"};
14564 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14565 :
14566 : properties =
14567 : object
14568 : ->GetPropertyNames(context.local(),
14569 : v8::KeyCollectionMode::kIncludePrototypes,
14570 6 : default_filter, v8::IndexFilter::kIncludeIndices)
14571 12 : .ToLocalChecked();
14572 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14573 :
14574 : properties = object
14575 : ->GetPropertyNames(context.local(),
14576 : v8::KeyCollectionMode::kIncludePrototypes,
14577 : include_symbols_filter,
14578 6 : v8::IndexFilter::kIncludeIndices)
14579 12 : .ToLocalChecked();
14580 : const char* expected_properties1_1[] = {
14581 : "0", "1", "4294967294", "a", "b", "4294967296",
14582 6 : "4294967295", nullptr, "2", "3", "c", "d"};
14583 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
14584 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14585 :
14586 : properties =
14587 : object
14588 : ->GetPropertyNames(context.local(),
14589 : v8::KeyCollectionMode::kIncludePrototypes,
14590 6 : default_filter, v8::IndexFilter::kSkipIndices)
14591 12 : .ToLocalChecked();
14592 : const char* expected_properties2[] = {"a", "b", "4294967296",
14593 6 : "4294967295", "c", "d"};
14594 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
14595 :
14596 : properties = object
14597 : ->GetPropertyNames(context.local(),
14598 : v8::KeyCollectionMode::kIncludePrototypes,
14599 : include_symbols_filter,
14600 6 : v8::IndexFilter::kSkipIndices)
14601 12 : .ToLocalChecked();
14602 : const char* expected_properties2_1[] = {
14603 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14604 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
14605 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14606 :
14607 : properties =
14608 : object
14609 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14610 6 : default_filter, v8::IndexFilter::kIncludeIndices)
14611 12 : .ToLocalChecked();
14612 : const char* expected_properties3[] = {
14613 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295",
14614 6 : };
14615 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
14616 :
14617 : properties = object
14618 : ->GetPropertyNames(
14619 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14620 6 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14621 12 : .ToLocalChecked();
14622 : const char* expected_properties3_1[] = {
14623 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14624 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
14625 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14626 :
14627 : properties =
14628 : object
14629 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14630 6 : default_filter, v8::IndexFilter::kSkipIndices)
14631 12 : .ToLocalChecked();
14632 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14633 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
14634 :
14635 : properties = object
14636 : ->GetPropertyNames(
14637 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14638 6 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
14639 12 : .ToLocalChecked();
14640 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14641 6 : nullptr};
14642 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
14643 12 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14644 6 : }
14645 :
14646 25881 : THREADED_TEST(ProxyGetPropertyNames) {
14647 6 : LocalContext context;
14648 6 : v8::Isolate* isolate = context->GetIsolate();
14649 12 : v8::HandleScope scope(isolate);
14650 : v8::Local<v8::Value> result = CompileRun(
14651 : "var target = {0: 0, 1: 1, a: 2, b: 3};"
14652 : "target[2**32] = '4294967296';"
14653 : "target[2**32-1] = '4294967295';"
14654 : "target[2**32-2] = '4294967294';"
14655 : "target[Symbol('symbol')] = true;"
14656 : "target.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14657 : "var result = new Proxy(target, {});"
14658 : "result;");
14659 : v8::Local<v8::Object> object = result.As<v8::Object>();
14660 : v8::PropertyFilter default_filter =
14661 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14662 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14663 :
14664 : v8::Local<v8::Array> properties =
14665 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
14666 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14667 : "b", "4294967296", "4294967295", "2",
14668 6 : "3", "c", "d"};
14669 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14670 :
14671 : properties =
14672 : object
14673 : ->GetPropertyNames(context.local(),
14674 : v8::KeyCollectionMode::kIncludePrototypes,
14675 6 : default_filter, v8::IndexFilter::kIncludeIndices)
14676 12 : .ToLocalChecked();
14677 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14678 :
14679 : properties = object
14680 : ->GetPropertyNames(context.local(),
14681 : v8::KeyCollectionMode::kIncludePrototypes,
14682 : include_symbols_filter,
14683 6 : v8::IndexFilter::kIncludeIndices)
14684 12 : .ToLocalChecked();
14685 : const char* expected_properties1_1[] = {
14686 : "0", "1", "4294967294", "a", "b", "4294967296",
14687 6 : "4294967295", nullptr, "2", "3", "c", "d"};
14688 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
14689 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14690 :
14691 : properties =
14692 : object
14693 : ->GetPropertyNames(context.local(),
14694 : v8::KeyCollectionMode::kIncludePrototypes,
14695 6 : default_filter, v8::IndexFilter::kSkipIndices)
14696 12 : .ToLocalChecked();
14697 : const char* expected_properties2[] = {"a", "b", "4294967296",
14698 6 : "4294967295", "c", "d"};
14699 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
14700 :
14701 : properties = object
14702 : ->GetPropertyNames(context.local(),
14703 : v8::KeyCollectionMode::kIncludePrototypes,
14704 : include_symbols_filter,
14705 6 : v8::IndexFilter::kSkipIndices)
14706 12 : .ToLocalChecked();
14707 : const char* expected_properties2_1[] = {
14708 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14709 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
14710 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14711 :
14712 : properties =
14713 : object
14714 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14715 6 : default_filter, v8::IndexFilter::kIncludeIndices)
14716 12 : .ToLocalChecked();
14717 : const char* expected_properties3[] = {"0", "1", "4294967294", "a",
14718 6 : "b", "4294967296", "4294967295"};
14719 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
14720 :
14721 : properties = object
14722 : ->GetPropertyNames(
14723 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14724 6 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14725 12 : .ToLocalChecked();
14726 : const char* expected_properties3_1[] = {
14727 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14728 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
14729 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14730 :
14731 : properties =
14732 : object
14733 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14734 6 : default_filter, v8::IndexFilter::kSkipIndices)
14735 12 : .ToLocalChecked();
14736 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14737 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
14738 :
14739 : properties = object
14740 : ->GetPropertyNames(
14741 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14742 6 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
14743 12 : .ToLocalChecked();
14744 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14745 6 : nullptr};
14746 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
14747 12 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14748 6 : }
14749 :
14750 25881 : THREADED_TEST(AccessChecksReenabledCorrectly) {
14751 6 : LocalContext context;
14752 6 : v8::Isolate* isolate = context->GetIsolate();
14753 12 : v8::HandleScope scope(isolate);
14754 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14755 6 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
14756 18 : templ->Set(v8_str("a"), v8_str("a"));
14757 : // Add more than 8 (see kMaxFastProperties) properties
14758 : // so that the constructor will force copying map.
14759 : // Cannot sprintf, gcc complains unsafety.
14760 : char buf[4];
14761 66 : for (char i = '0'; i <= '9' ; i++) {
14762 60 : buf[0] = i;
14763 660 : for (char j = '0'; j <= '9'; j++) {
14764 600 : buf[1] = j;
14765 6600 : for (char k = '0'; k <= '9'; k++) {
14766 6000 : buf[2] = k;
14767 6000 : buf[3] = 0;
14768 18000 : templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14769 : }
14770 : }
14771 : }
14772 :
14773 : Local<v8::Object> instance_1 =
14774 6 : templ->NewInstance(context.local()).ToLocalChecked();
14775 30 : CHECK(context->Global()
14776 : ->Set(context.local(), v8_str("obj_1"), instance_1)
14777 : .FromJust());
14778 :
14779 : Local<Value> value_1 = CompileRun("obj_1.a");
14780 6 : CHECK(value_1.IsEmpty());
14781 :
14782 : Local<v8::Object> instance_2 =
14783 6 : templ->NewInstance(context.local()).ToLocalChecked();
14784 30 : CHECK(context->Global()
14785 : ->Set(context.local(), v8_str("obj_2"), instance_2)
14786 : .FromJust());
14787 :
14788 : Local<Value> value_2 = CompileRun("obj_2.a");
14789 12 : CHECK(value_2.IsEmpty());
14790 6 : }
14791 :
14792 :
14793 : // This tests that we do not allow dictionary load/call inline caches
14794 : // to use functions that have not yet been compiled. The potential
14795 : // problem of loading a function that has not yet been compiled can
14796 : // arise because we share code between contexts via the compilation
14797 : // cache.
14798 25881 : THREADED_TEST(DictionaryICLoadedFunction) {
14799 6 : v8::HandleScope scope(CcTest::isolate());
14800 : // Test LoadIC.
14801 18 : for (int i = 0; i < 2; i++) {
14802 12 : LocalContext context;
14803 72 : CHECK(context->Global()
14804 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14805 : .FromJust());
14806 60 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14807 : CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14808 12 : }
14809 : // Test CallIC.
14810 12 : for (int i = 0; i < 2; i++) {
14811 12 : LocalContext context;
14812 72 : CHECK(context->Global()
14813 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14814 : .FromJust());
14815 60 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14816 : CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14817 18 : }
14818 6 : }
14819 :
14820 :
14821 : // Test that cross-context new calls use the context of the callee to
14822 : // create the new JavaScript object.
14823 25881 : THREADED_TEST(CrossContextNew) {
14824 6 : v8::Isolate* isolate = CcTest::isolate();
14825 6 : v8::HandleScope scope(isolate);
14826 6 : v8::Local<Context> context0 = Context::New(isolate);
14827 6 : v8::Local<Context> context1 = Context::New(isolate);
14828 :
14829 : // Allow cross-domain access.
14830 6 : Local<String> token = v8_str("<security token>");
14831 6 : context0->SetSecurityToken(token);
14832 6 : context1->SetSecurityToken(token);
14833 :
14834 : // Set an 'x' property on the Object prototype and define a
14835 : // constructor function in context0.
14836 6 : context0->Enter();
14837 : CompileRun("Object.prototype.x = 42; function C() {};");
14838 6 : context0->Exit();
14839 :
14840 : // Call the constructor function from context0 and check that the
14841 : // result has the 'x' property.
14842 6 : context1->Enter();
14843 30 : CHECK(context1->Global()
14844 : ->Set(context1, v8_str("other"), context0->Global())
14845 : .FromJust());
14846 : Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14847 6 : CHECK(value->IsInt32());
14848 12 : CHECK_EQ(42, value->Int32Value(context1).FromJust());
14849 6 : context1->Exit();
14850 6 : }
14851 :
14852 :
14853 : // Verify that we can clone an object
14854 25880 : TEST(ObjectClone) {
14855 5 : LocalContext env;
14856 5 : v8::Isolate* isolate = env->GetIsolate();
14857 10 : v8::HandleScope scope(isolate);
14858 :
14859 : const char* sample =
14860 : "var rv = {};" \
14861 : "rv.alpha = 'hello';" \
14862 : "rv.beta = 123;" \
14863 : "rv;";
14864 :
14865 : // Create an object, verify basics.
14866 : Local<Value> val = CompileRun(sample);
14867 5 : CHECK(val->IsObject());
14868 : Local<v8::Object> obj = val.As<v8::Object>();
14869 20 : obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
14870 :
14871 25 : CHECK(v8_str("hello")
14872 : ->Equals(env.local(),
14873 : obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14874 : .FromJust());
14875 25 : CHECK(v8::Integer::New(isolate, 123)
14876 : ->Equals(env.local(),
14877 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14878 : .FromJust());
14879 25 : CHECK(v8_str("cloneme")
14880 : ->Equals(env.local(),
14881 : obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14882 : .FromJust());
14883 :
14884 : // Clone it.
14885 5 : Local<v8::Object> clone = obj->Clone();
14886 25 : CHECK(v8_str("hello")
14887 : ->Equals(env.local(),
14888 : clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14889 : .FromJust());
14890 25 : CHECK(v8::Integer::New(isolate, 123)
14891 : ->Equals(env.local(),
14892 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14893 : .FromJust());
14894 25 : CHECK(v8_str("cloneme")
14895 : ->Equals(env.local(),
14896 : clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14897 : .FromJust());
14898 :
14899 : // Set a property on the clone, verify each object.
14900 20 : CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
14901 : .FromJust());
14902 25 : CHECK(v8::Integer::New(isolate, 123)
14903 : ->Equals(env.local(),
14904 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14905 : .FromJust());
14906 25 : CHECK(v8::Integer::New(isolate, 456)
14907 : ->Equals(env.local(),
14908 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14909 5 : .FromJust());
14910 5 : }
14911 :
14912 :
14913 : class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
14914 : public:
14915 : explicit OneByteVectorResource(i::Vector<const char> vector)
14916 6 : : data_(vector) {}
14917 6 : ~OneByteVectorResource() override = default;
14918 48 : size_t length() const override { return data_.length(); }
14919 24 : const char* data() const override { return data_.start(); }
14920 0 : void Dispose() override {}
14921 :
14922 : private:
14923 : i::Vector<const char> data_;
14924 : };
14925 :
14926 :
14927 : class UC16VectorResource : public v8::String::ExternalStringResource {
14928 : public:
14929 : explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14930 10 : : data_(vector) {}
14931 6 : ~UC16VectorResource() override = default;
14932 24 : size_t length() const override { return data_.length(); }
14933 414 : const i::uc16* data() const override { return data_.start(); }
14934 0 : void Dispose() override {}
14935 :
14936 : private:
14937 : i::Vector<const i::uc16> data_;
14938 : };
14939 :
14940 12 : static void MorphAString(i::String string,
14941 : OneByteVectorResource* one_byte_resource,
14942 : UC16VectorResource* uc16_resource) {
14943 : i::Isolate* isolate = CcTest::i_isolate();
14944 12 : CHECK(i::StringShape(string).IsExternal());
14945 12 : i::ReadOnlyRoots roots(CcTest::heap());
14946 12 : if (string->IsOneByteRepresentation()) {
14947 : // Check old map is not internalized or long.
14948 12 : CHECK(string->map() == roots.external_one_byte_string_map());
14949 : // Morph external string to be TwoByte string.
14950 12 : string->set_map(roots.external_string_map());
14951 12 : i::ExternalTwoByteString morphed = i::ExternalTwoByteString::cast(string);
14952 12 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14953 12 : morphed->SetResource(isolate, uc16_resource);
14954 : } else {
14955 : // Check old map is not internalized or long.
14956 0 : CHECK(string->map() == roots.external_string_map());
14957 : // Morph external string to be one-byte string.
14958 0 : string->set_map(roots.external_one_byte_string_map());
14959 0 : i::ExternalOneByteString morphed = i::ExternalOneByteString::cast(string);
14960 0 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14961 0 : morphed->SetResource(isolate, one_byte_resource);
14962 : }
14963 12 : }
14964 :
14965 : // Test that we can still flatten a string if the components it is built up
14966 : // from have been turned into 16 bit strings in the mean time.
14967 25881 : THREADED_TEST(MorphCompositeStringTest) {
14968 : char utf_buffer[129];
14969 : const char* c_string = "Now is the time for all good men"
14970 : " to come to the aid of the party";
14971 6 : uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14972 : {
14973 6 : LocalContext env;
14974 : i::Factory* factory = CcTest::i_isolate()->factory();
14975 6 : v8::Isolate* isolate = env->GetIsolate();
14976 : i::Isolate* i_isolate = CcTest::i_isolate();
14977 12 : v8::HandleScope scope(isolate);
14978 : OneByteVectorResource one_byte_resource(
14979 : i::Vector<const char>(c_string, i::StrLength(c_string)));
14980 : UC16VectorResource uc16_resource(
14981 : i::Vector<const uint16_t>(two_byte_string, i::StrLength(c_string)));
14982 :
14983 : Local<String> lhs(v8::Utils::ToLocal(
14984 : factory->NewExternalStringFromOneByte(&one_byte_resource)
14985 12 : .ToHandleChecked()));
14986 : Local<String> rhs(v8::Utils::ToLocal(
14987 : factory->NewExternalStringFromOneByte(&one_byte_resource)
14988 12 : .ToHandleChecked()));
14989 :
14990 30 : CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
14991 30 : CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
14992 :
14993 : CompileRun(
14994 : "var cons = lhs + rhs;"
14995 : "var slice = lhs.substring(1, lhs.length - 1);"
14996 : "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14997 :
14998 6 : CHECK(lhs->IsOneByte());
14999 6 : CHECK(rhs->IsOneByte());
15000 :
15001 6 : i::String ilhs = *v8::Utils::OpenHandle(*lhs);
15002 6 : i::String irhs = *v8::Utils::OpenHandle(*rhs);
15003 6 : MorphAString(ilhs, &one_byte_resource, &uc16_resource);
15004 6 : MorphAString(irhs, &one_byte_resource, &uc16_resource);
15005 :
15006 : // This should UTF-8 without flattening, since everything is ASCII.
15007 : Local<String> cons =
15008 12 : v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15009 6 : CHECK_EQ(128, cons->Utf8Length(isolate));
15010 6 : int nchars = -1;
15011 6 : CHECK_EQ(129, cons->WriteUtf8(isolate, utf_buffer, -1, &nchars));
15012 6 : CHECK_EQ(128, nchars);
15013 6 : CHECK_EQ(0, strcmp(
15014 : utf_buffer,
15015 : "Now is the time for all good men to come to the aid of the party"
15016 : "Now is the time for all good men to come to the aid of the party"));
15017 :
15018 : // Now do some stuff to make sure the strings are flattened, etc.
15019 : CompileRun(
15020 : "/[^a-z]/.test(cons);"
15021 : "/[^a-z]/.test(slice);"
15022 : "/[^a-z]/.test(slice_on_cons);");
15023 : const char* expected_cons =
15024 : "Now is the time for all good men to come to the aid of the party"
15025 : "Now is the time for all good men to come to the aid of the party";
15026 : const char* expected_slice =
15027 : "ow is the time for all good men to come to the aid of the part";
15028 : const char* expected_slice_on_cons =
15029 : "ow is the time for all good men to come to the aid of the party"
15030 : "Now is the time for all good men to come to the aid of the part";
15031 42 : CHECK(v8_str(expected_cons)
15032 : ->Equals(env.local(), env->Global()
15033 : ->Get(env.local(), v8_str("cons"))
15034 : .ToLocalChecked())
15035 : .FromJust());
15036 42 : CHECK(v8_str(expected_slice)
15037 : ->Equals(env.local(), env->Global()
15038 : ->Get(env.local(), v8_str("slice"))
15039 : .ToLocalChecked())
15040 : .FromJust());
15041 42 : CHECK(v8_str(expected_slice_on_cons)
15042 : ->Equals(env.local(),
15043 : env->Global()
15044 : ->Get(env.local(), v8_str("slice_on_cons"))
15045 : .ToLocalChecked())
15046 : .FromJust());
15047 :
15048 : // This avoids the GC from trying to free a stack allocated resource.
15049 6 : if (ilhs->IsExternalOneByteString())
15050 0 : i::ExternalOneByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15051 : else
15052 6 : i::ExternalTwoByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15053 6 : if (irhs->IsExternalOneByteString())
15054 0 : i::ExternalOneByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15055 : else
15056 12 : i::ExternalTwoByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15057 : }
15058 : i::DeleteArray(two_byte_string);
15059 6 : }
15060 :
15061 :
15062 25880 : TEST(CompileExternalTwoByteSource) {
15063 5 : LocalContext context;
15064 10 : v8::HandleScope scope(context->GetIsolate());
15065 :
15066 : // This is a very short list of sources, which currently is to check for a
15067 : // regression caused by r2703.
15068 : const char* one_byte_sources[] = {
15069 : "0.5",
15070 : "-0.5", // This mainly testes PushBack in the Scanner.
15071 : "--0.5", // This mainly testes PushBack in the Scanner.
15072 5 : nullptr};
15073 :
15074 : // Compile the sources as external two byte strings.
15075 20 : for (int i = 0; one_byte_sources[i] != nullptr; i++) {
15076 15 : uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15077 15 : TestResource* uc16_resource = new TestResource(two_byte_string);
15078 : v8::Local<v8::String> source =
15079 15 : v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15080 30 : .ToLocalChecked();
15081 15 : v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15082 5 : }
15083 5 : }
15084 :
15085 25875 : struct RegExpInterruptionData {
15086 : v8::base::Atomic32 loop_count;
15087 : UC16VectorResource* string_resource;
15088 : v8::Persistent<v8::String> string;
15089 25875 : } regexp_interruption_data;
15090 :
15091 :
15092 4 : class RegExpInterruptionThread : public v8::base::Thread {
15093 : public:
15094 : explicit RegExpInterruptionThread(v8::Isolate* isolate)
15095 4 : : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15096 :
15097 4 : void Run() override {
15098 32 : for (v8::base::Relaxed_Store(®exp_interruption_data.loop_count, 0);
15099 : v8::base::Relaxed_Load(®exp_interruption_data.loop_count) < 7;
15100 : v8::base::Relaxed_AtomicIncrement(®exp_interruption_data.loop_count,
15101 : 1)) {
15102 : // Wait a bit before requesting GC.
15103 28 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15104 28 : reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15105 : }
15106 : // Wait a bit before terminating.
15107 4 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15108 4 : isolate_->TerminateExecution();
15109 4 : }
15110 :
15111 : private:
15112 : v8::Isolate* isolate_;
15113 : };
15114 :
15115 :
15116 2 : void RunBeforeGC(v8::Isolate* isolate, v8::GCType type,
15117 : v8::GCCallbackFlags flags) {
15118 2 : if (v8::base::Relaxed_Load(®exp_interruption_data.loop_count) != 2) {
15119 2 : return;
15120 : }
15121 0 : v8::HandleScope scope(isolate);
15122 : v8::Local<v8::String> string = v8::Local<v8::String>::New(
15123 0 : CcTest::isolate(), regexp_interruption_data.string);
15124 0 : string->MakeExternal(regexp_interruption_data.string_resource);
15125 : }
15126 :
15127 :
15128 : // Test that RegExp execution can be interrupted. Specifically, we test
15129 : // * interrupting with GC
15130 : // * turn the subject string from one-byte internal to two-byte external string
15131 : // * force termination
15132 25879 : TEST(RegExpInterruption) {
15133 4 : LocalContext env;
15134 8 : v8::HandleScope scope(env->GetIsolate());
15135 :
15136 4 : RegExpInterruptionThread timeout_thread(env->GetIsolate());
15137 :
15138 4 : env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC);
15139 : static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15140 4 : i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15141 4 : v8::Local<v8::String> string = v8_str(one_byte_content);
15142 :
15143 20 : env->Global()->Set(env.local(), v8_str("a"), string).FromJust();
15144 4 : regexp_interruption_data.string.Reset(env->GetIsolate(), string);
15145 : regexp_interruption_data.string_resource = new UC16VectorResource(
15146 12 : i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15147 :
15148 8 : v8::TryCatch try_catch(env->GetIsolate());
15149 4 : timeout_thread.Start();
15150 :
15151 : CompileRun("/((a*)*)*b/.exec(a)");
15152 4 : CHECK(try_catch.HasTerminated());
15153 :
15154 4 : timeout_thread.Join();
15155 :
15156 : regexp_interruption_data.string.Reset();
15157 4 : i::DeleteArray(uc16_content);
15158 4 : }
15159 :
15160 : // Test that we cannot set a property on the global object if there
15161 : // is a read-only property in the prototype chain.
15162 25880 : TEST(ReadOnlyPropertyInGlobalProto) {
15163 5 : v8::Isolate* isolate = CcTest::isolate();
15164 5 : v8::HandleScope scope(isolate);
15165 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15166 10 : LocalContext context(nullptr, templ);
15167 5 : v8::Local<v8::Object> global = context->Global();
15168 : v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15169 20 : global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15170 : global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15171 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15172 10 : .FromJust();
15173 : global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15174 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15175 10 : .FromJust();
15176 : // Check without 'eval' or 'with'.
15177 : v8::Local<v8::Value> res =
15178 5 : CompileRun("function f() { x = 42; return x; }; f()");
15179 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15180 : // Check with 'eval'.
15181 5 : res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15182 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15183 : // Check with 'with'.
15184 5 : res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15185 20 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15186 5 : }
15187 :
15188 :
15189 25880 : TEST(CreateDataProperty) {
15190 5 : LocalContext env;
15191 5 : v8::Isolate* isolate = env->GetIsolate();
15192 10 : v8::HandleScope handle_scope(isolate);
15193 :
15194 : CompileRun(
15195 : "var a = {};"
15196 : "var b = [];"
15197 : "Object.defineProperty(a, 'foo', {value: 23});"
15198 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15199 :
15200 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15201 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15202 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15203 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15204 : {
15205 : // Can't change a non-configurable properties.
15206 5 : v8::TryCatch try_catch(isolate);
15207 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15208 : v8::Integer::New(isolate, 42)).FromJust());
15209 5 : CHECK(!try_catch.HasCaught());
15210 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15211 : v8::Integer::New(isolate, 42)).FromJust());
15212 5 : CHECK(!try_catch.HasCaught());
15213 : v8::Local<v8::Value> val =
15214 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15215 5 : CHECK(val->IsNumber());
15216 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15217 : }
15218 :
15219 : {
15220 : // Set a regular property.
15221 5 : v8::TryCatch try_catch(isolate);
15222 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15223 : v8::Integer::New(isolate, 42)).FromJust());
15224 5 : CHECK(!try_catch.HasCaught());
15225 : v8::Local<v8::Value> val =
15226 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15227 5 : CHECK(val->IsNumber());
15228 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15229 : }
15230 :
15231 : {
15232 : // Set an indexed property.
15233 5 : v8::TryCatch try_catch(isolate);
15234 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15235 : v8::Integer::New(isolate, 42)).FromJust());
15236 5 : CHECK(!try_catch.HasCaught());
15237 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15238 5 : CHECK(val->IsNumber());
15239 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15240 : }
15241 :
15242 : {
15243 : // Special cases for arrays.
15244 5 : v8::TryCatch try_catch(isolate);
15245 20 : CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15246 : v8::Integer::New(isolate, 1)).FromJust());
15247 5 : CHECK(!try_catch.HasCaught());
15248 : }
15249 : {
15250 : // Special cases for arrays: index exceeds the array's length
15251 5 : v8::TryCatch try_catch(isolate);
15252 15 : CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15253 : .FromJust());
15254 5 : CHECK(!try_catch.HasCaught());
15255 5 : CHECK_EQ(2U, arr->Length());
15256 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15257 5 : CHECK(val->IsNumber());
15258 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15259 :
15260 : // Set an existing entry.
15261 15 : CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15262 : .FromJust());
15263 5 : CHECK(!try_catch.HasCaught());
15264 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15265 5 : CHECK(val->IsNumber());
15266 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15267 : }
15268 :
15269 : CompileRun("Object.freeze(a);");
15270 : {
15271 : // Can't change non-extensible objects.
15272 5 : v8::TryCatch try_catch(isolate);
15273 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15274 : v8::Integer::New(isolate, 42)).FromJust());
15275 5 : CHECK(!try_catch.HasCaught());
15276 : }
15277 :
15278 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15279 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15280 : v8::Local<v8::Object> access_checked =
15281 5 : templ->NewInstance(env.local()).ToLocalChecked();
15282 : {
15283 5 : v8::TryCatch try_catch(isolate);
15284 20 : CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15285 : v8::Integer::New(isolate, 42))
15286 : .IsNothing());
15287 5 : CHECK(try_catch.HasCaught());
15288 5 : }
15289 5 : }
15290 :
15291 :
15292 25880 : TEST(DefineOwnProperty) {
15293 5 : LocalContext env;
15294 5 : v8::Isolate* isolate = env->GetIsolate();
15295 10 : v8::HandleScope handle_scope(isolate);
15296 :
15297 : CompileRun(
15298 : "var a = {};"
15299 : "var b = [];"
15300 : "Object.defineProperty(a, 'foo', {value: 23});"
15301 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15302 :
15303 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15304 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15305 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15306 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15307 : {
15308 : // Can't change a non-configurable properties.
15309 5 : v8::TryCatch try_catch(isolate);
15310 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15311 : v8::Integer::New(isolate, 42)).FromJust());
15312 5 : CHECK(!try_catch.HasCaught());
15313 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15314 : v8::Integer::New(isolate, 42)).FromJust());
15315 5 : CHECK(!try_catch.HasCaught());
15316 : v8::Local<v8::Value> val =
15317 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15318 5 : CHECK(val->IsNumber());
15319 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15320 : }
15321 :
15322 : {
15323 : // Set a regular property.
15324 5 : v8::TryCatch try_catch(isolate);
15325 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15326 : v8::Integer::New(isolate, 42)).FromJust());
15327 5 : CHECK(!try_catch.HasCaught());
15328 : v8::Local<v8::Value> val =
15329 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15330 5 : CHECK(val->IsNumber());
15331 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15332 : }
15333 :
15334 : {
15335 : // Set an indexed property.
15336 5 : v8::TryCatch try_catch(isolate);
15337 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15338 : v8::Integer::New(isolate, 42)).FromJust());
15339 5 : CHECK(!try_catch.HasCaught());
15340 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15341 5 : CHECK(val->IsNumber());
15342 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15343 : }
15344 :
15345 : {
15346 : // Special cases for arrays.
15347 5 : v8::TryCatch try_catch(isolate);
15348 20 : CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15349 : v8::Integer::New(isolate, 1)).FromJust());
15350 5 : CHECK(!try_catch.HasCaught());
15351 : }
15352 : {
15353 : // Special cases for arrays: index exceeds the array's length
15354 5 : v8::TryCatch try_catch(isolate);
15355 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15356 : v8::Integer::New(isolate, 23)).FromJust());
15357 5 : CHECK(!try_catch.HasCaught());
15358 5 : CHECK_EQ(2U, arr->Length());
15359 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15360 5 : CHECK(val->IsNumber());
15361 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15362 :
15363 : // Set an existing entry.
15364 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15365 : v8::Integer::New(isolate, 42)).FromJust());
15366 5 : CHECK(!try_catch.HasCaught());
15367 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15368 5 : CHECK(val->IsNumber());
15369 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15370 : }
15371 :
15372 : {
15373 : // Set a non-writable property.
15374 5 : v8::TryCatch try_catch(isolate);
15375 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15376 : v8::Integer::New(isolate, 42),
15377 : v8::ReadOnly).FromJust());
15378 5 : CHECK(!try_catch.HasCaught());
15379 : v8::Local<v8::Value> val =
15380 15 : obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15381 5 : CHECK(val->IsNumber());
15382 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15383 15 : CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
15384 : env.local(), v8_str("lala")).FromJust());
15385 5 : CHECK(!try_catch.HasCaught());
15386 : }
15387 :
15388 : CompileRun("Object.freeze(a);");
15389 : {
15390 : // Can't change non-extensible objects.
15391 5 : v8::TryCatch try_catch(isolate);
15392 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
15393 : v8::Integer::New(isolate, 42)).FromJust());
15394 5 : CHECK(!try_catch.HasCaught());
15395 : }
15396 :
15397 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15398 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15399 : v8::Local<v8::Object> access_checked =
15400 5 : templ->NewInstance(env.local()).ToLocalChecked();
15401 : {
15402 5 : v8::TryCatch try_catch(isolate);
15403 20 : CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
15404 : v8::Integer::New(isolate, 42))
15405 : .IsNothing());
15406 5 : CHECK(try_catch.HasCaught());
15407 5 : }
15408 5 : }
15409 :
15410 25880 : TEST(DefineProperty) {
15411 5 : LocalContext env;
15412 5 : v8::Isolate* isolate = env->GetIsolate();
15413 10 : v8::HandleScope handle_scope(isolate);
15414 :
15415 : v8::Local<v8::Name> p;
15416 :
15417 : CompileRun(
15418 : "var a = {};"
15419 : "var b = [];"
15420 : "Object.defineProperty(a, 'v1', {value: 23});"
15421 : "Object.defineProperty(a, 'v2', {value: 23, configurable: true});");
15422 :
15423 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15424 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15425 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15426 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15427 :
15428 10 : v8::PropertyDescriptor desc(v8_num(42));
15429 : {
15430 : // Use a data descriptor.
15431 :
15432 : // Cannot change a non-configurable property.
15433 5 : p = v8_str("v1");
15434 5 : v8::TryCatch try_catch(isolate);
15435 10 : CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
15436 5 : CHECK(!try_catch.HasCaught());
15437 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15438 5 : CHECK(val->IsNumber());
15439 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15440 :
15441 : // Change a configurable property.
15442 5 : p = v8_str("v2");
15443 10 : obj->DefineProperty(env.local(), p, desc).FromJust();
15444 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15445 5 : CHECK(!try_catch.HasCaught());
15446 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15447 5 : CHECK(val->IsNumber());
15448 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15449 :
15450 : // Check that missing writable has default value false.
15451 5 : p = v8_str("v12");
15452 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15453 5 : CHECK(!try_catch.HasCaught());
15454 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15455 5 : CHECK(val->IsNumber());
15456 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15457 10 : v8::PropertyDescriptor desc2(v8_num(43));
15458 10 : CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust());
15459 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15460 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15461 10 : CHECK(!try_catch.HasCaught());
15462 : }
15463 :
15464 : {
15465 : // Set a regular property.
15466 5 : p = v8_str("v3");
15467 5 : v8::TryCatch try_catch(isolate);
15468 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15469 5 : CHECK(!try_catch.HasCaught());
15470 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15471 5 : CHECK(val->IsNumber());
15472 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15473 : }
15474 :
15475 : {
15476 : // Set an indexed property.
15477 5 : v8::TryCatch try_catch(isolate);
15478 15 : CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust());
15479 5 : CHECK(!try_catch.HasCaught());
15480 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15481 5 : CHECK(val->IsNumber());
15482 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15483 : }
15484 :
15485 : {
15486 : // No special case when changing array length.
15487 5 : v8::TryCatch try_catch(isolate);
15488 : // Use a writable descriptor, otherwise the next test, that changes
15489 : // the array length will fail.
15490 10 : v8::PropertyDescriptor desc(v8_num(42), true);
15491 15 : CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust());
15492 10 : CHECK(!try_catch.HasCaught());
15493 : }
15494 :
15495 : {
15496 : // Special cases for arrays: index exceeds the array's length.
15497 5 : v8::TryCatch try_catch(isolate);
15498 15 : CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust());
15499 5 : CHECK(!try_catch.HasCaught());
15500 5 : CHECK_EQ(101U, arr->Length());
15501 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
15502 5 : CHECK(val->IsNumber());
15503 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15504 :
15505 : // Set an existing entry.
15506 15 : CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust());
15507 5 : CHECK(!try_catch.HasCaught());
15508 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15509 5 : CHECK(val->IsNumber());
15510 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15511 : }
15512 :
15513 : {
15514 : // Use a generic descriptor.
15515 5 : v8::PropertyDescriptor desc_generic;
15516 :
15517 5 : p = v8_str("v4");
15518 10 : v8::TryCatch try_catch(isolate);
15519 10 : CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust());
15520 5 : CHECK(!try_catch.HasCaught());
15521 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15522 5 : CHECK(val->IsUndefined());
15523 :
15524 15 : obj->Set(env.local(), p, v8_num(1)).FromJust();
15525 5 : CHECK(!try_catch.HasCaught());
15526 :
15527 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15528 5 : CHECK(val->IsUndefined());
15529 10 : CHECK(!try_catch.HasCaught());
15530 : }
15531 :
15532 : {
15533 : // Use a data descriptor with undefined value.
15534 5 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate));
15535 :
15536 10 : v8::TryCatch try_catch(isolate);
15537 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15538 5 : CHECK(!try_catch.HasCaught());
15539 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15540 5 : CHECK(val->IsUndefined());
15541 10 : CHECK(!try_catch.HasCaught());
15542 : }
15543 :
15544 : {
15545 : // Use a descriptor with attribute == v8::ReadOnly.
15546 5 : v8::PropertyDescriptor desc_read_only(v8_num(42), false);
15547 5 : desc_read_only.set_enumerable(true);
15548 5 : desc_read_only.set_configurable(true);
15549 :
15550 5 : p = v8_str("v5");
15551 10 : v8::TryCatch try_catch(isolate);
15552 10 : CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust());
15553 5 : CHECK(!try_catch.HasCaught());
15554 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15555 5 : CHECK(val->IsNumber());
15556 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15557 10 : CHECK_EQ(v8::ReadOnly,
15558 : obj->GetPropertyAttributes(env.local(), p).FromJust());
15559 10 : CHECK(!try_catch.HasCaught());
15560 : }
15561 :
15562 : {
15563 : // Use an accessor descriptor with empty handles.
15564 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate),
15565 5 : v8::Undefined(isolate));
15566 :
15567 5 : p = v8_str("v6");
15568 10 : v8::TryCatch try_catch(isolate);
15569 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15570 5 : CHECK(!try_catch.HasCaught());
15571 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15572 5 : CHECK(val->IsUndefined());
15573 10 : CHECK(!try_catch.HasCaught());
15574 : }
15575 :
15576 : {
15577 : // Use an accessor descriptor.
15578 : CompileRun(
15579 : "var set = function(x) {this.val = 2*x;};"
15580 : "var get = function() {return this.val || 0;};");
15581 :
15582 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15583 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15584 : v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
15585 25 : env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
15586 5 : v8::PropertyDescriptor desc(get, set);
15587 :
15588 5 : p = v8_str("v7");
15589 10 : v8::TryCatch try_catch(isolate);
15590 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15591 5 : CHECK(!try_catch.HasCaught());
15592 :
15593 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15594 5 : CHECK(val->IsNumber());
15595 10 : CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
15596 5 : CHECK(!try_catch.HasCaught());
15597 :
15598 15 : obj->Set(env.local(), p, v8_num(7)).FromJust();
15599 5 : CHECK(!try_catch.HasCaught());
15600 :
15601 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15602 5 : CHECK(val->IsNumber());
15603 10 : CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
15604 10 : CHECK(!try_catch.HasCaught());
15605 : }
15606 :
15607 : {
15608 : // Redefine an existing property.
15609 :
15610 : // desc = {value: 42, enumerable: true}
15611 5 : v8::PropertyDescriptor desc(v8_num(42));
15612 5 : desc.set_enumerable(true);
15613 :
15614 5 : p = v8_str("v8");
15615 10 : v8::TryCatch try_catch(isolate);
15616 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15617 5 : CHECK(!try_catch.HasCaught());
15618 :
15619 : // desc = {enumerable: true}
15620 10 : v8::PropertyDescriptor desc_true((v8::Local<v8::Value>()));
15621 5 : desc_true.set_enumerable(true);
15622 :
15623 : // Successful redefinition because all present attributes have the same
15624 : // value as the current descriptor.
15625 10 : CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust());
15626 5 : CHECK(!try_catch.HasCaught());
15627 :
15628 : // desc = {}
15629 10 : v8::PropertyDescriptor desc_empty;
15630 : // Successful redefinition because no attributes are overwritten in the
15631 : // current descriptor.
15632 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15633 5 : CHECK(!try_catch.HasCaught());
15634 :
15635 : // desc = {enumerable: false}
15636 10 : v8::PropertyDescriptor desc_false((v8::Local<v8::Value>()));
15637 5 : desc_false.set_enumerable(false);
15638 : // Not successful because we cannot define a different value for enumerable.
15639 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
15640 10 : CHECK(!try_catch.HasCaught());
15641 : }
15642 :
15643 : {
15644 : // Redefine a property that has a getter.
15645 : CompileRun("var get = function() {};");
15646 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15647 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15648 :
15649 : // desc = {get: function() {}}
15650 5 : v8::PropertyDescriptor desc(get, v8::Local<v8::Function>());
15651 10 : v8::TryCatch try_catch(isolate);
15652 :
15653 5 : p = v8_str("v9");
15654 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15655 5 : CHECK(!try_catch.HasCaught());
15656 :
15657 : // desc_empty = {}
15658 : // Successful because we are not redefining the current getter.
15659 10 : v8::PropertyDescriptor desc_empty;
15660 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15661 5 : CHECK(!try_catch.HasCaught());
15662 :
15663 : // desc = {get: function() {}}
15664 : // Successful because we redefine the getter with its current value.
15665 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15666 5 : CHECK(!try_catch.HasCaught());
15667 :
15668 : // desc = {get: undefined}
15669 : v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate),
15670 10 : v8::Local<v8::Function>());
15671 : // Not successful because we cannot redefine with the current value of get
15672 : // with undefined.
15673 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust());
15674 10 : CHECK(!try_catch.HasCaught());
15675 : }
15676 :
15677 : CompileRun("Object.freeze(a);");
15678 : {
15679 : // We cannot change non-extensible objects.
15680 5 : v8::TryCatch try_catch(isolate);
15681 15 : CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust());
15682 5 : CHECK(!try_catch.HasCaught());
15683 : }
15684 :
15685 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15686 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15687 : v8::Local<v8::Object> access_checked =
15688 5 : templ->NewInstance(env.local()).ToLocalChecked();
15689 : {
15690 5 : v8::TryCatch try_catch(isolate);
15691 15 : CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc)
15692 : .IsNothing());
15693 5 : CHECK(try_catch.HasCaught());
15694 5 : }
15695 5 : }
15696 :
15697 25881 : THREADED_TEST(GetCurrentContextWhenNotInContext) {
15698 : i::Isolate* isolate = CcTest::i_isolate();
15699 6 : CHECK_NOT_NULL(isolate);
15700 6 : CHECK(isolate->context().is_null());
15701 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15702 6 : v8::HandleScope scope(v8_isolate);
15703 : // The following should not crash, but return an empty handle.
15704 6 : v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15705 6 : CHECK(current.IsEmpty());
15706 6 : }
15707 :
15708 :
15709 : // Check that a variable declaration with no explicit initialization
15710 : // value does shadow an existing property in the prototype chain.
15711 25881 : THREADED_TEST(InitGlobalVarInProtoChain) {
15712 6 : LocalContext context;
15713 12 : v8::HandleScope scope(context->GetIsolate());
15714 : // Introduce a variable in the prototype chain.
15715 : CompileRun("__proto__.x = 42");
15716 : v8::Local<v8::Value> result = CompileRun("var x = 43; x");
15717 6 : CHECK(!result->IsUndefined());
15718 18 : CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
15719 6 : }
15720 :
15721 :
15722 : // Regression test for issue 398.
15723 : // If a function is added to an object, creating a constant function
15724 : // field, and the result is cloned, replacing the constant function on the
15725 : // original should not affect the clone.
15726 : // See http://code.google.com/p/v8/issues/detail?id=398
15727 25881 : THREADED_TEST(ReplaceConstantFunction) {
15728 6 : LocalContext context;
15729 6 : v8::Isolate* isolate = context->GetIsolate();
15730 12 : v8::HandleScope scope(isolate);
15731 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
15732 : v8::Local<v8::FunctionTemplate> func_templ =
15733 6 : v8::FunctionTemplate::New(isolate);
15734 6 : v8::Local<v8::String> foo_string = v8_str("foo");
15735 : obj->Set(context.local(), foo_string,
15736 24 : func_templ->GetFunction(context.local()).ToLocalChecked())
15737 12 : .FromJust();
15738 6 : v8::Local<v8::Object> obj_clone = obj->Clone();
15739 24 : obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
15740 18 : CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
15741 6 : }
15742 :
15743 :
15744 504 : static void CheckElementValue(i::Isolate* isolate,
15745 : int expected,
15746 : i::Handle<i::Object> obj,
15747 : int offset) {
15748 : i::Object element =
15749 1008 : *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15750 504 : CHECK_EQ(expected, i::Smi::ToInt(element));
15751 504 : }
15752 :
15753 :
15754 : template <class ExternalArrayClass, class ElementType>
15755 162 : static void ObjectWithExternalArrayTestHelper(Local<Context> context,
15756 : v8::Local<Object> obj,
15757 : int element_count,
15758 : i::ExternalArrayType array_type,
15759 : int64_t low, int64_t high) {
15760 : i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
15761 162 : v8::Isolate* v8_isolate = context->GetIsolate();
15762 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
15763 486 : obj->Set(context, v8_str("field"), v8::Int32::New(v8_isolate, 1503))
15764 324 : .FromJust();
15765 648 : CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
15766 : v8::Local<v8::Value> result = CompileRun("ext_array.field");
15767 324 : CHECK_EQ(1503, result->Int32Value(context).FromJust());
15768 : result = CompileRun("ext_array[1]");
15769 324 : CHECK_EQ(1, result->Int32Value(context).FromJust());
15770 :
15771 : // Check assigned smis
15772 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15773 : " ext_array[i] = i;"
15774 : "}"
15775 : "var sum = 0;"
15776 : "for (var i = 0; i < 8; i++) {"
15777 : " sum += ext_array[i];"
15778 : "}"
15779 : "sum;");
15780 :
15781 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15782 : // Check pass through of assigned smis
15783 : result = CompileRun("var sum = 0;"
15784 : "for (var i = 0; i < 8; i++) {"
15785 : " sum += ext_array[i] = ext_array[i] = -i;"
15786 : "}"
15787 : "sum;");
15788 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
15789 :
15790 :
15791 : // Check assigned smis in reverse order
15792 : result = CompileRun("for (var i = 8; --i >= 0; ) {"
15793 : " ext_array[i] = i;"
15794 : "}"
15795 : "var sum = 0;"
15796 : "for (var i = 0; i < 8; i++) {"
15797 : " sum += ext_array[i];"
15798 : "}"
15799 : "sum;");
15800 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15801 :
15802 : // Check pass through of assigned HeapNumbers
15803 : result = CompileRun("var sum = 0;"
15804 : "for (var i = 0; i < 16; i+=2) {"
15805 : " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15806 : "}"
15807 : "sum;");
15808 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
15809 :
15810 : // Check assigned HeapNumbers
15811 : result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15812 : " ext_array[i] = (i * 0.5);"
15813 : "}"
15814 : "var sum = 0;"
15815 : "for (var i = 0; i < 16; i+=2) {"
15816 : " sum += ext_array[i];"
15817 : "}"
15818 : "sum;");
15819 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15820 :
15821 : // Check assigned HeapNumbers in reverse order
15822 : result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15823 : " ext_array[i] = (i * 0.5);"
15824 : "}"
15825 : "var sum = 0;"
15826 : "for (var i = 0; i < 16; i+=2) {"
15827 : " sum += ext_array[i];"
15828 : "}"
15829 : "sum;");
15830 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15831 :
15832 : i::ScopedVector<char> test_buf(1024);
15833 :
15834 : // Check legal boundary conditions.
15835 : // The repeated loads and stores ensure the ICs are exercised.
15836 : const char* boundary_program =
15837 : "var res = 0;"
15838 : "for (var i = 0; i < 16; i++) {"
15839 : " ext_array[i] = %lld;"
15840 : " if (i > 8) {"
15841 : " res = ext_array[i];"
15842 : " }"
15843 : "}"
15844 : "res;";
15845 162 : i::SNPrintF(test_buf,
15846 : boundary_program,
15847 : low);
15848 : result = CompileRun(test_buf.start());
15849 324 : CHECK_EQ(low, result->IntegerValue(context).FromJust());
15850 :
15851 162 : i::SNPrintF(test_buf,
15852 : boundary_program,
15853 : high);
15854 : result = CompileRun(test_buf.start());
15855 324 : CHECK_EQ(high, result->IntegerValue(context).FromJust());
15856 :
15857 : // Check misprediction of type in IC.
15858 : result = CompileRun("var tmp_array = ext_array;"
15859 : "var sum = 0;"
15860 : "for (var i = 0; i < 8; i++) {"
15861 : " tmp_array[i] = i;"
15862 : " sum += tmp_array[i];"
15863 : " if (i == 4) {"
15864 : " tmp_array = {};"
15865 : " }"
15866 : "}"
15867 : "sum;");
15868 : // Force GC to trigger verification.
15869 162 : CcTest::CollectAllGarbage();
15870 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15871 :
15872 : // Make sure out-of-range loads do not throw.
15873 162 : i::SNPrintF(test_buf,
15874 : "var caught_exception = false;"
15875 : "try {"
15876 : " ext_array[%d];"
15877 : "} catch (e) {"
15878 : " caught_exception = true;"
15879 : "}"
15880 : "caught_exception;",
15881 : element_count);
15882 : result = CompileRun(test_buf.start());
15883 162 : CHECK(!result->BooleanValue(v8_isolate));
15884 :
15885 : // Make sure out-of-range stores do not throw.
15886 162 : i::SNPrintF(test_buf,
15887 : "var caught_exception = false;"
15888 : "try {"
15889 : " ext_array[%d] = 1;"
15890 : "} catch (e) {"
15891 : " caught_exception = true;"
15892 : "}"
15893 : "caught_exception;",
15894 : element_count);
15895 : result = CompileRun(test_buf.start());
15896 162 : CHECK(!result->BooleanValue(v8_isolate));
15897 :
15898 : // Check other boundary conditions, values and operations.
15899 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15900 : " ext_array[7] = undefined;"
15901 : "}"
15902 : "ext_array[7];");
15903 324 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15904 162 : if (array_type == i::kExternalFloat64Array ||
15905 : array_type == i::kExternalFloat32Array) {
15906 72 : CHECK(std::isnan(
15907 : i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
15908 : } else {
15909 126 : CheckElementValue(isolate, 0, jsobj, 7);
15910 : }
15911 :
15912 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15913 : " ext_array[6] = '2.3';"
15914 : "}"
15915 : "ext_array[6];");
15916 324 : CHECK_EQ(2, result->Int32Value(context).FromJust());
15917 324 : CHECK_EQ(2,
15918 : static_cast<int>(
15919 : i::Object::GetElement(
15920 : isolate, jsobj, 6).ToHandleChecked()->Number()));
15921 :
15922 162 : if (array_type != i::kExternalFloat32Array &&
15923 : array_type != i::kExternalFloat64Array) {
15924 : // Though the specification doesn't state it, be explicit about
15925 : // converting NaNs and +/-Infinity to zero.
15926 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15927 : " ext_array[i] = 5;"
15928 : "}"
15929 : "for (var i = 0; i < 8; i++) {"
15930 : " ext_array[i] = NaN;"
15931 : "}"
15932 : "ext_array[5];");
15933 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15934 126 : CheckElementValue(isolate, 0, jsobj, 5);
15935 :
15936 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15937 : " ext_array[i] = 5;"
15938 : "}"
15939 : "for (var i = 0; i < 8; i++) {"
15940 : " ext_array[i] = Infinity;"
15941 : "}"
15942 : "ext_array[5];");
15943 : int expected_value =
15944 126 : (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
15945 252 : CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
15946 126 : CheckElementValue(isolate, expected_value, jsobj, 5);
15947 :
15948 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15949 : " ext_array[i] = 5;"
15950 : "}"
15951 : "for (var i = 0; i < 8; i++) {"
15952 : " ext_array[i] = -Infinity;"
15953 : "}"
15954 : "ext_array[5];");
15955 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15956 126 : CheckElementValue(isolate, 0, jsobj, 5);
15957 :
15958 : // Check truncation behavior of integral arrays.
15959 : const char* unsigned_data =
15960 : "var source_data = [0.6, 10.6];"
15961 : "var expected_results = [0, 10];";
15962 : const char* signed_data =
15963 : "var source_data = [0.6, 10.6, -0.6, -10.6];"
15964 : "var expected_results = [0, 10, 0, -10];";
15965 : const char* pixel_data =
15966 : "var source_data = [0.6, 10.6];"
15967 : "var expected_results = [1, 11];";
15968 : bool is_unsigned = (array_type == i::kExternalUint8Array ||
15969 : array_type == i::kExternalUint16Array ||
15970 126 : array_type == i::kExternalUint32Array);
15971 : bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
15972 :
15973 126 : i::SNPrintF(test_buf,
15974 : "%s"
15975 : "var all_passed = true;"
15976 : "for (var i = 0; i < source_data.length; i++) {"
15977 : " for (var j = 0; j < 8; j++) {"
15978 : " ext_array[j] = source_data[i];"
15979 : " }"
15980 : " all_passed = all_passed &&"
15981 : " (ext_array[5] == expected_results[i]);"
15982 : "}"
15983 : "all_passed;",
15984 : (is_unsigned ?
15985 : unsigned_data :
15986 126 : (is_pixel_data ? pixel_data : signed_data)));
15987 : result = CompileRun(test_buf.start());
15988 126 : CHECK(result->BooleanValue(v8_isolate));
15989 : }
15990 :
15991 : i::Handle<ExternalArrayClass> array(
15992 486 : ExternalArrayClass::cast(i::Handle<i::JSObject>::cast(jsobj)->elements()),
15993 324 : isolate);
15994 19602 : for (int i = 0; i < element_count; i++) {
15995 36720 : array->set(i, static_cast<ElementType>(i));
15996 : }
15997 :
15998 162 : bool old_natives_flag_sentry = i::FLAG_allow_natives_syntax;
15999 162 : i::FLAG_allow_natives_syntax = true;
16000 :
16001 : // Test complex assignments
16002 : result = CompileRun(
16003 : "function ee_op_test_complex_func(sum) {"
16004 : " for (var i = 0; i < 40; ++i) {"
16005 : " sum += (ext_array[i] += 1);"
16006 : " sum += (ext_array[i] -= 1);"
16007 : " } "
16008 : " return sum;"
16009 : "}"
16010 : "sum=0;"
16011 : "sum=ee_op_test_complex_func(sum);"
16012 : "sum=ee_op_test_complex_func(sum);"
16013 : "%OptimizeFunctionOnNextCall(ee_op_test_complex_func);"
16014 : "sum=ee_op_test_complex_func(sum);"
16015 : "sum;");
16016 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
16017 :
16018 : // Test count operations
16019 : result = CompileRun(
16020 : "function ee_op_test_count_func(sum) {"
16021 : " for (var i = 0; i < 40; ++i) {"
16022 : " sum += (++ext_array[i]);"
16023 : " sum += (--ext_array[i]);"
16024 : " } "
16025 : " return sum;"
16026 : "}"
16027 : "sum=0;"
16028 : "sum=ee_op_test_count_func(sum);"
16029 : "sum=ee_op_test_count_func(sum);"
16030 : "%OptimizeFunctionOnNextCall(ee_op_test_count_func);"
16031 : "sum=ee_op_test_count_func(sum);"
16032 : "sum;");
16033 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
16034 :
16035 162 : i::FLAG_allow_natives_syntax = old_natives_flag_sentry;
16036 :
16037 : result = CompileRun("ext_array[3] = 33;"
16038 : "delete ext_array[3];"
16039 : "ext_array[3];");
16040 324 : CHECK_EQ(33, result->Int32Value(context).FromJust());
16041 :
16042 : result = CompileRun(
16043 : "ext_array[0] = 10; ext_array[1] = 11;"
16044 : "ext_array[2] = 12; ext_array[3] = 13;"
16045 : "try { ext_array.__defineGetter__('2', function() { return 120; }); }"
16046 : "catch (e) { }"
16047 : "ext_array[2];");
16048 324 : CHECK_EQ(12, result->Int32Value(context).FromJust());
16049 :
16050 : result = CompileRun("var js_array = new Array(40);"
16051 : "js_array[0] = 77;"
16052 : "js_array;");
16053 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16054 : ->Get(context, v8_str("0"))
16055 : .ToLocalChecked()
16056 : ->Int32Value(context)
16057 : .FromJust());
16058 :
16059 : result = CompileRun("ext_array[1] = 23;"
16060 : "ext_array.__proto__ = [];"
16061 : "js_array.__proto__ = ext_array;"
16062 : "js_array.concat(ext_array);");
16063 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16064 : ->Get(context, v8_str("0"))
16065 : .ToLocalChecked()
16066 : ->Int32Value(context)
16067 : .FromJust());
16068 648 : CHECK_EQ(23, v8::Object::Cast(*result)
16069 : ->Get(context, v8_str("1"))
16070 : .ToLocalChecked()
16071 : ->Int32Value(context)
16072 : .FromJust());
16073 :
16074 : result = CompileRun("ext_array[1] = 23;");
16075 324 : CHECK_EQ(23, result->Int32Value(context).FromJust());
16076 162 : }
16077 :
16078 :
16079 : template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16080 : class ElementType>
16081 54 : static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16082 : ElementType low, ElementType high) {
16083 54 : i::FLAG_allow_natives_syntax = true;
16084 54 : LocalContext context;
16085 : i::Isolate* isolate = CcTest::i_isolate();
16086 : i::Factory* factory = isolate->factory();
16087 108 : v8::HandleScope scope(context->GetIsolate());
16088 : const int kElementCount = 260;
16089 : i::Handle<i::JSTypedArray> jsobj =
16090 54 : factory->NewJSTypedArray(elements_kind, kElementCount);
16091 : i::Handle<FixedTypedArrayClass> fixed_array(
16092 108 : FixedTypedArrayClass::cast(jsobj->elements()), isolate);
16093 54 : CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16094 : fixed_array->map()->instance_type());
16095 54 : CHECK_EQ(kElementCount, fixed_array->length());
16096 54 : CcTest::CollectAllGarbage();
16097 14094 : for (int i = 0; i < kElementCount; i++) {
16098 26520 : fixed_array->set(i, static_cast<ElementType>(i));
16099 : }
16100 : // Force GC to trigger verification.
16101 54 : CcTest::CollectAllGarbage();
16102 14094 : for (int i = 0; i < kElementCount; i++) {
16103 14040 : CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16104 : static_cast<int64_t>(fixed_array->get_scalar(i)));
16105 : }
16106 : v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16107 :
16108 54 : ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16109 : context.local(), obj, kElementCount, array_type,
16110 : static_cast<int64_t>(low),
16111 108 : static_cast<int64_t>(high));
16112 54 : }
16113 :
16114 :
16115 25881 : THREADED_TEST(FixedUint8Array) {
16116 : FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16117 6 : i::kExternalUint8Array, 0x0, 0xFF);
16118 6 : }
16119 :
16120 :
16121 25881 : THREADED_TEST(FixedUint8ClampedArray) {
16122 : FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16123 : i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16124 6 : i::kExternalUint8ClampedArray, 0x0, 0xFF);
16125 6 : }
16126 :
16127 :
16128 25881 : THREADED_TEST(FixedInt8Array) {
16129 : FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16130 6 : i::kExternalInt8Array, -0x80, 0x7F);
16131 6 : }
16132 :
16133 :
16134 25881 : THREADED_TEST(FixedUint16Array) {
16135 : FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16136 6 : i::kExternalUint16Array, 0x0, 0xFFFF);
16137 6 : }
16138 :
16139 :
16140 25881 : THREADED_TEST(FixedInt16Array) {
16141 : FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16142 6 : i::kExternalInt16Array, -0x8000, 0x7FFF);
16143 6 : }
16144 :
16145 :
16146 25881 : THREADED_TEST(FixedUint32Array) {
16147 : FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16148 6 : i::kExternalUint32Array, 0x0, UINT_MAX);
16149 6 : }
16150 :
16151 :
16152 25881 : THREADED_TEST(FixedInt32Array) {
16153 : FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16154 6 : i::kExternalInt32Array, INT_MIN, INT_MAX);
16155 6 : }
16156 :
16157 :
16158 25881 : THREADED_TEST(FixedFloat32Array) {
16159 : FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16160 6 : i::kExternalFloat32Array, -500, 500);
16161 6 : }
16162 :
16163 :
16164 25881 : THREADED_TEST(FixedFloat64Array) {
16165 : FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16166 6 : i::kExternalFloat64Array, -500, 500);
16167 6 : }
16168 :
16169 :
16170 : template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16171 : class ArrayBufferType>
16172 108 : void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16173 : int64_t high) {
16174 : const int kElementCount = 50;
16175 :
16176 : i::ScopedVector<ElementType> backing_store(kElementCount+2);
16177 :
16178 216 : LocalContext env;
16179 108 : v8::Isolate* isolate = env->GetIsolate();
16180 216 : v8::HandleScope handle_scope(isolate);
16181 :
16182 : Local<ArrayBufferType> ab =
16183 : ArrayBufferType::New(isolate, backing_store.start(),
16184 108 : (kElementCount + 2) * sizeof(ElementType));
16185 : Local<TypedArray> ta =
16186 108 : TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16187 108 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16188 108 : CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16189 108 : CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16190 108 : CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16191 432 : CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16192 :
16193 108 : ElementType* data = backing_store.start() + 2;
16194 5508 : for (int i = 0; i < kElementCount; i++) {
16195 5400 : data[i] = static_cast<ElementType>(i);
16196 : }
16197 :
16198 108 : ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16199 216 : env.local(), ta, kElementCount, array_type, low, high);
16200 108 : }
16201 :
16202 :
16203 25881 : THREADED_TEST(Uint8Array) {
16204 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16205 6 : v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16206 6 : }
16207 :
16208 :
16209 25881 : THREADED_TEST(Int8Array) {
16210 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16211 6 : v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16212 6 : }
16213 :
16214 :
16215 25881 : THREADED_TEST(Uint16Array) {
16216 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16217 6 : v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16218 6 : }
16219 :
16220 :
16221 25881 : THREADED_TEST(Int16Array) {
16222 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16223 : v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16224 6 : 0x7FFF);
16225 6 : }
16226 :
16227 :
16228 25881 : THREADED_TEST(Uint32Array) {
16229 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16230 6 : v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16231 6 : }
16232 :
16233 :
16234 25881 : THREADED_TEST(Int32Array) {
16235 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16236 : v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16237 6 : INT_MAX);
16238 6 : }
16239 :
16240 :
16241 25881 : THREADED_TEST(Float32Array) {
16242 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16243 6 : v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16244 6 : }
16245 :
16246 :
16247 25881 : THREADED_TEST(Float64Array) {
16248 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16249 6 : v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16250 6 : }
16251 :
16252 :
16253 25881 : THREADED_TEST(Uint8ClampedArray) {
16254 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16255 : i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16256 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16257 6 : }
16258 :
16259 :
16260 25881 : THREADED_TEST(DataView) {
16261 : const int kSize = 50;
16262 :
16263 : i::ScopedVector<uint8_t> backing_store(kSize+2);
16264 :
16265 12 : LocalContext env;
16266 6 : v8::Isolate* isolate = env->GetIsolate();
16267 12 : v8::HandleScope handle_scope(isolate);
16268 :
16269 : Local<v8::ArrayBuffer> ab =
16270 6 : v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16271 6 : Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16272 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16273 6 : CHECK_EQ(2u, dv->ByteOffset());
16274 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16275 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16276 6 : }
16277 :
16278 :
16279 25881 : THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16280 6 : LocalContext env;
16281 6 : v8::Isolate* isolate = env->GetIsolate();
16282 12 : v8::HandleScope handle_scope(isolate);
16283 :
16284 : // Make sure the pointer looks like a heap object
16285 : uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16286 :
16287 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16288 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16289 :
16290 : // Should not crash
16291 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16292 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16293 6 : CcTest::CollectAllGarbage();
16294 6 : CcTest::CollectAllGarbage();
16295 :
16296 : // Should not move the pointer
16297 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16298 6 : }
16299 :
16300 :
16301 25881 : THREADED_TEST(SkipArrayBufferDuringScavenge) {
16302 6 : LocalContext env;
16303 6 : v8::Isolate* isolate = env->GetIsolate();
16304 12 : v8::HandleScope handle_scope(isolate);
16305 :
16306 : // Make sure the pointer looks like a heap object
16307 6 : Local<v8::Object> tmp = v8::Object::New(isolate);
16308 : uint8_t* store_ptr =
16309 6 : reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16310 :
16311 : // Make `store_ptr` point to from space
16312 6 : CcTest::CollectGarbage(i::NEW_SPACE);
16313 :
16314 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16315 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16316 :
16317 : // Should not crash,
16318 : // i.e. backing store pointer should not be treated as a heap object pointer
16319 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16320 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16321 :
16322 : // Use `ab` to silence compiler warning
16323 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16324 6 : }
16325 :
16326 :
16327 25881 : THREADED_TEST(SharedUint8Array) {
16328 6 : i::FLAG_harmony_sharedarraybuffer = true;
16329 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16330 6 : v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16331 6 : }
16332 :
16333 :
16334 25881 : THREADED_TEST(SharedInt8Array) {
16335 6 : i::FLAG_harmony_sharedarraybuffer = true;
16336 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16337 : v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16338 6 : 0x7F);
16339 6 : }
16340 :
16341 :
16342 25881 : THREADED_TEST(SharedUint16Array) {
16343 6 : i::FLAG_harmony_sharedarraybuffer = true;
16344 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16345 : v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16346 6 : 0xFFFF);
16347 6 : }
16348 :
16349 :
16350 25881 : THREADED_TEST(SharedInt16Array) {
16351 6 : i::FLAG_harmony_sharedarraybuffer = true;
16352 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16353 : v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16354 6 : 0x7FFF);
16355 6 : }
16356 :
16357 :
16358 25881 : THREADED_TEST(SharedUint32Array) {
16359 6 : i::FLAG_harmony_sharedarraybuffer = true;
16360 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16361 : v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16362 6 : UINT_MAX);
16363 6 : }
16364 :
16365 :
16366 25881 : THREADED_TEST(SharedInt32Array) {
16367 6 : i::FLAG_harmony_sharedarraybuffer = true;
16368 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16369 : v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16370 6 : INT_MAX);
16371 6 : }
16372 :
16373 :
16374 25881 : THREADED_TEST(SharedFloat32Array) {
16375 6 : i::FLAG_harmony_sharedarraybuffer = true;
16376 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16377 : v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16378 6 : 500);
16379 6 : }
16380 :
16381 :
16382 25881 : THREADED_TEST(SharedFloat64Array) {
16383 6 : i::FLAG_harmony_sharedarraybuffer = true;
16384 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16385 : v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
16386 6 : 500);
16387 6 : }
16388 :
16389 :
16390 25881 : THREADED_TEST(SharedUint8ClampedArray) {
16391 6 : i::FLAG_harmony_sharedarraybuffer = true;
16392 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16393 : i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
16394 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16395 6 : }
16396 :
16397 :
16398 25881 : THREADED_TEST(SharedDataView) {
16399 6 : i::FLAG_harmony_sharedarraybuffer = true;
16400 : const int kSize = 50;
16401 :
16402 : i::ScopedVector<uint8_t> backing_store(kSize + 2);
16403 :
16404 12 : LocalContext env;
16405 6 : v8::Isolate* isolate = env->GetIsolate();
16406 12 : v8::HandleScope handle_scope(isolate);
16407 :
16408 : Local<v8::SharedArrayBuffer> ab =
16409 6 : v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16410 : Local<v8::DataView> dv =
16411 6 : v8::DataView::New(ab, 2, kSize);
16412 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16413 6 : CHECK_EQ(2u, dv->ByteOffset());
16414 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16415 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16416 6 : }
16417 :
16418 : #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16419 : THREADED_TEST(Is##View) { \
16420 : LocalContext env; \
16421 : v8::Isolate* isolate = env->GetIsolate(); \
16422 : v8::HandleScope handle_scope(isolate); \
16423 : \
16424 : Local<Value> result = CompileRun( \
16425 : "var ab = new ArrayBuffer(128);" \
16426 : "new " #View "(ab)"); \
16427 : CHECK(result->IsArrayBufferView()); \
16428 : CHECK(result->Is##View()); \
16429 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16430 : }
16431 :
16432 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16433 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16434 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16435 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16436 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16437 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16438 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16439 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16440 25905 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16441 25905 : IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16442 :
16443 : #undef IS_ARRAY_BUFFER_VIEW_TEST
16444 :
16445 :
16446 :
16447 25881 : THREADED_TEST(ScriptContextDependence) {
16448 6 : LocalContext c1;
16449 12 : v8::HandleScope scope(c1->GetIsolate());
16450 : const char *source = "foo";
16451 : v8::Local<v8::Script> dep = v8_compile(source);
16452 : v8::ScriptCompiler::Source script_source(
16453 : v8::String::NewFromUtf8(c1->GetIsolate(), source,
16454 6 : v8::NewStringType::kNormal)
16455 6 : .ToLocalChecked());
16456 : v8::Local<v8::UnboundScript> indep =
16457 6 : v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
16458 6 : .ToLocalChecked();
16459 : c1->Global()
16460 : ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
16461 6 : v8::NewStringType::kNormal)
16462 : .ToLocalChecked(),
16463 30 : v8::Integer::New(c1->GetIsolate(), 100))
16464 12 : .FromJust();
16465 18 : CHECK_EQ(
16466 : dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
16467 : 100);
16468 24 : CHECK_EQ(indep->BindToCurrentContext()
16469 : ->Run(c1.local())
16470 : .ToLocalChecked()
16471 : ->Int32Value(c1.local())
16472 : .FromJust(),
16473 : 100);
16474 12 : LocalContext c2;
16475 : c2->Global()
16476 : ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
16477 6 : v8::NewStringType::kNormal)
16478 : .ToLocalChecked(),
16479 30 : v8::Integer::New(c2->GetIsolate(), 101))
16480 12 : .FromJust();
16481 18 : CHECK_EQ(
16482 : dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
16483 : 100);
16484 24 : CHECK_EQ(indep->BindToCurrentContext()
16485 : ->Run(c2.local())
16486 : .ToLocalChecked()
16487 : ->Int32Value(c2.local())
16488 : .FromJust(),
16489 6 : 101);
16490 6 : }
16491 :
16492 :
16493 25881 : THREADED_TEST(StackTrace) {
16494 6 : LocalContext context;
16495 12 : v8::HandleScope scope(context->GetIsolate());
16496 12 : v8::TryCatch try_catch(context->GetIsolate());
16497 : const char *source = "function foo() { FAIL.FAIL; }; foo();";
16498 6 : v8::Local<v8::String> src = v8_str(source);
16499 6 : v8::Local<v8::String> origin = v8_str("stack-trace-test");
16500 : v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
16501 30 : CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
16502 : &script_source)
16503 : .ToLocalChecked()
16504 : ->BindToCurrentContext()
16505 : ->Run(context.local())
16506 : .IsEmpty());
16507 6 : CHECK(try_catch.HasCaught());
16508 : v8::String::Utf8Value stack(
16509 : context->GetIsolate(),
16510 18 : try_catch.StackTrace(context.local()).ToLocalChecked());
16511 18 : CHECK_NOT_NULL(strstr(*stack, "at foo (stack-trace-test"));
16512 6 : }
16513 :
16514 :
16515 : // Checks that a StackFrame has certain expected values.
16516 100 : void checkStackFrame(const char* expected_script_name,
16517 : const char* expected_func_name, int expected_line_number,
16518 : int expected_column, bool is_eval, bool is_constructor,
16519 : v8::Local<v8::StackFrame> frame) {
16520 100 : v8::HandleScope scope(CcTest::isolate());
16521 300 : v8::String::Utf8Value func_name(CcTest::isolate(), frame->GetFunctionName());
16522 300 : v8::String::Utf8Value script_name(CcTest::isolate(), frame->GetScriptName());
16523 100 : if (*script_name == nullptr) {
16524 : // The situation where there is no associated script, like for evals.
16525 35 : CHECK_NULL(expected_script_name);
16526 : } else {
16527 65 : CHECK_NOT_NULL(strstr(*script_name, expected_script_name));
16528 : }
16529 200 : CHECK_NOT_NULL(strstr(*func_name, expected_func_name));
16530 100 : CHECK_EQ(expected_line_number, frame->GetLineNumber());
16531 100 : CHECK_EQ(expected_column, frame->GetColumn());
16532 100 : CHECK_EQ(is_eval, frame->IsEval());
16533 200 : CHECK_EQ(is_constructor, frame->IsConstructor());
16534 100 : }
16535 :
16536 :
16537 180 : void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16538 35 : v8::HandleScope scope(args.GetIsolate());
16539 : const char* origin = "capture-stack-trace-test";
16540 : const int kOverviewTest = 1;
16541 : const int kDetailedTest = 2;
16542 : const int kFunctionName = 3;
16543 : const int kDisplayName = 4;
16544 : const int kFunctionNameAndDisplayName = 5;
16545 : const int kDisplayNameIsNotString = 6;
16546 : const int kFunctionNameIsNotString = 7;
16547 :
16548 35 : CHECK_EQ(args.Length(), 1);
16549 :
16550 35 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
16551 : v8::Isolate* isolate = args.GetIsolate();
16552 70 : int testGroup = args[0]->Int32Value(context).FromJust();
16553 35 : if (testGroup == kOverviewTest) {
16554 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16555 5 : args.GetIsolate(), 10, v8::StackTrace::kOverview);
16556 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
16557 : checkStackFrame(origin, "bar", 2, 10, false, false,
16558 5 : stackTrace->GetFrame(args.GetIsolate(), 0));
16559 : checkStackFrame(origin, "foo", 6, 3, false, true,
16560 5 : stackTrace->GetFrame(isolate, 1));
16561 : // This is the source string inside the eval which has the call to foo.
16562 : checkStackFrame(nullptr, "", 1, 1, true, false,
16563 5 : stackTrace->GetFrame(isolate, 2));
16564 : // The last frame is an anonymous function which has the initial eval call.
16565 : checkStackFrame(origin, "", 8, 7, false, false,
16566 5 : stackTrace->GetFrame(isolate, 3));
16567 30 : } else if (testGroup == kDetailedTest) {
16568 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16569 5 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
16570 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
16571 : checkStackFrame(origin, "bat", 4, 22, false, false,
16572 5 : stackTrace->GetFrame(isolate, 0));
16573 : checkStackFrame(origin, "baz", 8, 3, false, true,
16574 5 : stackTrace->GetFrame(isolate, 1));
16575 : bool is_eval = true;
16576 : // This is the source string inside the eval which has the call to baz.
16577 : checkStackFrame(nullptr, "", 1, 1, is_eval, false,
16578 5 : stackTrace->GetFrame(isolate, 2));
16579 : // The last frame is an anonymous function which has the initial eval call.
16580 : checkStackFrame(origin, "", 10, 1, false, false,
16581 5 : stackTrace->GetFrame(isolate, 3));
16582 25 : } else if (testGroup == kFunctionName) {
16583 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16584 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16585 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16586 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16587 5 : stackTrace->GetFrame(isolate, 0));
16588 20 : } else if (testGroup == kDisplayName) {
16589 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16590 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16591 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16592 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16593 5 : stackTrace->GetFrame(isolate, 0));
16594 15 : } else if (testGroup == kFunctionNameAndDisplayName) {
16595 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16596 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16597 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16598 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16599 5 : stackTrace->GetFrame(isolate, 0));
16600 10 : } else if (testGroup == kDisplayNameIsNotString) {
16601 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16602 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16603 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16604 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16605 5 : stackTrace->GetFrame(isolate, 0));
16606 5 : } else if (testGroup == kFunctionNameIsNotString) {
16607 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16608 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16609 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16610 : checkStackFrame(nullptr, "", 3, 1, true, false,
16611 5 : stackTrace->GetFrame(isolate, 0));
16612 35 : }
16613 35 : }
16614 :
16615 :
16616 : // Tests the C++ StackTrace API.
16617 : // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16618 : // THREADED_TEST(CaptureStackTrace) {
16619 25880 : TEST(CaptureStackTrace) {
16620 5 : v8::Isolate* isolate = CcTest::isolate();
16621 5 : v8::HandleScope scope(isolate);
16622 5 : v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
16623 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16624 : templ->Set(v8_str("AnalyzeStackInNativeCode"),
16625 15 : v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
16626 10 : LocalContext context(nullptr, templ);
16627 :
16628 : // Test getting OVERVIEW information. Should ignore information that is not
16629 : // script name, function name, line number, and column offset.
16630 : const char *overview_source =
16631 : "function bar() {\n"
16632 : " var y; AnalyzeStackInNativeCode(1);\n"
16633 : "}\n"
16634 : "function foo() {\n"
16635 : "\n"
16636 : " bar();\n"
16637 : "}\n"
16638 : "var x;eval('new foo();');";
16639 5 : v8::Local<v8::String> overview_src = v8_str(overview_source);
16640 : v8::ScriptCompiler::Source script_source(overview_src,
16641 : v8::ScriptOrigin(origin));
16642 : v8::Local<Value> overview_result(
16643 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
16644 5 : .ToLocalChecked()
16645 : ->BindToCurrentContext()
16646 15 : ->Run(context.local())
16647 5 : .ToLocalChecked());
16648 5 : CHECK(!overview_result.IsEmpty());
16649 5 : CHECK(overview_result->IsObject());
16650 :
16651 : // Test getting DETAILED information.
16652 : const char *detailed_source =
16653 : "function bat() {AnalyzeStackInNativeCode(2);\n"
16654 : "}\n"
16655 : "\n"
16656 : "function baz() {\n"
16657 : " bat();\n"
16658 : "}\n"
16659 : "eval('new baz();');";
16660 5 : v8::Local<v8::String> detailed_src = v8_str(detailed_source);
16661 : // Make the script using a non-zero line and column offset.
16662 5 : v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
16663 5 : v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
16664 : v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16665 : v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
16666 : v8::Local<v8::UnboundScript> detailed_script(
16667 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
16668 5 : .ToLocalChecked());
16669 : v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
16670 10 : ->Run(context.local())
16671 5 : .ToLocalChecked());
16672 5 : CHECK(!detailed_result.IsEmpty());
16673 5 : CHECK(detailed_result->IsObject());
16674 :
16675 : // Test using function.name and function.displayName in stack trace
16676 : const char* function_name_source =
16677 : "function bar(function_name, display_name, testGroup) {\n"
16678 : " var f = new Function(`AnalyzeStackInNativeCode(${testGroup});`);\n"
16679 : " if (function_name) {\n"
16680 : " Object.defineProperty(f, 'name', { value: function_name });\n"
16681 : " }\n"
16682 : " if (display_name) {\n"
16683 : " f.displayName = display_name;"
16684 : " }\n"
16685 : " f()\n"
16686 : "}\n"
16687 : "bar('function.name', undefined, 3);\n"
16688 : "bar(undefined, 'function.displayName', 4);\n"
16689 : "bar('function.name', 'function.displayName', 5);\n"
16690 : "bar('function.name', 239, 6);\n"
16691 : "bar(239, undefined, 7);\n";
16692 : v8::Local<v8::String> function_name_src =
16693 : v8::String::NewFromUtf8(isolate, function_name_source,
16694 : v8::NewStringType::kNormal)
16695 5 : .ToLocalChecked();
16696 : v8::ScriptCompiler::Source script_source3(function_name_src,
16697 : v8::ScriptOrigin(origin));
16698 : v8::Local<Value> function_name_result(
16699 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
16700 5 : .ToLocalChecked()
16701 : ->BindToCurrentContext()
16702 15 : ->Run(context.local())
16703 5 : .ToLocalChecked());
16704 10 : CHECK(!function_name_result.IsEmpty());
16705 5 : }
16706 :
16707 :
16708 5 : static void StackTraceForUncaughtExceptionListener(
16709 : v8::Local<v8::Message> message, v8::Local<Value>) {
16710 5 : report_count++;
16711 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16712 5 : CHECK_EQ(2, stack_trace->GetFrameCount());
16713 : checkStackFrame("origin", "foo", 2, 3, false, false,
16714 5 : stack_trace->GetFrame(message->GetIsolate(), 0));
16715 : checkStackFrame("origin", "bar", 5, 3, false, false,
16716 5 : stack_trace->GetFrame(message->GetIsolate(), 1));
16717 5 : }
16718 :
16719 :
16720 25880 : TEST(CaptureStackTraceForUncaughtException) {
16721 5 : report_count = 0;
16722 5 : LocalContext env;
16723 5 : v8::Isolate* isolate = env->GetIsolate();
16724 10 : v8::HandleScope scope(isolate);
16725 5 : isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
16726 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16727 :
16728 : CompileRunWithOrigin(
16729 : "function foo() {\n"
16730 : " throw 1;\n"
16731 : "};\n"
16732 : "function bar() {\n"
16733 : " foo();\n"
16734 : "};",
16735 : "origin");
16736 5 : v8::Local<v8::Object> global = env->Global();
16737 : Local<Value> trouble =
16738 20 : global->Get(env.local(), v8_str("bar")).ToLocalChecked();
16739 5 : CHECK(trouble->IsFunction());
16740 10 : CHECK(Function::Cast(*trouble)
16741 : ->Call(env.local(), global, 0, nullptr)
16742 : .IsEmpty());
16743 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16744 5 : isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16745 10 : CHECK_EQ(1, report_count);
16746 5 : }
16747 :
16748 25880 : TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16749 5 : LocalContext env;
16750 5 : v8::Isolate* isolate = env->GetIsolate();
16751 10 : v8::HandleScope scope(isolate);
16752 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
16753 5 : v8::StackTrace::kDetailed);
16754 :
16755 : CompileRun(
16756 : "var setters = ['column', 'lineNumber', 'scriptName',\n"
16757 : " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16758 : " 'isConstructor'];\n"
16759 : "for (var i = 0; i < setters.length; i++) {\n"
16760 : " var prop = setters[i];\n"
16761 : " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16762 : "}\n");
16763 : CompileRun("throw 'exception';");
16764 10 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16765 5 : }
16766 :
16767 : static int asm_warning_triggered = 0;
16768 :
16769 5 : static void AsmJsWarningListener(v8::Local<v8::Message> message,
16770 : v8::Local<Value>) {
16771 : DCHECK_EQ(v8::Isolate::kMessageWarning, message->ErrorLevel());
16772 5 : asm_warning_triggered = 1;
16773 5 : }
16774 :
16775 25880 : TEST(AsmJsWarning) {
16776 5 : i::FLAG_validate_asm = true;
16777 5 : if (i::FLAG_suppress_asm_messages) return;
16778 :
16779 5 : LocalContext env;
16780 5 : v8::Isolate* isolate = env->GetIsolate();
16781 10 : v8::HandleScope scope(isolate);
16782 :
16783 5 : asm_warning_triggered = 0;
16784 : isolate->AddMessageListenerWithErrorLevel(AsmJsWarningListener,
16785 5 : v8::Isolate::kMessageAll);
16786 : CompileRun(
16787 : "function module() {\n"
16788 : " 'use asm';\n"
16789 : " var x = 'hi';\n"
16790 : " return {};\n"
16791 : "}\n"
16792 : "module();");
16793 : DCHECK_EQ(1, asm_warning_triggered);
16794 10 : isolate->RemoveMessageListeners(AsmJsWarningListener);
16795 : }
16796 :
16797 : static int error_level_message_count = 0;
16798 : static int expected_error_level = 0;
16799 :
16800 20 : static void ErrorLevelListener(v8::Local<v8::Message> message,
16801 : v8::Local<Value>) {
16802 : DCHECK_EQ(expected_error_level, message->ErrorLevel());
16803 20 : ++error_level_message_count;
16804 20 : }
16805 :
16806 25880 : TEST(ErrorLevelWarning) {
16807 5 : LocalContext env;
16808 5 : v8::Isolate* isolate = env->GetIsolate();
16809 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
16810 10 : v8::HandleScope scope(isolate);
16811 :
16812 : const char* source = "fake = 1;";
16813 5 : v8::Local<v8::Script> lscript = CompileWithOrigin(source, "test");
16814 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
16815 10 : v8::Utils::OpenHandle(*lscript->GetUnboundScript()));
16816 10 : CHECK(obj->script()->IsScript());
16817 10 : i::Handle<i::Script> script(i::Script::cast(obj->script()), i_isolate);
16818 :
16819 : int levels[] = {
16820 : v8::Isolate::kMessageLog, v8::Isolate::kMessageInfo,
16821 : v8::Isolate::kMessageDebug, v8::Isolate::kMessageWarning,
16822 5 : };
16823 5 : error_level_message_count = 0;
16824 : isolate->AddMessageListenerWithErrorLevel(ErrorLevelListener,
16825 5 : v8::Isolate::kMessageAll);
16826 25 : for (size_t i = 0; i < arraysize(levels); i++) {
16827 20 : i::MessageLocation location(script, 0, 0);
16828 : i::Handle<i::String> msg(i_isolate->factory()->InternalizeOneByteString(
16829 20 : i::StaticCharVector("test")));
16830 : i::Handle<i::JSMessageObject> message =
16831 : i::MessageHandler::MakeMessageObject(
16832 : i_isolate, i::MessageTemplate::kAsmJsInvalid, &location, msg,
16833 20 : i::Handle<i::FixedArray>::null());
16834 20 : message->set_error_level(levels[i]);
16835 20 : expected_error_level = levels[i];
16836 20 : i::MessageHandler::ReportMessage(i_isolate, &location, message);
16837 : }
16838 5 : isolate->RemoveMessageListeners(ErrorLevelListener);
16839 5 : DCHECK_EQ(arraysize(levels), error_level_message_count);
16840 5 : }
16841 :
16842 5 : static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
16843 : v8::Local<Value>) {
16844 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16845 5 : v8::Isolate* isolate = message->GetIsolate();
16846 5 : CHECK_EQ(5, stack_trace->GetFrameCount());
16847 : checkStackFrame("origin", "foo:0", 4, 7, false, false,
16848 5 : stack_trace->GetFrame(isolate, 0));
16849 : checkStackFrame("origin", "foo:1", 5, 27, false, false,
16850 5 : stack_trace->GetFrame(isolate, 1));
16851 : checkStackFrame("origin", "foo", 5, 27, false, false,
16852 5 : stack_trace->GetFrame(isolate, 2));
16853 : checkStackFrame("origin", "foo", 5, 27, false, false,
16854 5 : stack_trace->GetFrame(isolate, 3));
16855 : checkStackFrame("origin", "", 1, 14, false, false,
16856 5 : stack_trace->GetFrame(isolate, 4));
16857 5 : }
16858 :
16859 :
16860 25880 : TEST(GetStackTraceContainsFunctionsWithFunctionName) {
16861 5 : LocalContext env;
16862 5 : v8::Isolate* isolate = env->GetIsolate();
16863 10 : v8::HandleScope scope(isolate);
16864 :
16865 : CompileRunWithOrigin(
16866 : "function gen(name, counter) {\n"
16867 : " var f = function foo() {\n"
16868 : " if (counter === 0)\n"
16869 : " throw 1;\n"
16870 : " gen(name, counter - 1)();\n"
16871 : " };\n"
16872 : " if (counter == 3) {\n"
16873 : " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
16874 : " } else {\n"
16875 : " Object.defineProperty(f, 'name', {writable:true});\n"
16876 : " if (counter == 2)\n"
16877 : " f.name = 42;\n"
16878 : " else\n"
16879 : " f.name = name + ':' + counter;\n"
16880 : " }\n"
16881 : " return f;\n"
16882 : "};",
16883 : "origin");
16884 :
16885 5 : isolate->AddMessageListener(StackTraceFunctionNameListener);
16886 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16887 : CompileRunWithOrigin("gen('foo', 3)();", "origin");
16888 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16889 10 : isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
16890 5 : }
16891 :
16892 :
16893 5 : static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
16894 : v8::Local<v8::Value> data) {
16895 : // Use the frame where JavaScript is called from.
16896 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16897 5 : CHECK(!stack_trace.IsEmpty());
16898 5 : int frame_count = stack_trace->GetFrameCount();
16899 5 : CHECK_EQ(3, frame_count);
16900 5 : int line_number[] = {1, 2, 5};
16901 20 : for (int i = 0; i < frame_count; i++) {
16902 30 : CHECK_EQ(line_number[i],
16903 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16904 : }
16905 5 : }
16906 :
16907 :
16908 : // Test that we only return the stack trace at the site where the exception
16909 : // is first thrown (not where it is rethrown).
16910 25880 : TEST(RethrowStackTrace) {
16911 5 : LocalContext env;
16912 5 : v8::Isolate* isolate = env->GetIsolate();
16913 10 : v8::HandleScope scope(isolate);
16914 : // We make sure that
16915 : // - the stack trace of the ReferenceError in g() is reported.
16916 : // - the stack trace is not overwritten when e1 is rethrown by t().
16917 : // - the stack trace of e2 does not overwrite that of e1.
16918 : const char* source =
16919 : "function g() { error; } \n"
16920 : "function f() { g(); } \n"
16921 : "function t(e) { throw e; } \n"
16922 : "try { \n"
16923 : " f(); \n"
16924 : "} catch (e1) { \n"
16925 : " try { \n"
16926 : " error; \n"
16927 : " } catch (e2) { \n"
16928 : " t(e1); \n"
16929 : " } \n"
16930 : "} \n";
16931 5 : isolate->AddMessageListener(RethrowStackTraceHandler);
16932 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16933 : CompileRun(source);
16934 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16935 10 : isolate->RemoveMessageListeners(RethrowStackTraceHandler);
16936 5 : }
16937 :
16938 :
16939 5 : static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
16940 : v8::Local<v8::Value> data) {
16941 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16942 5 : CHECK(!stack_trace.IsEmpty());
16943 5 : int frame_count = stack_trace->GetFrameCount();
16944 5 : CHECK_EQ(2, frame_count);
16945 5 : int line_number[] = {3, 7};
16946 15 : for (int i = 0; i < frame_count; i++) {
16947 20 : CHECK_EQ(line_number[i],
16948 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16949 : }
16950 5 : }
16951 :
16952 :
16953 : // Test that we do not recognize identity for primitive exceptions.
16954 25880 : TEST(RethrowPrimitiveStackTrace) {
16955 5 : LocalContext env;
16956 5 : v8::Isolate* isolate = env->GetIsolate();
16957 10 : v8::HandleScope scope(isolate);
16958 : // We do not capture stack trace for non Error objects on creation time.
16959 : // Instead, we capture the stack trace on last throw.
16960 : const char* source =
16961 : "function g() { throw 404; } \n"
16962 : "function f() { g(); } \n"
16963 : "function t(e) { throw e; } \n"
16964 : "try { \n"
16965 : " f(); \n"
16966 : "} catch (e1) { \n"
16967 : " t(e1) \n"
16968 : "} \n";
16969 5 : isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
16970 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16971 : CompileRun(source);
16972 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16973 10 : isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16974 5 : }
16975 :
16976 :
16977 5 : static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
16978 : v8::Local<v8::Value> data) {
16979 : // Use the frame where JavaScript is called from.
16980 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16981 5 : CHECK(!stack_trace.IsEmpty());
16982 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
16983 10 : CHECK_EQ(1, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
16984 5 : }
16985 :
16986 :
16987 : // Test that the stack trace is captured when the error object is created and
16988 : // not where it is thrown.
16989 25880 : TEST(RethrowExistingStackTrace) {
16990 5 : LocalContext env;
16991 5 : v8::Isolate* isolate = env->GetIsolate();
16992 10 : v8::HandleScope scope(isolate);
16993 : const char* source =
16994 : "var e = new Error(); \n"
16995 : "throw e; \n";
16996 5 : isolate->AddMessageListener(RethrowExistingStackTraceHandler);
16997 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16998 : CompileRun(source);
16999 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17000 10 : isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
17001 5 : }
17002 :
17003 :
17004 5 : static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
17005 : v8::Local<v8::Value> data) {
17006 : // Use the frame where JavaScript is called from.
17007 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17008 5 : CHECK(!stack_trace.IsEmpty());
17009 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
17010 10 : CHECK_EQ(2, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
17011 5 : }
17012 :
17013 :
17014 : // Test that the stack trace is captured where the bogus Error object is thrown.
17015 25880 : TEST(RethrowBogusErrorStackTrace) {
17016 5 : LocalContext env;
17017 5 : v8::Isolate* isolate = env->GetIsolate();
17018 10 : v8::HandleScope scope(isolate);
17019 : const char* source =
17020 : "var e = {__proto__: new Error()} \n"
17021 : "throw e; \n";
17022 5 : isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
17023 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17024 : CompileRun(source);
17025 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17026 10 : isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17027 5 : }
17028 :
17029 :
17030 : v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17031 : int promise_reject_counter = 0;
17032 : int promise_revoke_counter = 0;
17033 : int promise_reject_after_resolved_counter = 0;
17034 : int promise_resolve_after_resolved_counter = 0;
17035 : int promise_reject_msg_line_number = -1;
17036 : int promise_reject_msg_column_number = -1;
17037 : int promise_reject_line_number = -1;
17038 : int promise_reject_column_number = -1;
17039 : int promise_reject_frame_count = -1;
17040 : bool promise_reject_is_shared_cross_origin = false;
17041 :
17042 140 : void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
17043 140 : v8::Local<v8::Object> global = CcTest::global();
17044 140 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17045 140 : CHECK_NE(v8::Promise::PromiseState::kPending,
17046 : reject_message.GetPromise()->State());
17047 140 : switch (reject_message.GetEvent()) {
17048 : case v8::kPromiseRejectWithNoHandler: {
17049 95 : promise_reject_counter++;
17050 190 : global->Set(context, v8_str("rejected"), reject_message.GetPromise())
17051 190 : .FromJust();
17052 190 : global->Set(context, v8_str("value"), reject_message.GetValue())
17053 190 : .FromJust();
17054 : v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17055 95 : CcTest::isolate(), reject_message.GetValue());
17056 95 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17057 :
17058 : promise_reject_msg_line_number =
17059 190 : message->GetLineNumber(context).FromJust();
17060 : promise_reject_msg_column_number =
17061 190 : message->GetStartColumn(context).FromJust() + 1;
17062 : promise_reject_is_shared_cross_origin =
17063 95 : message->IsSharedCrossOrigin();
17064 :
17065 95 : if (!stack_trace.IsEmpty()) {
17066 35 : promise_reject_frame_count = stack_trace->GetFrameCount();
17067 35 : if (promise_reject_frame_count > 0) {
17068 150 : CHECK(stack_trace->GetFrame(CcTest::isolate(), 0)
17069 : ->GetScriptName()
17070 : ->Equals(context, v8_str("pro"))
17071 : .FromJust());
17072 : promise_reject_line_number =
17073 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetLineNumber();
17074 : promise_reject_column_number =
17075 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetColumn();
17076 : } else {
17077 5 : promise_reject_line_number = -1;
17078 5 : promise_reject_column_number = -1;
17079 : }
17080 : }
17081 : break;
17082 : }
17083 : case v8::kPromiseHandlerAddedAfterReject: {
17084 30 : promise_revoke_counter++;
17085 60 : global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17086 60 : .FromJust();
17087 30 : CHECK(reject_message.GetValue().IsEmpty());
17088 : break;
17089 : }
17090 : case v8::kPromiseRejectAfterResolved: {
17091 10 : promise_reject_after_resolved_counter++;
17092 10 : break;
17093 : }
17094 : case v8::kPromiseResolveAfterResolved: {
17095 5 : promise_resolve_after_resolved_counter++;
17096 5 : break;
17097 : }
17098 : }
17099 140 : }
17100 :
17101 :
17102 600 : v8::Local<v8::Promise> GetPromise(const char* name) {
17103 : return v8::Local<v8::Promise>::Cast(
17104 : CcTest::global()
17105 1800 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17106 1200 : .ToLocalChecked());
17107 : }
17108 :
17109 :
17110 35 : v8::Local<v8::Value> RejectValue() {
17111 : return CcTest::global()
17112 105 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17113 70 : .ToLocalChecked();
17114 : }
17115 :
17116 :
17117 70 : void ResetPromiseStates() {
17118 70 : promise_reject_counter = 0;
17119 70 : promise_revoke_counter = 0;
17120 70 : promise_reject_after_resolved_counter = 0;
17121 70 : promise_resolve_after_resolved_counter = 0;
17122 70 : promise_reject_msg_line_number = -1;
17123 70 : promise_reject_msg_column_number = -1;
17124 70 : promise_reject_line_number = -1;
17125 70 : promise_reject_column_number = -1;
17126 70 : promise_reject_frame_count = -1;
17127 :
17128 70 : v8::Local<v8::Object> global = CcTest::global();
17129 70 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17130 280 : global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17131 280 : global->Set(context, v8_str("value"), v8_str("")).FromJust();
17132 280 : global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17133 70 : }
17134 :
17135 :
17136 25880 : TEST(PromiseRejectCallback) {
17137 5 : LocalContext env;
17138 5 : v8::Isolate* isolate = env->GetIsolate();
17139 10 : v8::HandleScope scope(isolate);
17140 :
17141 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17142 :
17143 5 : ResetPromiseStates();
17144 :
17145 : // Create promise p0.
17146 : CompileRun(
17147 : "var reject; \n"
17148 : "var p0 = new Promise( \n"
17149 : " function(res, rej) { \n"
17150 : " reject = rej; \n"
17151 : " } \n"
17152 : "); \n");
17153 10 : CHECK(!GetPromise("p0")->HasHandler());
17154 5 : CHECK_EQ(0, promise_reject_counter);
17155 5 : CHECK_EQ(0, promise_revoke_counter);
17156 :
17157 : // Add resolve handler (and default reject handler) to p0.
17158 : CompileRun("var p1 = p0.then(function(){});");
17159 10 : CHECK(GetPromise("p0")->HasHandler());
17160 10 : CHECK(!GetPromise("p1")->HasHandler());
17161 5 : CHECK_EQ(0, promise_reject_counter);
17162 5 : CHECK_EQ(0, promise_revoke_counter);
17163 :
17164 : // Reject p0.
17165 : CompileRun("reject('ppp');");
17166 10 : CHECK(GetPromise("p0")->HasHandler());
17167 10 : CHECK(!GetPromise("p1")->HasHandler());
17168 5 : CHECK_EQ(1, promise_reject_counter);
17169 5 : CHECK_EQ(0, promise_revoke_counter);
17170 5 : CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17171 20 : CHECK(
17172 : GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17173 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17174 :
17175 : // Reject p0 again. Callback is not triggered again.
17176 : CompileRun("reject();");
17177 10 : CHECK(GetPromise("p0")->HasHandler());
17178 10 : CHECK(!GetPromise("p1")->HasHandler());
17179 5 : CHECK_EQ(1, promise_reject_counter);
17180 5 : CHECK_EQ(0, promise_revoke_counter);
17181 :
17182 : // Add resolve handler to p1.
17183 : CompileRun("var p2 = p1.then(function(){});");
17184 10 : CHECK(GetPromise("p0")->HasHandler());
17185 10 : CHECK(GetPromise("p1")->HasHandler());
17186 10 : CHECK(!GetPromise("p2")->HasHandler());
17187 5 : CHECK_EQ(2, promise_reject_counter);
17188 5 : CHECK_EQ(1, promise_revoke_counter);
17189 20 : CHECK(
17190 : GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17191 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17192 20 : CHECK(
17193 : GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17194 :
17195 5 : ResetPromiseStates();
17196 :
17197 : // Create promise q0.
17198 : CompileRun(
17199 : "var q0 = new Promise( \n"
17200 : " function(res, rej) { \n"
17201 : " reject = rej; \n"
17202 : " } \n"
17203 : "); \n");
17204 10 : CHECK(!GetPromise("q0")->HasHandler());
17205 5 : CHECK_EQ(0, promise_reject_counter);
17206 5 : CHECK_EQ(0, promise_revoke_counter);
17207 :
17208 : // Add reject handler to q0.
17209 : CompileRun("var q1 = q0.catch(function() {});");
17210 10 : CHECK(GetPromise("q0")->HasHandler());
17211 10 : CHECK(!GetPromise("q1")->HasHandler());
17212 5 : CHECK_EQ(0, promise_reject_counter);
17213 5 : CHECK_EQ(0, promise_revoke_counter);
17214 :
17215 : // Reject q0.
17216 : CompileRun("reject('qq')");
17217 10 : CHECK(GetPromise("q0")->HasHandler());
17218 10 : CHECK(!GetPromise("q1")->HasHandler());
17219 5 : CHECK_EQ(0, promise_reject_counter);
17220 5 : CHECK_EQ(0, promise_revoke_counter);
17221 :
17222 : // Add a new reject handler, which rejects by returning Promise.reject().
17223 : // The returned promise q_ triggers a reject callback at first, only to
17224 : // revoke it when returning it causes q2 to be rejected.
17225 : CompileRun(
17226 : "var q_;"
17227 : "var q2 = q0.catch( \n"
17228 : " function() { \n"
17229 : " q_ = Promise.reject('qqq'); \n"
17230 : " return q_; \n"
17231 : " } \n"
17232 : "); \n");
17233 10 : CHECK(GetPromise("q0")->HasHandler());
17234 10 : CHECK(!GetPromise("q1")->HasHandler());
17235 10 : CHECK(!GetPromise("q2")->HasHandler());
17236 10 : CHECK(GetPromise("q_")->HasHandler());
17237 5 : CHECK_EQ(2, promise_reject_counter);
17238 5 : CHECK_EQ(1, promise_revoke_counter);
17239 20 : CHECK(
17240 : GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17241 20 : CHECK(
17242 : GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17243 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17244 :
17245 : // Add a reject handler to the resolved q1, which rejects by throwing.
17246 : CompileRun(
17247 : "var q3 = q1.then( \n"
17248 : " function() { \n"
17249 : " throw 'qqqq'; \n"
17250 : " } \n"
17251 : "); \n");
17252 10 : CHECK(GetPromise("q0")->HasHandler());
17253 10 : CHECK(GetPromise("q1")->HasHandler());
17254 10 : CHECK(!GetPromise("q2")->HasHandler());
17255 10 : CHECK(!GetPromise("q3")->HasHandler());
17256 5 : CHECK_EQ(3, promise_reject_counter);
17257 5 : CHECK_EQ(1, promise_revoke_counter);
17258 20 : CHECK(
17259 : GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17260 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17261 :
17262 5 : ResetPromiseStates();
17263 :
17264 : // Create promise r0, which has three handlers, two of which handle rejects.
17265 : CompileRun(
17266 : "var r0 = new Promise( \n"
17267 : " function(res, rej) { \n"
17268 : " reject = rej; \n"
17269 : " } \n"
17270 : "); \n"
17271 : "var r1 = r0.catch(function() {}); \n"
17272 : "var r2 = r0.then(function() {}); \n"
17273 : "var r3 = r0.then(function() {}, \n"
17274 : " function() {}); \n");
17275 10 : CHECK(GetPromise("r0")->HasHandler());
17276 10 : CHECK(!GetPromise("r1")->HasHandler());
17277 10 : CHECK(!GetPromise("r2")->HasHandler());
17278 10 : CHECK(!GetPromise("r3")->HasHandler());
17279 5 : CHECK_EQ(0, promise_reject_counter);
17280 5 : CHECK_EQ(0, promise_revoke_counter);
17281 :
17282 : // Reject r0.
17283 : CompileRun("reject('rrr')");
17284 10 : CHECK(GetPromise("r0")->HasHandler());
17285 10 : CHECK(!GetPromise("r1")->HasHandler());
17286 10 : CHECK(!GetPromise("r2")->HasHandler());
17287 10 : CHECK(!GetPromise("r3")->HasHandler());
17288 5 : CHECK_EQ(1, promise_reject_counter);
17289 5 : CHECK_EQ(0, promise_revoke_counter);
17290 20 : CHECK(
17291 : GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17292 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17293 :
17294 : // Add reject handler to r2.
17295 : CompileRun("var r4 = r2.catch(function() {});");
17296 10 : CHECK(GetPromise("r0")->HasHandler());
17297 10 : CHECK(!GetPromise("r1")->HasHandler());
17298 10 : CHECK(GetPromise("r2")->HasHandler());
17299 10 : CHECK(!GetPromise("r3")->HasHandler());
17300 10 : CHECK(!GetPromise("r4")->HasHandler());
17301 5 : CHECK_EQ(1, promise_reject_counter);
17302 5 : CHECK_EQ(1, promise_revoke_counter);
17303 20 : CHECK(
17304 : GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17305 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17306 :
17307 : // Add reject handlers to r4.
17308 : CompileRun("var r5 = r4.then(function() {}, function() {});");
17309 10 : CHECK(GetPromise("r0")->HasHandler());
17310 10 : CHECK(!GetPromise("r1")->HasHandler());
17311 10 : CHECK(GetPromise("r2")->HasHandler());
17312 10 : CHECK(!GetPromise("r3")->HasHandler());
17313 10 : CHECK(GetPromise("r4")->HasHandler());
17314 10 : CHECK(!GetPromise("r5")->HasHandler());
17315 5 : CHECK_EQ(1, promise_reject_counter);
17316 5 : CHECK_EQ(1, promise_revoke_counter);
17317 :
17318 5 : ResetPromiseStates();
17319 :
17320 : // Create promise s0, which has three handlers, none of which handle rejects.
17321 : CompileRun(
17322 : "var s0 = new Promise( \n"
17323 : " function(res, rej) { \n"
17324 : " reject = rej; \n"
17325 : " } \n"
17326 : "); \n"
17327 : "var s1 = s0.then(function() {}); \n"
17328 : "var s2 = s0.then(function() {}); \n"
17329 : "var s3 = s0.then(function() {}); \n");
17330 10 : CHECK(GetPromise("s0")->HasHandler());
17331 10 : CHECK(!GetPromise("s1")->HasHandler());
17332 10 : CHECK(!GetPromise("s2")->HasHandler());
17333 10 : CHECK(!GetPromise("s3")->HasHandler());
17334 5 : CHECK_EQ(0, promise_reject_counter);
17335 5 : CHECK_EQ(0, promise_revoke_counter);
17336 :
17337 : // Reject s0.
17338 : CompileRun("reject('sss')");
17339 10 : CHECK(GetPromise("s0")->HasHandler());
17340 10 : CHECK(!GetPromise("s1")->HasHandler());
17341 10 : CHECK(!GetPromise("s2")->HasHandler());
17342 10 : CHECK(!GetPromise("s3")->HasHandler());
17343 5 : CHECK_EQ(3, promise_reject_counter);
17344 5 : CHECK_EQ(0, promise_revoke_counter);
17345 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17346 :
17347 5 : ResetPromiseStates();
17348 :
17349 : // Swallowed exceptions in the Promise constructor.
17350 : CompileRun(
17351 : "var v0 = new Promise(\n"
17352 : " function(res, rej) {\n"
17353 : " res(1);\n"
17354 : " throw new Error();\n"
17355 : " }\n"
17356 : ");\n");
17357 10 : CHECK(!GetPromise("v0")->HasHandler());
17358 5 : CHECK_EQ(0, promise_reject_counter);
17359 5 : CHECK_EQ(0, promise_revoke_counter);
17360 5 : CHECK_EQ(1, promise_reject_after_resolved_counter);
17361 5 : CHECK_EQ(0, promise_resolve_after_resolved_counter);
17362 :
17363 5 : ResetPromiseStates();
17364 :
17365 : // Duplication resolve.
17366 : CompileRun(
17367 : "var r;\n"
17368 : "var y0 = new Promise(\n"
17369 : " function(res, rej) {\n"
17370 : " r = res;\n"
17371 : " throw new Error();\n"
17372 : " }\n"
17373 : ");\n"
17374 : "r(1);\n");
17375 10 : CHECK(!GetPromise("y0")->HasHandler());
17376 5 : CHECK_EQ(1, promise_reject_counter);
17377 5 : CHECK_EQ(0, promise_revoke_counter);
17378 5 : CHECK_EQ(0, promise_reject_after_resolved_counter);
17379 5 : CHECK_EQ(1, promise_resolve_after_resolved_counter);
17380 :
17381 : // Test stack frames.
17382 5 : env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
17383 :
17384 5 : ResetPromiseStates();
17385 :
17386 : // Create promise t0, which is rejected in the constructor with an error.
17387 : CompileRunWithOrigin(
17388 : "var t0 = new Promise( \n"
17389 : " function(res, rej) { \n"
17390 : " reference_error; \n"
17391 : " } \n"
17392 : "); \n",
17393 5 : "pro", 0, 0);
17394 10 : CHECK(!GetPromise("t0")->HasHandler());
17395 5 : CHECK_EQ(1, promise_reject_counter);
17396 5 : CHECK_EQ(0, promise_revoke_counter);
17397 5 : CHECK_EQ(2, promise_reject_frame_count);
17398 5 : CHECK_EQ(3, promise_reject_line_number);
17399 5 : CHECK_EQ(5, promise_reject_column_number);
17400 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17401 5 : CHECK_EQ(5, promise_reject_msg_column_number);
17402 :
17403 5 : ResetPromiseStates();
17404 :
17405 : // Create promise u0 and chain u1 to it, which is rejected via throw.
17406 : CompileRunWithOrigin(
17407 : "var u0 = Promise.resolve(); \n"
17408 : "var u1 = u0.then( \n"
17409 : " function() { \n"
17410 : " (function() { \n"
17411 : " throw new Error(); \n"
17412 : " })(); \n"
17413 : " } \n"
17414 : " ); \n",
17415 5 : "pro", 0, 0);
17416 10 : CHECK(GetPromise("u0")->HasHandler());
17417 10 : CHECK(!GetPromise("u1")->HasHandler());
17418 5 : CHECK_EQ(1, promise_reject_counter);
17419 5 : CHECK_EQ(0, promise_revoke_counter);
17420 5 : CHECK_EQ(2, promise_reject_frame_count);
17421 5 : CHECK_EQ(5, promise_reject_line_number);
17422 5 : CHECK_EQ(23, promise_reject_column_number);
17423 5 : CHECK_EQ(5, promise_reject_msg_line_number);
17424 5 : CHECK_EQ(23, promise_reject_msg_column_number);
17425 :
17426 : // Throw in u3, which handles u1's rejection.
17427 : CompileRunWithOrigin(
17428 : "function f() { \n"
17429 : " return (function() { \n"
17430 : " return new Error(); \n"
17431 : " })(); \n"
17432 : "} \n"
17433 : "var u2 = Promise.reject(f()); \n"
17434 : "var u3 = u1.catch( \n"
17435 : " function() { \n"
17436 : " return u2; \n"
17437 : " } \n"
17438 : " ); \n",
17439 5 : "pro", 0, 0);
17440 10 : CHECK(GetPromise("u0")->HasHandler());
17441 10 : CHECK(GetPromise("u1")->HasHandler());
17442 10 : CHECK(GetPromise("u2")->HasHandler());
17443 10 : CHECK(!GetPromise("u3")->HasHandler());
17444 5 : CHECK_EQ(3, promise_reject_counter);
17445 5 : CHECK_EQ(2, promise_revoke_counter);
17446 5 : CHECK_EQ(3, promise_reject_frame_count);
17447 5 : CHECK_EQ(3, promise_reject_line_number);
17448 5 : CHECK_EQ(12, promise_reject_column_number);
17449 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17450 5 : CHECK_EQ(12, promise_reject_msg_column_number);
17451 :
17452 5 : ResetPromiseStates();
17453 :
17454 : // Create promise rejected promise v0, which is incorrectly handled by v1
17455 : // via chaining cycle.
17456 : CompileRunWithOrigin(
17457 : "var v0 = Promise.reject(); \n"
17458 : "var v1 = v0.catch( \n"
17459 : " function() { \n"
17460 : " return v1; \n"
17461 : " } \n"
17462 : " ); \n",
17463 5 : "pro", 0, 0);
17464 10 : CHECK(GetPromise("v0")->HasHandler());
17465 10 : CHECK(!GetPromise("v1")->HasHandler());
17466 5 : CHECK_EQ(2, promise_reject_counter);
17467 5 : CHECK_EQ(1, promise_revoke_counter);
17468 5 : CHECK_EQ(0, promise_reject_frame_count);
17469 5 : CHECK_EQ(-1, promise_reject_line_number);
17470 5 : CHECK_EQ(-1, promise_reject_column_number);
17471 :
17472 5 : ResetPromiseStates();
17473 :
17474 : // Create promise t1, which rejects by throwing syntax error from eval.
17475 : CompileRunWithOrigin(
17476 : "var t1 = new Promise( \n"
17477 : " function(res, rej) { \n"
17478 : " var content = '\\n\\\n"
17479 : " }'; \n"
17480 : " eval(content); \n"
17481 : " } \n"
17482 : "); \n",
17483 5 : "pro", 0, 0);
17484 10 : CHECK(!GetPromise("t1")->HasHandler());
17485 5 : CHECK_EQ(1, promise_reject_counter);
17486 5 : CHECK_EQ(0, promise_revoke_counter);
17487 5 : CHECK_EQ(2, promise_reject_frame_count);
17488 5 : CHECK_EQ(5, promise_reject_line_number);
17489 5 : CHECK_EQ(10, promise_reject_column_number);
17490 5 : CHECK_EQ(2, promise_reject_msg_line_number);
17491 10 : CHECK_EQ(7, promise_reject_msg_column_number);
17492 5 : }
17493 :
17494 25880 : TEST(PromiseRejectIsSharedCrossOrigin) {
17495 5 : LocalContext env;
17496 5 : v8::Isolate* isolate = env->GetIsolate();
17497 10 : v8::HandleScope scope(isolate);
17498 :
17499 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17500 :
17501 5 : ResetPromiseStates();
17502 :
17503 : // Create promise p0.
17504 : CompileRun(
17505 : "var reject; \n"
17506 : "var p0 = new Promise( \n"
17507 : " function(res, rej) { \n"
17508 : " reject = rej; \n"
17509 : " } \n"
17510 : "); \n");
17511 10 : CHECK(!GetPromise("p0")->HasHandler());
17512 5 : CHECK_EQ(0, promise_reject_counter);
17513 5 : CHECK_EQ(0, promise_revoke_counter);
17514 : // Not set because it's not yet rejected.
17515 5 : CHECK(!promise_reject_is_shared_cross_origin);
17516 :
17517 : // Reject p0.
17518 : CompileRun("reject('ppp');");
17519 5 : CHECK_EQ(1, promise_reject_counter);
17520 5 : CHECK_EQ(0, promise_revoke_counter);
17521 : // Not set because the ScriptOriginOptions is from the script.
17522 5 : CHECK(!promise_reject_is_shared_cross_origin);
17523 :
17524 5 : ResetPromiseStates();
17525 :
17526 : // Create promise p1
17527 : CompileRun(
17528 : "var reject; \n"
17529 : "var p1 = new Promise( \n"
17530 : " function(res, rej) { \n"
17531 : " reject = rej; \n"
17532 : " } \n"
17533 : "); \n");
17534 10 : CHECK(!GetPromise("p1")->HasHandler());
17535 5 : CHECK_EQ(0, promise_reject_counter);
17536 5 : CHECK_EQ(0, promise_revoke_counter);
17537 : // Not set because it's not yet rejected.
17538 5 : CHECK(!promise_reject_is_shared_cross_origin);
17539 :
17540 : // Add resolve handler (and default reject handler) to p1.
17541 : CompileRun("var p2 = p1.then(function(){});");
17542 10 : CHECK(GetPromise("p1")->HasHandler());
17543 10 : CHECK(!GetPromise("p2")->HasHandler());
17544 5 : CHECK_EQ(0, promise_reject_counter);
17545 5 : CHECK_EQ(0, promise_revoke_counter);
17546 :
17547 : // Reject p1.
17548 : CompileRun("reject('ppp');");
17549 5 : CHECK_EQ(1, promise_reject_counter);
17550 5 : CHECK_EQ(0, promise_revoke_counter);
17551 : // Set because the event is from an empty script.
17552 10 : CHECK(promise_reject_is_shared_cross_origin);
17553 5 : }
17554 :
17555 25880 : TEST(PromiseRejectMarkAsHandled) {
17556 5 : LocalContext env;
17557 5 : v8::Isolate* isolate = env->GetIsolate();
17558 10 : v8::HandleScope scope(isolate);
17559 :
17560 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17561 :
17562 5 : ResetPromiseStates();
17563 :
17564 : // Create promise p0.
17565 : CompileRun(
17566 : "var reject; \n"
17567 : "var p0 = new Promise( \n"
17568 : " function(res, rej) { \n"
17569 : " reject = rej; \n"
17570 : " } \n"
17571 : "); \n");
17572 10 : CHECK(!GetPromise("p0")->HasHandler());
17573 5 : CHECK_EQ(0, promise_reject_counter);
17574 5 : CHECK_EQ(0, promise_revoke_counter);
17575 10 : GetPromise("p0")->MarkAsHandled();
17576 :
17577 : // Reject p0. promise_reject_counter shouldn't be incremented because
17578 : // it's marked as handled.
17579 : CompileRun("reject('ppp');");
17580 5 : CHECK_EQ(0, promise_reject_counter);
17581 10 : CHECK_EQ(0, promise_revoke_counter);
17582 5 : }
17583 30 : void PromiseRejectCallbackConstructError(
17584 : v8::PromiseRejectMessage reject_message) {
17585 30 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17586 30 : CHECK_EQ(v8::Promise::PromiseState::kRejected,
17587 : reject_message.GetPromise()->State());
17588 60 : USE(v8::Script::Compile(context, v8_str("new Error('test')"))
17589 : .ToLocalChecked()
17590 : ->Run(context));
17591 30 : }
17592 :
17593 25880 : TEST(PromiseRejectCallbackConstructError) {
17594 5 : i::FLAG_allow_natives_syntax = true;
17595 5 : LocalContext env;
17596 5 : v8::Isolate* isolate = env->GetIsolate();
17597 10 : v8::HandleScope scope(isolate);
17598 :
17599 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallbackConstructError);
17600 :
17601 5 : ResetPromiseStates();
17602 : CompileRun(
17603 : "function f(p) {"
17604 : " p.catch(() => {});"
17605 : "}"
17606 : "f(Promise.reject());"
17607 : "f(Promise.reject());"
17608 : "%OptimizeFunctionOnNextCall(f);"
17609 : "let p = Promise.reject();"
17610 5 : "f(p);");
17611 5 : }
17612 :
17613 10 : void AnalyzeStackOfEvalWithSourceURL(
17614 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17615 10 : v8::HandleScope scope(args.GetIsolate());
17616 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17617 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17618 10 : CHECK_EQ(5, stackTrace->GetFrameCount());
17619 10 : v8::Local<v8::String> url = v8_str("eval_url");
17620 40 : for (int i = 0; i < 3; i++) {
17621 : v8::Local<v8::String> name =
17622 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17623 30 : CHECK(!name.IsEmpty());
17624 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17625 10 : }
17626 10 : }
17627 :
17628 :
17629 25880 : TEST(SourceURLInStackTrace) {
17630 5 : v8::Isolate* isolate = CcTest::isolate();
17631 5 : v8::HandleScope scope(isolate);
17632 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17633 : templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17634 : v8::FunctionTemplate::New(isolate,
17635 15 : AnalyzeStackOfEvalWithSourceURL));
17636 10 : LocalContext context(nullptr, templ);
17637 :
17638 : const char *source =
17639 : "function outer() {\n"
17640 : "function bar() {\n"
17641 : " AnalyzeStackOfEvalWithSourceURL();\n"
17642 : "}\n"
17643 : "function foo() {\n"
17644 : "\n"
17645 : " bar();\n"
17646 : "}\n"
17647 : "foo();\n"
17648 : "}\n"
17649 : "eval('(' + outer +')()%s');";
17650 :
17651 : i::ScopedVector<char> code(1024);
17652 5 : i::SNPrintF(code, source, "//# sourceURL=eval_url");
17653 5 : CHECK(CompileRun(code.start())->IsUndefined());
17654 5 : i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17655 10 : CHECK(CompileRun(code.start())->IsUndefined());
17656 5 : }
17657 :
17658 :
17659 : static int scriptIdInStack[2];
17660 :
17661 5 : void AnalyzeScriptIdInStack(
17662 20 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17663 5 : v8::HandleScope scope(args.GetIsolate());
17664 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17665 5 : args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17666 5 : CHECK_EQ(2, stackTrace->GetFrameCount());
17667 10 : for (int i = 0; i < 2; i++) {
17668 : scriptIdInStack[i] =
17669 30 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptId();
17670 5 : }
17671 5 : }
17672 :
17673 :
17674 25880 : TEST(ScriptIdInStackTrace) {
17675 5 : v8::Isolate* isolate = CcTest::isolate();
17676 5 : v8::HandleScope scope(isolate);
17677 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17678 : templ->Set(v8_str("AnalyzeScriptIdInStack"),
17679 15 : v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17680 10 : LocalContext context(nullptr, templ);
17681 :
17682 : v8::Local<v8::String> scriptSource = v8_str(
17683 : "function foo() {\n"
17684 : " AnalyzeScriptIdInStack();"
17685 : "}\n"
17686 5 : "foo();\n");
17687 : v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17688 5 : script->Run(context.local()).ToLocalChecked();
17689 15 : for (int i = 0; i < 2; i++) {
17690 10 : CHECK_NE(scriptIdInStack[i], v8::Message::kNoScriptIdInfo);
17691 20 : CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17692 5 : }
17693 5 : }
17694 :
17695 :
17696 10 : void AnalyzeStackOfInlineScriptWithSourceURL(
17697 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17698 10 : v8::HandleScope scope(args.GetIsolate());
17699 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17700 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17701 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
17702 10 : v8::Local<v8::String> url = v8_str("source_url");
17703 40 : for (int i = 0; i < 3; i++) {
17704 : v8::Local<v8::String> name =
17705 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17706 30 : CHECK(!name.IsEmpty());
17707 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17708 10 : }
17709 10 : }
17710 :
17711 :
17712 25880 : TEST(InlineScriptWithSourceURLInStackTrace) {
17713 5 : v8::Isolate* isolate = CcTest::isolate();
17714 5 : v8::HandleScope scope(isolate);
17715 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17716 : templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17717 : v8::FunctionTemplate::New(
17718 15 : CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17719 10 : LocalContext context(nullptr, templ);
17720 :
17721 : const char *source =
17722 : "function outer() {\n"
17723 : "function bar() {\n"
17724 : " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17725 : "}\n"
17726 : "function foo() {\n"
17727 : "\n"
17728 : " bar();\n"
17729 : "}\n"
17730 : "foo();\n"
17731 : "}\n"
17732 : "outer()\n%s";
17733 :
17734 : i::ScopedVector<char> code(1024);
17735 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
17736 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17737 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
17738 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17739 5 : }
17740 :
17741 395 : void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
17742 : CcTest::global()
17743 1185 : ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
17744 790 : .FromJust();
17745 395 : }
17746 :
17747 5 : class PromiseHookData {
17748 : public:
17749 : int before_hook_count = 0;
17750 : int after_hook_count = 0;
17751 : int promise_hook_count = 0;
17752 : int parent_promise_count = 0;
17753 : bool check_value = true;
17754 : std::string promise_hook_value;
17755 :
17756 : void Reset() {
17757 50 : before_hook_count = 0;
17758 50 : after_hook_count = 0;
17759 50 : promise_hook_count = 0;
17760 50 : parent_promise_count = 0;
17761 50 : check_value = true;
17762 50 : promise_hook_value = "";
17763 : }
17764 : };
17765 :
17766 : PromiseHookData* promise_hook_data;
17767 :
17768 350 : void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
17769 : v8::Local<v8::Value> parentPromise) {
17770 350 : promise_hook_data->promise_hook_count++;
17771 350 : switch (type) {
17772 : case v8::PromiseHookType::kInit:
17773 125 : SetPromise("init", promise);
17774 :
17775 125 : if (!parentPromise->IsUndefined()) {
17776 45 : promise_hook_data->parent_promise_count++;
17777 45 : SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
17778 : }
17779 :
17780 : break;
17781 : case v8::PromiseHookType::kResolve:
17782 125 : SetPromise("resolve", promise);
17783 125 : break;
17784 : case v8::PromiseHookType::kBefore:
17785 50 : promise_hook_data->before_hook_count++;
17786 50 : CHECK(promise_hook_data->before_hook_count >
17787 : promise_hook_data->after_hook_count);
17788 300 : CHECK(CcTest::global()
17789 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17790 : .ToLocalChecked()
17791 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
17792 : .FromJust());
17793 50 : SetPromise("before", promise);
17794 50 : break;
17795 : case v8::PromiseHookType::kAfter:
17796 50 : promise_hook_data->after_hook_count++;
17797 50 : CHECK(promise_hook_data->after_hook_count <=
17798 : promise_hook_data->before_hook_count);
17799 50 : if (promise_hook_data->check_value) {
17800 180 : CHECK(
17801 : CcTest::global()
17802 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17803 : .ToLocalChecked()
17804 : ->Equals(CcTest::isolate()->GetCurrentContext(),
17805 : v8_str(promise_hook_data->promise_hook_value.c_str()))
17806 : .FromJust());
17807 : }
17808 50 : SetPromise("after", promise);
17809 50 : break;
17810 : }
17811 350 : }
17812 :
17813 25880 : TEST(PromiseHook) {
17814 5 : LocalContext env;
17815 5 : v8::Isolate* isolate = env->GetIsolate();
17816 10 : v8::HandleScope scope(isolate);
17817 :
17818 5 : v8::Local<v8::Object> global = CcTest::global();
17819 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17820 :
17821 10 : promise_hook_data = new PromiseHookData();
17822 5 : isolate->SetPromiseHook(CustomPromiseHook);
17823 :
17824 : // Test that an initialized promise is passed to init. Other hooks
17825 : // can not have un initialized promise.
17826 5 : promise_hook_data->check_value = false;
17827 : CompileRun("var p = new Promise(() => {});");
17828 :
17829 15 : auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17830 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17831 : auto init_promise_obj = v8::Local<v8::Promise>::Cast(init_promise);
17832 5 : CHECK_EQ(init_promise_obj->State(), v8::Promise::PromiseState::kPending);
17833 5 : CHECK(!init_promise_obj->HasHandler());
17834 :
17835 5 : promise_hook_data->Reset();
17836 5 : promise_hook_data->promise_hook_value = "fulfilled";
17837 : const char* source =
17838 : "var resolve, value = ''; \n"
17839 : "var p = new Promise(r => resolve = r); \n";
17840 :
17841 : CompileRun(source);
17842 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17843 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17844 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17845 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17846 :
17847 : CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
17848 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17849 15 : auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17850 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17851 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17852 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17853 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17854 :
17855 : CompileRun("resolve(); \n");
17856 : auto resolve_promise =
17857 15 : global->Get(context, v8_str("resolve")).ToLocalChecked();
17858 15 : auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17859 15 : auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17860 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17861 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17862 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17863 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17864 :
17865 : CompileRun("value = ''; var p2 = p1.then(() => { value = 'fulfilled' }); \n");
17866 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17867 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17868 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17869 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17870 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17871 15 : CHECK(GetPromise("p2")->Equals(env.local(), init_promise).FromJust());
17872 15 : CHECK(GetPromise("p1")->Equals(env.local(), parent_promise).FromJust());
17873 15 : CHECK(GetPromise("p2")->Equals(env.local(), before_promise).FromJust());
17874 15 : CHECK(GetPromise("p2")->Equals(env.local(), after_promise).FromJust());
17875 15 : CHECK(GetPromise("p2")->Equals(env.local(), resolve_promise).FromJust());
17876 5 : CHECK_EQ(10, promise_hook_data->promise_hook_count);
17877 :
17878 : promise_hook_data->Reset();
17879 5 : promise_hook_data->promise_hook_value = "rejected";
17880 : source =
17881 : "var reject, value = ''; \n"
17882 : "var p = new Promise((_, r) => reject = r); \n";
17883 :
17884 : CompileRun(source);
17885 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17886 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17887 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17888 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17889 :
17890 : CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
17891 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17892 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17893 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17894 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17895 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17896 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17897 :
17898 : CompileRun("reject(); \n");
17899 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17900 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17901 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17902 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17903 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17904 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17905 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17906 :
17907 : promise_hook_data->Reset();
17908 5 : promise_hook_data->promise_hook_value = "Promise.resolve";
17909 : source =
17910 : "var value = ''; \n"
17911 : "var p = Promise.resolve('Promise.resolve'); \n";
17912 :
17913 : CompileRun(source);
17914 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17915 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17916 : // init hook and resolve hook
17917 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17918 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17919 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17920 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17921 :
17922 : CompileRun("var p1 = p.then((v) => { value = v; }); \n");
17923 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17924 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17925 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17926 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17927 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17928 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17929 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17930 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17931 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17932 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17933 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17934 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17935 :
17936 : promise_hook_data->Reset();
17937 : source =
17938 : "var resolve, value = ''; \n"
17939 : "var p = new Promise((_, r) => resolve = r); \n";
17940 :
17941 : CompileRun(source);
17942 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17943 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17944 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17945 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17946 :
17947 : CompileRun("resolve(); \n");
17948 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17949 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17950 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17951 :
17952 : promise_hook_data->Reset();
17953 : source =
17954 : "var reject, value = ''; \n"
17955 : "var p = new Promise((_, r) => reject = r); \n";
17956 :
17957 : CompileRun(source);
17958 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17959 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17960 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17961 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17962 :
17963 : CompileRun("reject(); \n");
17964 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17965 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17966 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17967 :
17968 : promise_hook_data->Reset();
17969 : // This test triggers after callbacks right after each other, so
17970 : // lets just check the value at the end.
17971 5 : promise_hook_data->check_value = false;
17972 5 : promise_hook_data->promise_hook_value = "Promise.all";
17973 : source =
17974 : "var resolve, value = ''; \n"
17975 : "var tempPromise = new Promise(r => resolve = r); \n"
17976 : "var p = Promise.all([tempPromise]);\n "
17977 : "var p1 = p.then(v => value = v[0]); \n";
17978 :
17979 : CompileRun(source);
17980 : // 1) init hook (tempPromise)
17981 : // 2) init hook (p)
17982 : // 3) init hook (throwaway Promise in Promise.all, p)
17983 : // 4) init hook (p1, p)
17984 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
17985 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
17986 :
17987 5 : promise_hook_data->promise_hook_value = "Promise.all";
17988 : CompileRun("resolve('Promise.all'); \n");
17989 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17990 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17991 : // 5) resolve hook (tempPromise)
17992 : // 6) resolve hook (throwaway Promise in Promise.all)
17993 : // 6) before hook (throwaway Promise in Promise.all)
17994 : // 7) after hook (throwaway Promise in Promise.all)
17995 : // 8) before hook (p)
17996 : // 9) after hook (p)
17997 : // 10) resolve hook (p1)
17998 : // 11) before hook (p1)
17999 : // 12) after hook (p1)
18000 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18001 30 : CHECK(CcTest::global()
18002 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18003 : .ToLocalChecked()
18004 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18005 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18006 : .FromJust());
18007 :
18008 5 : promise_hook_data->Reset();
18009 : // This test triggers after callbacks right after each other, so
18010 : // lets just check the value at the end.
18011 5 : promise_hook_data->check_value = false;
18012 5 : promise_hook_data->promise_hook_value = "Promise.race";
18013 : source =
18014 : "var resolve, value = ''; \n"
18015 : "var tempPromise = new Promise(r => resolve = r); \n"
18016 : "var p = Promise.race([tempPromise]);\n "
18017 : "var p1 = p.then(v => value = v); \n";
18018 :
18019 : CompileRun(source);
18020 : // 1) init hook (tempPromise)
18021 : // 2) init hook (p)
18022 : // 3) init hook (throwaway Promise in Promise.race, p)
18023 : // 4) init hook (p1, p)
18024 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
18025 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
18026 :
18027 5 : promise_hook_data->promise_hook_value = "Promise.race";
18028 : CompileRun("resolve('Promise.race'); \n");
18029 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18030 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18031 : // 5) resolve hook (tempPromise)
18032 : // 6) resolve hook (throwaway Promise in Promise.race)
18033 : // 6) before hook (throwaway Promise in Promise.race)
18034 : // 7) after hook (throwaway Promise in Promise.race)
18035 : // 8) before hook (p)
18036 : // 9) after hook (p)
18037 : // 10) resolve hook (p1)
18038 : // 11) before hook (p1)
18039 : // 12) after hook (p1)
18040 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18041 30 : CHECK(CcTest::global()
18042 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18043 : .ToLocalChecked()
18044 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18045 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18046 : .FromJust());
18047 :
18048 5 : promise_hook_data->Reset();
18049 5 : promise_hook_data->promise_hook_value = "subclass";
18050 : source =
18051 : "var resolve, value = '';\n"
18052 : "class MyPromise extends Promise { \n"
18053 : " then(onFulfilled, onRejected) { \n"
18054 : " return super.then(onFulfilled, onRejected); \n"
18055 : " };\n"
18056 : "};\n"
18057 : "var p = new MyPromise(r => resolve = r);\n";
18058 :
18059 : CompileRun(source);
18060 : // 1) init hook (p)
18061 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18062 :
18063 : CompileRun("var p1 = p.then(() => value = 'subclass');\n");
18064 : // 2) init hook (p1)
18065 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18066 :
18067 : CompileRun("resolve();\n");
18068 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18069 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18070 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18071 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18072 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18073 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18074 : // 3) resolve hook (p)
18075 : // 4) before hook (p)
18076 : // 5) after hook (p)
18077 : // 6) resolve hook (p1)
18078 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18079 :
18080 : promise_hook_data->Reset();
18081 : source =
18082 : "class X extends Promise {\n"
18083 : " static get [Symbol.species]() {\n"
18084 : " return Y;\n"
18085 : " }\n"
18086 : "}\n"
18087 : "class Y {\n"
18088 : " constructor(executor) {\n"
18089 : " return new Proxy(new Promise(executor), {});\n"
18090 : " }\n"
18091 : "}\n"
18092 : "var x = X.resolve().then(() => {});\n";
18093 :
18094 : CompileRun(source);
18095 :
18096 5 : promise_hook_data->Reset();
18097 : source =
18098 : "var resolve, value = '';\n"
18099 : "var p = new Promise(r => resolve = r);\n";
18100 :
18101 : CompileRun(source);
18102 10 : CHECK_EQ(v8::Promise::kPending, GetPromise("p")->State());
18103 : CompileRun("resolve(Promise.resolve(value));\n");
18104 10 : CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State());
18105 5 : CHECK_EQ(9, promise_hook_data->promise_hook_count);
18106 :
18107 10 : delete promise_hook_data;
18108 10 : isolate->SetPromiseHook(nullptr);
18109 5 : }
18110 :
18111 10 : void AnalyzeStackOfDynamicScriptWithSourceURL(
18112 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18113 10 : v8::HandleScope scope(args.GetIsolate());
18114 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18115 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18116 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18117 10 : v8::Local<v8::String> url = v8_str("source_url");
18118 40 : for (int i = 0; i < 3; i++) {
18119 : v8::Local<v8::String> name =
18120 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18121 30 : CHECK(!name.IsEmpty());
18122 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18123 10 : }
18124 10 : }
18125 :
18126 :
18127 25880 : TEST(DynamicWithSourceURLInStackTrace) {
18128 5 : v8::Isolate* isolate = CcTest::isolate();
18129 5 : v8::HandleScope scope(isolate);
18130 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18131 : templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18132 : v8::FunctionTemplate::New(
18133 15 : CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18134 10 : LocalContext context(nullptr, templ);
18135 :
18136 : const char *source =
18137 : "function outer() {\n"
18138 : "function bar() {\n"
18139 : " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18140 : "}\n"
18141 : "function foo() {\n"
18142 : "\n"
18143 : " bar();\n"
18144 : "}\n"
18145 : "foo();\n"
18146 : "}\n"
18147 : "outer()\n%s";
18148 :
18149 : i::ScopedVector<char> code(1024);
18150 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18151 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18152 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18153 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18154 5 : }
18155 :
18156 :
18157 25880 : TEST(DynamicWithSourceURLInStackTraceString) {
18158 5 : LocalContext context;
18159 10 : v8::HandleScope scope(context->GetIsolate());
18160 :
18161 : const char *source =
18162 : "function outer() {\n"
18163 : " function foo() {\n"
18164 : " FAIL.FAIL;\n"
18165 : " }\n"
18166 : " foo();\n"
18167 : "}\n"
18168 : "outer()\n%s";
18169 :
18170 : i::ScopedVector<char> code(1024);
18171 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18172 10 : v8::TryCatch try_catch(context->GetIsolate());
18173 5 : CompileRunWithOrigin(code.start(), "", 0, 0);
18174 5 : CHECK(try_catch.HasCaught());
18175 : v8::String::Utf8Value stack(
18176 : context->GetIsolate(),
18177 15 : try_catch.StackTrace(context.local()).ToLocalChecked());
18178 15 : CHECK_NOT_NULL(strstr(*stack, "at foo (source_url:3:5)"));
18179 5 : }
18180 :
18181 :
18182 25880 : TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18183 5 : LocalContext context;
18184 10 : v8::HandleScope scope(context->GetIsolate());
18185 :
18186 : const char *source =
18187 : "function outer() {\n"
18188 : " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18189 : " //# sourceURL=source_url\";\n"
18190 : " eval(scriptContents);\n"
18191 : " foo(); }\n"
18192 : "outer();\n"
18193 : "//# sourceURL=outer_url";
18194 :
18195 10 : v8::TryCatch try_catch(context->GetIsolate());
18196 : CompileRun(source);
18197 5 : CHECK(try_catch.HasCaught());
18198 :
18199 5 : Local<v8::Message> message = try_catch.Message();
18200 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18201 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18202 5 : "source_url"));
18203 5 : }
18204 :
18205 :
18206 25880 : TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18207 5 : LocalContext context;
18208 10 : v8::HandleScope scope(context->GetIsolate());
18209 :
18210 : const char *source =
18211 : "function outer() {\n"
18212 : " var scriptContents = \"function boo(){ boo(); }\\\n"
18213 : " //# sourceURL=source_url\";\n"
18214 : " eval(scriptContents);\n"
18215 : " boo(); }\n"
18216 : "outer();\n"
18217 : "//# sourceURL=outer_url";
18218 :
18219 10 : v8::TryCatch try_catch(context->GetIsolate());
18220 : CompileRun(source);
18221 5 : CHECK(try_catch.HasCaught());
18222 :
18223 5 : Local<v8::Message> message = try_catch.Message();
18224 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18225 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18226 5 : "source_url"));
18227 5 : }
18228 :
18229 :
18230 5 : static void CreateGarbageInOldSpace() {
18231 : i::Factory* factory = CcTest::i_isolate()->factory();
18232 5 : v8::HandleScope scope(CcTest::isolate());
18233 : i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18234 5005 : for (int i = 0; i < 1000; i++) {
18235 5000 : factory->NewFixedArray(1000, i::TENURED);
18236 5 : }
18237 5 : }
18238 :
18239 :
18240 : // Test that idle notification can be handled and eventually collects garbage.
18241 25880 : TEST(TestIdleNotification) {
18242 5 : if (!i::FLAG_incremental_marking) return;
18243 : ManualGCScope manual_gc_scope;
18244 : const intptr_t MB = 1024 * 1024;
18245 : const double IdlePauseInSeconds = 1.0;
18246 10 : LocalContext env;
18247 10 : v8::HandleScope scope(env->GetIsolate());
18248 5 : intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18249 5 : CreateGarbageInOldSpace();
18250 5 : intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18251 5 : CHECK_GT(size_with_garbage, initial_size + MB);
18252 : bool finished = false;
18253 35 : for (int i = 0; i < 200 && !finished; i++) {
18254 70 : if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
18255 : CcTest::heap()->StartIdleIncrementalMarking(
18256 5 : i::GarbageCollectionReason::kTesting);
18257 : }
18258 : finished = env->GetIsolate()->IdleNotificationDeadline(
18259 105 : (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
18260 : static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
18261 70 : IdlePauseInSeconds);
18262 105 : if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
18263 10 : CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
18264 : }
18265 : }
18266 5 : intptr_t final_size = CcTest::heap()->SizeOfObjects();
18267 5 : CHECK(finished);
18268 5 : CHECK_LT(final_size, initial_size + 1);
18269 : }
18270 :
18271 25880 : TEST(TestMemorySavingsMode) {
18272 5 : LocalContext context;
18273 5 : v8::Isolate* isolate = context->GetIsolate();
18274 15 : v8::internal::Isolate* i_isolate =
18275 : reinterpret_cast<v8::internal::Isolate*>(isolate);
18276 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18277 5 : isolate->EnableMemorySavingsMode();
18278 5 : CHECK(i_isolate->IsMemorySavingsModeActive());
18279 5 : isolate->DisableMemorySavingsMode();
18280 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18281 5 : }
18282 :
18283 25880 : TEST(Regress2333) {
18284 5 : LocalContext env;
18285 20 : for (int i = 0; i < 3; i++) {
18286 15 : CcTest::CollectGarbage(i::NEW_SPACE);
18287 5 : }
18288 5 : }
18289 :
18290 : static uint32_t* stack_limit;
18291 :
18292 10 : static void GetStackLimitCallback(
18293 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18294 : stack_limit = reinterpret_cast<uint32_t*>(
18295 10 : CcTest::i_isolate()->stack_guard()->real_climit());
18296 10 : }
18297 :
18298 :
18299 : // Uses the address of a local variable to determine the stack top now.
18300 : // Given a size, returns an address that is that far from the current
18301 : // top of stack.
18302 : static uint32_t* ComputeStackLimit(uint32_t size) {
18303 : uint32_t* answer = &size - (size / sizeof(size));
18304 : // If the size is very large and the stack is very near the bottom of
18305 : // memory then the calculation above may wrap around and give an address
18306 : // that is above the (downwards-growing) stack. In that case we return
18307 : // a very low address.
18308 : if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18309 : return answer;
18310 : }
18311 :
18312 :
18313 : // We need at least 165kB for an x64 debug build with clang and ASAN.
18314 : static const int stack_breathing_room = 256 * i::KB;
18315 :
18316 :
18317 25880 : TEST(SetStackLimit) {
18318 : uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18319 :
18320 : // Set stack limit.
18321 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18322 :
18323 : // Execute a script.
18324 5 : LocalContext env;
18325 10 : v8::HandleScope scope(env->GetIsolate());
18326 : Local<v8::FunctionTemplate> fun_templ =
18327 5 : v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18328 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18329 25 : CHECK(env->Global()
18330 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18331 : .FromJust());
18332 : CompileRun("get_stack_limit();");
18333 :
18334 10 : CHECK(stack_limit == set_limit);
18335 5 : }
18336 :
18337 :
18338 25880 : TEST(SetStackLimitInThread) {
18339 : uint32_t* set_limit;
18340 : {
18341 5 : v8::Locker locker(CcTest::isolate());
18342 : set_limit = ComputeStackLimit(stack_breathing_room);
18343 :
18344 : // Set stack limit.
18345 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18346 :
18347 : // Execute a script.
18348 10 : v8::HandleScope scope(CcTest::isolate());
18349 10 : LocalContext env;
18350 : Local<v8::FunctionTemplate> fun_templ =
18351 5 : v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18352 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18353 25 : CHECK(env->Global()
18354 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18355 : .FromJust());
18356 : CompileRun("get_stack_limit();");
18357 :
18358 10 : CHECK(stack_limit == set_limit);
18359 : }
18360 : {
18361 5 : v8::Locker locker(CcTest::isolate());
18362 5 : CHECK(stack_limit == set_limit);
18363 : }
18364 5 : }
18365 :
18366 25881 : THREADED_TEST(GetHeapStatistics) {
18367 6 : LocalContext c1;
18368 12 : v8::HandleScope scope(c1->GetIsolate());
18369 6 : v8::HeapStatistics heap_statistics;
18370 6 : CHECK_EQ(0u, heap_statistics.total_heap_size());
18371 6 : CHECK_EQ(0u, heap_statistics.used_heap_size());
18372 6 : c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18373 6 : CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18374 12 : CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18375 6 : }
18376 :
18377 25880 : TEST(GetHeapSpaceStatistics) {
18378 5 : LocalContext c1;
18379 5 : v8::Isolate* isolate = c1->GetIsolate();
18380 10 : v8::HandleScope scope(isolate);
18381 5 : v8::HeapStatistics heap_statistics;
18382 :
18383 : // Force allocation in LO_SPACE so that every space has non-zero size.
18384 : v8::internal::Isolate* i_isolate =
18385 : reinterpret_cast<v8::internal::Isolate*>(isolate);
18386 5 : auto unused = i_isolate->factory()->TryNewFixedArray(512 * 1024, i::TENURED);
18387 : USE(unused);
18388 :
18389 5 : isolate->GetHeapStatistics(&heap_statistics);
18390 :
18391 : // Ensure that the sum of all the spaces matches the totals from
18392 : // GetHeapSpaceStatics.
18393 : size_t total_size = 0u;
18394 : size_t total_used_size = 0u;
18395 : size_t total_available_size = 0u;
18396 : size_t total_physical_size = 0u;
18397 45 : for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); ++i) {
18398 40 : v8::HeapSpaceStatistics space_statistics;
18399 40 : isolate->GetHeapSpaceStatistics(&space_statistics, i);
18400 40 : CHECK_NOT_NULL(space_statistics.space_name());
18401 40 : total_size += space_statistics.space_size();
18402 40 : total_used_size += space_statistics.space_used_size();
18403 40 : total_available_size += space_statistics.space_available_size();
18404 40 : total_physical_size += space_statistics.physical_space_size();
18405 : }
18406 10 : total_available_size += CcTest::heap()->memory_allocator()->Available();
18407 :
18408 5 : CHECK_EQ(total_size, heap_statistics.total_heap_size());
18409 5 : CHECK_EQ(total_used_size, heap_statistics.used_heap_size());
18410 5 : CHECK_EQ(total_available_size, heap_statistics.total_available_size());
18411 10 : CHECK_EQ(total_physical_size, heap_statistics.total_physical_size());
18412 5 : }
18413 :
18414 25880 : TEST(NumberOfNativeContexts) {
18415 : static const size_t kNumTestContexts = 10;
18416 : i::Isolate* isolate = CcTest::i_isolate();
18417 : i::HandleScope scope(isolate);
18418 110 : v8::Global<v8::Context> context[kNumTestContexts];
18419 5 : v8::HeapStatistics heap_statistics;
18420 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18421 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18422 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18423 55 : for (size_t i = 0; i < kNumTestContexts; i++) {
18424 : i::HandleScope inner(isolate);
18425 100 : context[i].Reset(CcTest::isolate(), v8::Context::New(CcTest::isolate()));
18426 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18427 50 : CHECK_EQ(i + 1, heap_statistics.number_of_native_contexts());
18428 : }
18429 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
18430 50 : context[i].Reset();
18431 50 : CcTest::PreciseCollectAllGarbage();
18432 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18433 50 : CHECK_EQ(kNumTestContexts - i - 1u,
18434 : heap_statistics.number_of_native_contexts());
18435 : }
18436 5 : }
18437 :
18438 25880 : TEST(NumberOfDetachedContexts) {
18439 : static const size_t kNumTestContexts = 10;
18440 : i::Isolate* isolate = CcTest::i_isolate();
18441 : i::HandleScope scope(isolate);
18442 110 : v8::Global<v8::Context> context[kNumTestContexts];
18443 5 : v8::HeapStatistics heap_statistics;
18444 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18445 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18446 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18447 55 : for (size_t i = 0; i < kNumTestContexts; i++) {
18448 : i::HandleScope inner(isolate);
18449 50 : v8::Local<v8::Context> local = v8::Context::New(CcTest::isolate());
18450 50 : context[i].Reset(CcTest::isolate(), local);
18451 50 : local->DetachGlobal();
18452 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18453 50 : CHECK_EQ(i + 1, heap_statistics.number_of_detached_contexts());
18454 : }
18455 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
18456 50 : context[i].Reset();
18457 50 : CcTest::PreciseCollectAllGarbage();
18458 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18459 50 : CHECK_EQ(kNumTestContexts - i - 1u,
18460 : heap_statistics.number_of_detached_contexts());
18461 : }
18462 5 : }
18463 :
18464 : class VisitorImpl : public v8::ExternalResourceVisitor {
18465 : public:
18466 5 : explicit VisitorImpl(TestResource** resource) {
18467 20 : for (int i = 0; i < 4; i++) {
18468 20 : resource_[i] = resource[i];
18469 20 : found_resource_[i] = false;
18470 : }
18471 : }
18472 5 : ~VisitorImpl() override = default;
18473 25 : void VisitExternalString(v8::Local<v8::String> string) override {
18474 25 : if (!string->IsExternal()) {
18475 5 : CHECK(string->IsExternalOneByte());
18476 25 : return;
18477 : }
18478 : v8::String::ExternalStringResource* resource =
18479 : string->GetExternalStringResource();
18480 20 : CHECK(resource);
18481 80 : for (int i = 0; i < 4; i++) {
18482 80 : if (resource_[i] == resource) {
18483 20 : CHECK(!found_resource_[i]);
18484 20 : found_resource_[i] = true;
18485 : }
18486 : }
18487 : }
18488 5 : void CheckVisitedResources() {
18489 25 : for (int i = 0; i < 4; i++) {
18490 20 : CHECK(found_resource_[i]);
18491 : }
18492 5 : }
18493 :
18494 : private:
18495 : v8::String::ExternalStringResource* resource_[4];
18496 : bool found_resource_[4];
18497 : };
18498 :
18499 :
18500 25880 : TEST(ExternalizeOldSpaceTwoByteCons) {
18501 5 : v8::Isolate* isolate = CcTest::isolate();
18502 5 : LocalContext env;
18503 10 : v8::HandleScope scope(isolate);
18504 : v8::Local<v8::String> cons =
18505 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18506 5 : ->ToString(env.local())
18507 5 : .ToLocalChecked();
18508 10 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18509 5 : CcTest::CollectAllAvailableGarbage();
18510 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18511 :
18512 : TestResource* resource = new TestResource(
18513 5 : AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18514 5 : cons->MakeExternal(resource);
18515 :
18516 5 : CHECK(cons->IsExternal());
18517 5 : CHECK_EQ(resource, cons->GetExternalStringResource());
18518 : String::Encoding encoding;
18519 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18520 10 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18521 5 : }
18522 :
18523 :
18524 25880 : TEST(ExternalizeOldSpaceOneByteCons) {
18525 5 : v8::Isolate* isolate = CcTest::isolate();
18526 5 : LocalContext env;
18527 10 : v8::HandleScope scope(isolate);
18528 : v8::Local<v8::String> cons =
18529 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18530 5 : ->ToString(env.local())
18531 5 : .ToLocalChecked();
18532 10 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18533 5 : CcTest::CollectAllAvailableGarbage();
18534 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18535 :
18536 : TestOneByteResource* resource =
18537 5 : new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18538 5 : cons->MakeExternal(resource);
18539 :
18540 5 : CHECK(cons->IsExternalOneByte());
18541 5 : CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18542 : String::Encoding encoding;
18543 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18544 10 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18545 5 : }
18546 :
18547 :
18548 25880 : TEST(VisitExternalStrings) {
18549 5 : v8::Isolate* isolate = CcTest::isolate();
18550 5 : LocalContext env;
18551 10 : v8::HandleScope scope(isolate);
18552 : const char* string = "Some string";
18553 5 : uint16_t* two_byte_string = AsciiToTwoByteString(string);
18554 : TestResource* resource[4];
18555 10 : resource[0] = new TestResource(two_byte_string);
18556 : v8::Local<v8::String> string0 =
18557 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
18558 5 : .ToLocalChecked();
18559 10 : resource[1] = new TestResource(two_byte_string, nullptr, false);
18560 : v8::Local<v8::String> string1 =
18561 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
18562 5 : .ToLocalChecked();
18563 :
18564 : // Externalized symbol.
18565 10 : resource[2] = new TestResource(two_byte_string, nullptr, false);
18566 : v8::Local<v8::String> string2 =
18567 : v8::String::NewFromUtf8(env->GetIsolate(), string,
18568 5 : v8::NewStringType::kInternalized)
18569 5 : .ToLocalChecked();
18570 5 : CHECK(string2->MakeExternal(resource[2]));
18571 :
18572 : // Symbolized External.
18573 10 : resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18574 : v8::Local<v8::String> string3 =
18575 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
18576 5 : .ToLocalChecked();
18577 5 : CcTest::CollectAllAvailableGarbage(); // Tenure string.
18578 : // Turn into a symbol.
18579 : i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18580 10 : CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18581 : string3_i).is_null());
18582 10 : CHECK(string3_i->IsInternalizedString());
18583 :
18584 : // We need to add usages for string* to avoid warnings in GCC 4.7
18585 5 : CHECK(string0->IsExternal());
18586 5 : CHECK(string1->IsExternal());
18587 5 : CHECK(string2->IsExternal());
18588 5 : CHECK(string3->IsExternal());
18589 :
18590 : VisitorImpl visitor(resource);
18591 5 : isolate->VisitExternalResources(&visitor);
18592 10 : visitor.CheckVisitedResources();
18593 5 : }
18594 :
18595 :
18596 25880 : TEST(ExternalStringCollectedAtTearDown) {
18597 5 : int destroyed = 0;
18598 : v8::Isolate::CreateParams create_params;
18599 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18600 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18601 : { v8::Isolate::Scope isolate_scope(isolate);
18602 10 : v8::HandleScope handle_scope(isolate);
18603 : const char* s = "One string to test them all, one string to find them.";
18604 : TestOneByteResource* inscription =
18605 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18606 : v8::Local<v8::String> ring =
18607 5 : v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
18608 : // Ring is still alive. Orcs are roaming freely across our lands.
18609 5 : CHECK_EQ(0, destroyed);
18610 : USE(ring);
18611 : }
18612 :
18613 5 : isolate->Dispose();
18614 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18615 5 : CHECK_EQ(1, destroyed);
18616 5 : }
18617 :
18618 :
18619 25880 : TEST(ExternalInternalizedStringCollectedAtTearDown) {
18620 5 : int destroyed = 0;
18621 : v8::Isolate::CreateParams create_params;
18622 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18623 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18624 : { v8::Isolate::Scope isolate_scope(isolate);
18625 5 : LocalContext env(isolate);
18626 10 : v8::HandleScope handle_scope(isolate);
18627 : CompileRun("var ring = 'One string to test them all';");
18628 : const char* s = "One string to test them all";
18629 : TestOneByteResource* inscription =
18630 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18631 : v8::Local<v8::String> ring =
18632 10 : CompileRun("ring")->ToString(env.local()).ToLocalChecked();
18633 10 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18634 5 : ring->MakeExternal(inscription);
18635 : // Ring is still alive. Orcs are roaming freely across our lands.
18636 5 : CHECK_EQ(0, destroyed);
18637 : USE(ring);
18638 : }
18639 :
18640 5 : isolate->Dispose();
18641 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18642 5 : CHECK_EQ(1, destroyed);
18643 5 : }
18644 :
18645 :
18646 25880 : TEST(ExternalInternalizedStringCollectedAtGC) {
18647 5 : int destroyed = 0;
18648 5 : { LocalContext env;
18649 10 : v8::HandleScope handle_scope(env->GetIsolate());
18650 : CompileRun("var ring = 'One string to test them all';");
18651 : const char* s = "One string to test them all";
18652 : TestOneByteResource* inscription =
18653 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18654 : v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
18655 10 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18656 5 : ring->MakeExternal(inscription);
18657 : // Ring is still alive. Orcs are roaming freely across our lands.
18658 5 : CHECK_EQ(0, destroyed);
18659 5 : USE(ring);
18660 : }
18661 :
18662 : // Garbage collector deals swift blows to evil.
18663 5 : CcTest::i_isolate()->compilation_cache()->Clear();
18664 5 : CcTest::CollectAllAvailableGarbage();
18665 :
18666 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18667 5 : CHECK_EQ(1, destroyed);
18668 5 : }
18669 :
18670 :
18671 : static double DoubleFromBits(uint64_t value) {
18672 : double target;
18673 : i::MemCopy(&target, &value, sizeof(target));
18674 : return target;
18675 : }
18676 :
18677 :
18678 : static uint64_t DoubleToBits(double value) {
18679 : uint64_t target;
18680 : i::MemCopy(&target, &value, sizeof(target));
18681 : return target;
18682 : }
18683 :
18684 :
18685 120 : static double DoubleToDateTime(double input) {
18686 : double date_limit = 864e13;
18687 120 : if (std::isnan(input) || input < -date_limit || input > date_limit) {
18688 : return std::numeric_limits<double>::quiet_NaN();
18689 : }
18690 60 : return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18691 : }
18692 :
18693 :
18694 : // We don't have a consistent way to write 64-bit constants syntactically, so we
18695 : // split them into two 32-bit constants and combine them programmatically.
18696 : static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18697 : return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18698 : }
18699 :
18700 :
18701 25881 : THREADED_TEST(QuietSignalingNaNs) {
18702 6 : LocalContext context;
18703 6 : v8::Isolate* isolate = context->GetIsolate();
18704 12 : v8::HandleScope scope(isolate);
18705 12 : v8::TryCatch try_catch(isolate);
18706 :
18707 : // Special double values.
18708 : double snan = DoubleFromBits(0x7FF00000, 0x00000001);
18709 : double qnan = DoubleFromBits(0x7FF80000, 0x00000000);
18710 : double infinity = DoubleFromBits(0x7FF00000, 0x00000000);
18711 : double max_normal = DoubleFromBits(0x7FEFFFFF, 0xFFFFFFFFu);
18712 : double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18713 : double max_denormal = DoubleFromBits(0x000FFFFF, 0xFFFFFFFFu);
18714 : double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18715 :
18716 : // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18717 : // on either side of the epoch.
18718 : double date_limit = 864e13;
18719 :
18720 : double test_values[] = {
18721 : snan,
18722 : qnan,
18723 : infinity,
18724 : max_normal,
18725 : date_limit + 1,
18726 : date_limit,
18727 : min_normal,
18728 : max_denormal,
18729 : min_denormal,
18730 : 0,
18731 : -0,
18732 : -min_denormal,
18733 : -max_denormal,
18734 : -min_normal,
18735 : -date_limit,
18736 : -date_limit - 1,
18737 : -max_normal,
18738 : -infinity,
18739 : -qnan,
18740 : -snan
18741 6 : };
18742 : int num_test_values = 20;
18743 :
18744 126 : for (int i = 0; i < num_test_values; i++) {
18745 120 : double test_value = test_values[i];
18746 :
18747 : // Check that Number::New preserves non-NaNs and quiets SNaNs.
18748 120 : v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
18749 240 : double stored_number = number->NumberValue(context.local()).FromJust();
18750 120 : if (!std::isnan(test_value)) {
18751 96 : CHECK_EQ(test_value, stored_number);
18752 : } else {
18753 : uint64_t stored_bits = DoubleToBits(stored_number);
18754 : // Check if quiet nan (bits 51..62 all set).
18755 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18756 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18757 : !defined(USE_SIMULATOR)
18758 : // Most significant fraction bit for quiet nan is set to 0
18759 : // on MIPS architecture. Allowed by IEEE-754.
18760 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18761 : #else
18762 24 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18763 : #endif
18764 : }
18765 :
18766 : // Check that Date::New preserves non-NaNs in the date range and
18767 : // quiets SNaNs.
18768 : v8::Local<v8::Value> date =
18769 120 : v8::Date::New(context.local(), test_value).ToLocalChecked();
18770 120 : double expected_stored_date = DoubleToDateTime(test_value);
18771 240 : double stored_date = date->NumberValue(context.local()).FromJust();
18772 120 : if (!std::isnan(expected_stored_date)) {
18773 60 : CHECK_EQ(expected_stored_date, stored_date);
18774 : } else {
18775 : uint64_t stored_bits = DoubleToBits(stored_date);
18776 : // Check if quiet nan (bits 51..62 all set).
18777 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18778 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18779 : !defined(USE_SIMULATOR)
18780 : // Most significant fraction bit for quiet nan is set to 0
18781 : // on MIPS architecture. Allowed by IEEE-754.
18782 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18783 : #else
18784 60 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18785 : #endif
18786 : }
18787 6 : }
18788 6 : }
18789 :
18790 :
18791 66 : static void SpaghettiIncident(
18792 198 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18793 66 : v8::HandleScope scope(args.GetIsolate());
18794 132 : v8::TryCatch tc(args.GetIsolate());
18795 : v8::MaybeLocal<v8::String> str(
18796 132 : args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
18797 : USE(str);
18798 66 : if (tc.HasCaught())
18799 132 : tc.ReThrow();
18800 66 : }
18801 :
18802 :
18803 : // Test that an exception can be propagated down through a spaghetti
18804 : // stack using ReThrow.
18805 25881 : THREADED_TEST(SpaghettiStackReThrow) {
18806 6 : v8::Isolate* isolate = CcTest::isolate();
18807 6 : v8::HandleScope scope(isolate);
18808 12 : LocalContext context;
18809 : context->Global()
18810 : ->Set(context.local(), v8_str("s"),
18811 6 : v8::FunctionTemplate::New(isolate, SpaghettiIncident)
18812 18 : ->GetFunction(context.local())
18813 30 : .ToLocalChecked())
18814 12 : .FromJust();
18815 12 : v8::TryCatch try_catch(isolate);
18816 : CompileRun(
18817 : "var i = 0;"
18818 : "var o = {"
18819 : " toString: function () {"
18820 : " if (i == 10) {"
18821 : " throw 'Hey!';"
18822 : " } else {"
18823 : " i++;"
18824 : " return s(o);"
18825 : " }"
18826 : " }"
18827 : "};"
18828 : "s(o);");
18829 6 : CHECK(try_catch.HasCaught());
18830 12 : v8::String::Utf8Value value(isolate, try_catch.Exception());
18831 12 : CHECK_EQ(0, strcmp(*value, "Hey!"));
18832 6 : }
18833 :
18834 :
18835 25880 : TEST(Regress528) {
18836 : ManualGCScope manual_gc_scope;
18837 5 : v8::V8::Initialize();
18838 5 : v8::Isolate* isolate = CcTest::isolate();
18839 5 : i::FLAG_retain_maps_for_n_gc = 0;
18840 10 : v8::HandleScope scope(isolate);
18841 : v8::Local<Context> other_context;
18842 : int gc_count;
18843 :
18844 : // Create a context used to keep the code from aging in the compilation
18845 : // cache.
18846 5 : other_context = Context::New(isolate);
18847 :
18848 : // Context-dependent context data creates reference from the compilation
18849 : // cache to the global object.
18850 : const char* source_simple = "1";
18851 : {
18852 5 : v8::HandleScope scope(isolate);
18853 5 : v8::Local<Context> context = Context::New(isolate);
18854 :
18855 5 : context->Enter();
18856 5 : Local<v8::String> obj = v8_str("");
18857 5 : context->SetEmbedderData(0, obj);
18858 : CompileRun(source_simple);
18859 5 : context->Exit();
18860 : }
18861 5 : isolate->ContextDisposedNotification();
18862 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18863 5 : other_context->Enter();
18864 : CompileRun(source_simple);
18865 5 : other_context->Exit();
18866 5 : CcTest::CollectAllGarbage();
18867 5 : if (GetGlobalObjectsCount() == 1) break;
18868 : }
18869 5 : CHECK_GE(2, gc_count);
18870 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18871 :
18872 : // Eval in a function creates reference from the compilation cache to the
18873 : // global object.
18874 : const char* source_eval = "function f(){eval('1')}; f()";
18875 : {
18876 5 : v8::HandleScope scope(isolate);
18877 5 : v8::Local<Context> context = Context::New(isolate);
18878 :
18879 5 : context->Enter();
18880 : CompileRun(source_eval);
18881 5 : context->Exit();
18882 : }
18883 5 : isolate->ContextDisposedNotification();
18884 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18885 5 : other_context->Enter();
18886 : CompileRun(source_eval);
18887 5 : other_context->Exit();
18888 5 : CcTest::CollectAllGarbage();
18889 5 : if (GetGlobalObjectsCount() == 1) break;
18890 : }
18891 5 : CHECK_GE(2, gc_count);
18892 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18893 :
18894 : // Looking up the line number for an exception creates reference from the
18895 : // compilation cache to the global object.
18896 : const char* source_exception = "function f(){throw 1;} f()";
18897 : {
18898 5 : v8::HandleScope scope(isolate);
18899 5 : v8::Local<Context> context = Context::New(isolate);
18900 :
18901 5 : context->Enter();
18902 10 : v8::TryCatch try_catch(isolate);
18903 : CompileRun(source_exception);
18904 5 : CHECK(try_catch.HasCaught());
18905 5 : v8::Local<v8::Message> message = try_catch.Message();
18906 5 : CHECK(!message.IsEmpty());
18907 10 : CHECK_EQ(1, message->GetLineNumber(context).FromJust());
18908 10 : context->Exit();
18909 : }
18910 5 : isolate->ContextDisposedNotification();
18911 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18912 5 : other_context->Enter();
18913 : CompileRun(source_exception);
18914 5 : other_context->Exit();
18915 5 : CcTest::CollectAllGarbage();
18916 5 : if (GetGlobalObjectsCount() == 1) break;
18917 : }
18918 5 : CHECK_GE(2, gc_count);
18919 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18920 :
18921 5 : isolate->ContextDisposedNotification();
18922 5 : }
18923 :
18924 :
18925 25881 : THREADED_TEST(ScriptOrigin) {
18926 6 : LocalContext env;
18927 6 : v8::Isolate* isolate = env->GetIsolate();
18928 12 : v8::HandleScope scope(isolate);
18929 6 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 1));
18930 6 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
18931 6 : array->Set(isolate, 0, symbol);
18932 :
18933 : v8::ScriptOrigin origin = v8::ScriptOrigin(
18934 : v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
18935 : v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
18936 : v8::Local<v8::Integer>(), v8_str("http://sourceMapUrl"),
18937 : v8::True(env->GetIsolate()), v8::False(env->GetIsolate()),
18938 42 : v8::False(env->GetIsolate()), array);
18939 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
18940 6 : v8::Script::Compile(env.local(), script, &origin)
18941 6 : .ToLocalChecked()
18942 6 : ->Run(env.local())
18943 6 : .ToLocalChecked();
18944 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18945 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18946 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18947 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18948 :
18949 6 : v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18950 6 : CHECK_EQ(0, strcmp("test",
18951 : *v8::String::Utf8Value(env->GetIsolate(),
18952 : script_origin_f.ResourceName())));
18953 12 : CHECK_EQ(
18954 : 1,
18955 : script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18956 6 : CHECK(script_origin_f.Options().IsSharedCrossOrigin());
18957 6 : CHECK(script_origin_f.Options().IsOpaque());
18958 6 : printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
18959 12 : CHECK(script_origin_f.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18960 :
18961 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
18962 : *v8::String::Utf8Value(env->GetIsolate(),
18963 : script_origin_f.SourceMapUrl())));
18964 :
18965 6 : v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18966 6 : CHECK_EQ(0, strcmp("test",
18967 : *v8::String::Utf8Value(env->GetIsolate(),
18968 : script_origin_g.ResourceName())));
18969 12 : CHECK_EQ(
18970 : 1,
18971 : script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18972 6 : CHECK(script_origin_g.Options().IsSharedCrossOrigin());
18973 6 : CHECK(script_origin_g.Options().IsOpaque());
18974 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
18975 : *v8::String::Utf8Value(env->GetIsolate(),
18976 : script_origin_g.SourceMapUrl())));
18977 18 : CHECK(script_origin_g.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18978 6 : }
18979 :
18980 :
18981 25881 : THREADED_TEST(FunctionGetInferredName) {
18982 6 : LocalContext env;
18983 12 : v8::HandleScope scope(env->GetIsolate());
18984 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18985 : v8::Local<v8::String> script =
18986 6 : v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18987 6 : v8::Script::Compile(env.local(), script, &origin)
18988 6 : .ToLocalChecked()
18989 6 : ->Run(env.local())
18990 6 : .ToLocalChecked();
18991 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18992 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18993 12 : CHECK_EQ(0,
18994 : strcmp("foo.bar.baz", *v8::String::Utf8Value(env->GetIsolate(),
18995 6 : f->GetInferredName())));
18996 6 : }
18997 :
18998 :
18999 25881 : THREADED_TEST(FunctionGetDebugName) {
19000 6 : LocalContext env;
19001 6 : v8::Isolate* isolate = env->GetIsolate();
19002 12 : v8::HandleScope scope(isolate);
19003 : const char* code =
19004 : "var error = false;"
19005 : "function a() { this.x = 1; };"
19006 : "a.displayName = 'display_a';"
19007 : "var b = (function() {"
19008 : " var f = function() { this.x = 2; };"
19009 : " f.displayName = 'display_b';"
19010 : " return f;"
19011 : "})();"
19012 : "var c = function() {};"
19013 : "c.__defineGetter__('displayName', function() {"
19014 : " error = true;"
19015 : " throw new Error();"
19016 : "});"
19017 : "function d() {};"
19018 : "d.__defineGetter__('displayName', function() {"
19019 : " error = true;"
19020 : " return 'wrong_display_name';"
19021 : "});"
19022 : "function e() {};"
19023 : "e.displayName = 'wrong_display_name';"
19024 : "e.__defineSetter__('displayName', function() {"
19025 : " error = true;"
19026 : " throw new Error();"
19027 : "});"
19028 : "function f() {};"
19029 : "f.displayName = { 'foo': 6, toString: function() {"
19030 : " error = true;"
19031 : " return 'wrong_display_name';"
19032 : "}};"
19033 : "var g = function() {"
19034 : " arguments.callee.displayName = 'set_in_runtime';"
19035 : "}; g();"
19036 : "var h = function() {};"
19037 : "h.displayName = 'displayName';"
19038 : "Object.defineProperty(h, 'name', { value: 'function.name' });"
19039 : "var i = function() {};"
19040 : "i.displayName = 239;"
19041 : "Object.defineProperty(i, 'name', { value: 'function.name' });"
19042 : "var j = function() {};"
19043 : "Object.defineProperty(j, 'name', { value: 'function.name' });"
19044 : "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
19045 : "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
19046 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19047 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19048 6 : .ToLocalChecked()
19049 6 : ->Run(env.local())
19050 6 : .ToLocalChecked();
19051 : v8::Local<v8::Value> error =
19052 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19053 6 : CHECK(!error->BooleanValue(isolate));
19054 : const char* functions[] = {"a", "display_a",
19055 : "b", "display_b",
19056 : "c", "c",
19057 : "d", "d",
19058 : "e", "e",
19059 : "f", "f",
19060 : "g", "set_in_runtime",
19061 : "h", "displayName",
19062 : "i", "function.name",
19063 : "j", "function.name",
19064 : "k", "foo.bar.baz",
19065 6 : "l", "baz"};
19066 78 : for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
19067 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19068 : env->Global()
19069 : ->Get(env.local(),
19070 72 : v8::String::NewFromUtf8(isolate, functions[i * 2],
19071 72 : v8::NewStringType::kNormal)
19072 288 : .ToLocalChecked())
19073 72 : .ToLocalChecked());
19074 72 : CHECK_EQ(0, strcmp(functions[i * 2 + 1],
19075 : *v8::String::Utf8Value(isolate, f->GetDebugName())));
19076 6 : }
19077 6 : }
19078 :
19079 :
19080 25881 : THREADED_TEST(FunctionGetDisplayName) {
19081 6 : LocalContext env;
19082 6 : v8::Isolate* isolate = env->GetIsolate();
19083 12 : v8::HandleScope scope(isolate);
19084 : const char* code = "var error = false;"
19085 : "function a() { this.x = 1; };"
19086 : "a.displayName = 'display_a';"
19087 : "var b = (function() {"
19088 : " var f = function() { this.x = 2; };"
19089 : " f.displayName = 'display_b';"
19090 : " return f;"
19091 : "})();"
19092 : "var c = function() {};"
19093 : "c.__defineGetter__('displayName', function() {"
19094 : " error = true;"
19095 : " throw new Error();"
19096 : "});"
19097 : "function d() {};"
19098 : "d.__defineGetter__('displayName', function() {"
19099 : " error = true;"
19100 : " return 'wrong_display_name';"
19101 : "});"
19102 : "function e() {};"
19103 : "e.displayName = 'wrong_display_name';"
19104 : "e.__defineSetter__('displayName', function() {"
19105 : " error = true;"
19106 : " throw new Error();"
19107 : "});"
19108 : "function f() {};"
19109 : "f.displayName = { 'foo': 6, toString: function() {"
19110 : " error = true;"
19111 : " return 'wrong_display_name';"
19112 : "}};"
19113 : "var g = function() {"
19114 : " arguments.callee.displayName = 'set_in_runtime';"
19115 : "}; g();";
19116 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19117 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19118 6 : .ToLocalChecked()
19119 6 : ->Run(env.local())
19120 6 : .ToLocalChecked();
19121 : v8::Local<v8::Value> error =
19122 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19123 : v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19124 30 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
19125 : v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19126 30 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
19127 : v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19128 30 : env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
19129 : v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19130 30 : env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
19131 : v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19132 30 : env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
19133 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19134 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19135 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19136 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19137 6 : CHECK(!error->BooleanValue(isolate));
19138 6 : CHECK_EQ(0, strcmp("display_a",
19139 : *v8::String::Utf8Value(isolate, a->GetDisplayName())));
19140 6 : CHECK_EQ(0, strcmp("display_b",
19141 : *v8::String::Utf8Value(isolate, b->GetDisplayName())));
19142 12 : CHECK(c->GetDisplayName()->IsUndefined());
19143 12 : CHECK(d->GetDisplayName()->IsUndefined());
19144 12 : CHECK(e->GetDisplayName()->IsUndefined());
19145 12 : CHECK(f->GetDisplayName()->IsUndefined());
19146 6 : CHECK_EQ(0, strcmp("set_in_runtime",
19147 6 : *v8::String::Utf8Value(isolate, g->GetDisplayName())));
19148 6 : }
19149 :
19150 :
19151 25881 : THREADED_TEST(ScriptLineNumber) {
19152 6 : LocalContext env;
19153 12 : v8::HandleScope scope(env->GetIsolate());
19154 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19155 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19156 6 : v8::Script::Compile(env.local(), script, &origin)
19157 6 : .ToLocalChecked()
19158 6 : ->Run(env.local())
19159 6 : .ToLocalChecked();
19160 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19161 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19162 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19163 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19164 6 : CHECK_EQ(0, f->GetScriptLineNumber());
19165 12 : CHECK_EQ(2, g->GetScriptLineNumber());
19166 6 : }
19167 :
19168 :
19169 25881 : THREADED_TEST(ScriptColumnNumber) {
19170 6 : LocalContext env;
19171 6 : v8::Isolate* isolate = env->GetIsolate();
19172 12 : v8::HandleScope scope(isolate);
19173 : v8::ScriptOrigin origin =
19174 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19175 6 : v8::Integer::New(isolate, 2));
19176 : v8::Local<v8::String> script =
19177 6 : v8_str("function foo() {}\n\n function bar() {}");
19178 6 : v8::Script::Compile(env.local(), script, &origin)
19179 6 : .ToLocalChecked()
19180 6 : ->Run(env.local())
19181 6 : .ToLocalChecked();
19182 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19183 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19184 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19185 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19186 6 : CHECK_EQ(14, foo->GetScriptColumnNumber());
19187 12 : CHECK_EQ(17, bar->GetScriptColumnNumber());
19188 6 : }
19189 :
19190 :
19191 25881 : THREADED_TEST(FunctionGetScriptId) {
19192 6 : LocalContext env;
19193 6 : v8::Isolate* isolate = env->GetIsolate();
19194 12 : v8::HandleScope scope(isolate);
19195 : v8::ScriptOrigin origin =
19196 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19197 6 : v8::Integer::New(isolate, 2));
19198 : v8::Local<v8::String> scriptSource =
19199 6 : v8_str("function foo() {}\n\n function bar() {}");
19200 : v8::Local<v8::Script> script(
19201 6 : v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
19202 6 : script->Run(env.local()).ToLocalChecked();
19203 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19204 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19205 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19206 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19207 12 : CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19208 18 : CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19209 6 : }
19210 :
19211 :
19212 25881 : THREADED_TEST(FunctionGetBoundFunction) {
19213 6 : LocalContext env;
19214 12 : v8::HandleScope scope(env->GetIsolate());
19215 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19216 : v8::Local<v8::String> script = v8_str(
19217 : "var a = new Object();\n"
19218 : "a.x = 1;\n"
19219 : "function f () { return this.x };\n"
19220 : "var g = f.bind(a);\n"
19221 6 : "var b = g();");
19222 6 : v8::Script::Compile(env.local(), script, &origin)
19223 6 : .ToLocalChecked()
19224 6 : ->Run(env.local())
19225 6 : .ToLocalChecked();
19226 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19227 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19228 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19229 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19230 12 : CHECK(g->GetBoundFunction()->IsFunction());
19231 : Local<v8::Function> original_function = Local<v8::Function>::Cast(
19232 6 : g->GetBoundFunction());
19233 18 : CHECK(f->GetName()
19234 : ->Equals(env.local(), original_function->GetName())
19235 : .FromJust());
19236 6 : CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19237 6 : CHECK_EQ(f->GetScriptColumnNumber(),
19238 6 : original_function->GetScriptColumnNumber());
19239 6 : }
19240 :
19241 :
19242 330 : static void GetterWhichReturns42(
19243 : Local<String> name,
19244 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19245 660 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19246 660 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19247 330 : info.GetReturnValue().Set(v8_num(42));
19248 330 : }
19249 :
19250 :
19251 270 : static void SetterWhichSetsYOnThisTo23(
19252 : Local<String> name,
19253 : Local<Value> value,
19254 : const v8::PropertyCallbackInfo<void>& info) {
19255 540 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19256 540 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19257 : Local<Object>::Cast(info.This())
19258 810 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19259 540 : .FromJust();
19260 270 : }
19261 :
19262 :
19263 120 : void FooGetInterceptor(Local<Name> name,
19264 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19265 240 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19266 240 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19267 360 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19268 240 : .FromJust()) {
19269 120 : return;
19270 : }
19271 96 : info.GetReturnValue().Set(v8_num(42));
19272 : }
19273 :
19274 :
19275 336 : void FooSetInterceptor(Local<Name> name, Local<Value> value,
19276 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19277 672 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19278 672 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19279 1008 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19280 672 : .FromJust()) {
19281 336 : return;
19282 : }
19283 : Local<Object>::Cast(info.This())
19284 288 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19285 192 : .FromJust();
19286 96 : info.GetReturnValue().Set(v8_num(23));
19287 : }
19288 :
19289 :
19290 25880 : TEST(SetterOnConstructorPrototype) {
19291 5 : v8::Isolate* isolate = CcTest::isolate();
19292 5 : v8::HandleScope scope(isolate);
19293 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19294 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19295 5 : SetterWhichSetsYOnThisTo23);
19296 10 : LocalContext context;
19297 30 : CHECK(context->Global()
19298 : ->Set(context.local(), v8_str("P"),
19299 : templ->NewInstance(context.local()).ToLocalChecked())
19300 : .FromJust());
19301 : CompileRun("function C1() {"
19302 : " this.x = 23;"
19303 : "};"
19304 : "C1.prototype = P;"
19305 : "function C2() {"
19306 : " this.x = 23"
19307 : "};"
19308 : "C2.prototype = { };"
19309 : "C2.prototype.__proto__ = P;");
19310 :
19311 : v8::Local<v8::Script> script;
19312 : script = v8_compile("new C1();");
19313 55 : for (int i = 0; i < 10; i++) {
19314 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19315 50 : script->Run(context.local()).ToLocalChecked());
19316 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19317 : .ToLocalChecked()
19318 : ->Int32Value(context.local())
19319 : .FromJust());
19320 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19321 : .ToLocalChecked()
19322 : ->Int32Value(context.local())
19323 : .FromJust());
19324 : }
19325 :
19326 : script = v8_compile("new C2();");
19327 55 : for (int i = 0; i < 10; i++) {
19328 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19329 50 : script->Run(context.local()).ToLocalChecked());
19330 200 : CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
19331 : .ToLocalChecked()
19332 : ->Int32Value(context.local())
19333 : .FromJust());
19334 200 : CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
19335 : .ToLocalChecked()
19336 : ->Int32Value(context.local())
19337 : .FromJust());
19338 5 : }
19339 5 : }
19340 :
19341 :
19342 0 : static void NamedPropertySetterWhichSetsYOnThisTo23(
19343 : Local<Name> name, Local<Value> value,
19344 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19345 0 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
19346 0 : .FromJust()) {
19347 : Local<Object>::Cast(info.This())
19348 0 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19349 0 : .FromJust();
19350 : }
19351 0 : }
19352 :
19353 :
19354 25881 : THREADED_TEST(InterceptorOnConstructorPrototype) {
19355 6 : v8::Isolate* isolate = CcTest::isolate();
19356 6 : v8::HandleScope scope(isolate);
19357 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19358 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19359 : NamedPropertyGetterWhichReturns42,
19360 6 : NamedPropertySetterWhichSetsYOnThisTo23));
19361 12 : LocalContext context;
19362 36 : CHECK(context->Global()
19363 : ->Set(context.local(), v8_str("P"),
19364 : templ->NewInstance(context.local()).ToLocalChecked())
19365 : .FromJust());
19366 : CompileRun("function C1() {"
19367 : " this.x = 23;"
19368 : "};"
19369 : "C1.prototype = P;"
19370 : "function C2() {"
19371 : " this.x = 23"
19372 : "};"
19373 : "C2.prototype = { };"
19374 : "C2.prototype.__proto__ = P;");
19375 :
19376 : v8::Local<v8::Script> script;
19377 : script = v8_compile("new C1();");
19378 66 : for (int i = 0; i < 10; i++) {
19379 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19380 60 : script->Run(context.local()).ToLocalChecked());
19381 240 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19382 : .ToLocalChecked()
19383 : ->Int32Value(context.local())
19384 : .FromJust());
19385 240 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19386 : .ToLocalChecked()
19387 : ->Int32Value(context.local())
19388 : .FromJust());
19389 : }
19390 :
19391 : script = v8_compile("new C2();");
19392 66 : for (int i = 0; i < 10; i++) {
19393 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19394 60 : script->Run(context.local()).ToLocalChecked());
19395 240 : CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
19396 : .ToLocalChecked()
19397 : ->Int32Value(context.local())
19398 : .FromJust());
19399 240 : CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
19400 : .ToLocalChecked()
19401 : ->Int32Value(context.local())
19402 : .FromJust());
19403 6 : }
19404 6 : }
19405 :
19406 :
19407 25880 : TEST(Regress618) {
19408 : const char* source = "function C1() {"
19409 : " this.x = 23;"
19410 : "};"
19411 : "C1.prototype = P;";
19412 :
19413 5 : LocalContext context;
19414 5 : v8::Isolate* isolate = context->GetIsolate();
19415 10 : v8::HandleScope scope(isolate);
19416 : v8::Local<v8::Script> script;
19417 :
19418 : // Use a simple object as prototype.
19419 5 : v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19420 20 : prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
19421 25 : CHECK(context->Global()
19422 : ->Set(context.local(), v8_str("P"), prototype)
19423 : .FromJust());
19424 :
19425 : // This compile will add the code to the compilation cache.
19426 : CompileRun(source);
19427 :
19428 : script = v8_compile("new C1();");
19429 : // Allow enough iterations for the inobject slack tracking logic
19430 : // to finalize instance size and install the fast construct stub.
19431 1285 : for (int i = 0; i < 256; i++) {
19432 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19433 1280 : script->Run(context.local()).ToLocalChecked());
19434 5120 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19435 : .ToLocalChecked()
19436 : ->Int32Value(context.local())
19437 : .FromJust());
19438 5120 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19439 : .ToLocalChecked()
19440 : ->Int32Value(context.local())
19441 : .FromJust());
19442 : }
19443 :
19444 : // Use an API object with accessors as prototype.
19445 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19446 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19447 5 : SetterWhichSetsYOnThisTo23);
19448 30 : CHECK(context->Global()
19449 : ->Set(context.local(), v8_str("P"),
19450 : templ->NewInstance(context.local()).ToLocalChecked())
19451 : .FromJust());
19452 :
19453 : // This compile will get the code from the compilation cache.
19454 : CompileRun(source);
19455 :
19456 : script = v8_compile("new C1();");
19457 55 : for (int i = 0; i < 10; i++) {
19458 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19459 50 : script->Run(context.local()).ToLocalChecked());
19460 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19461 : .ToLocalChecked()
19462 : ->Int32Value(context.local())
19463 : .FromJust());
19464 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19465 : .ToLocalChecked()
19466 : ->Int32Value(context.local())
19467 : .FromJust());
19468 5 : }
19469 5 : }
19470 :
19471 : v8::Isolate* gc_callbacks_isolate = nullptr;
19472 : int prologue_call_count = 0;
19473 : int epilogue_call_count = 0;
19474 : int prologue_call_count_second = 0;
19475 : int epilogue_call_count_second = 0;
19476 : int prologue_call_count_alloc = 0;
19477 : int epilogue_call_count_alloc = 0;
19478 :
19479 20 : void PrologueCallback(v8::Isolate* isolate,
19480 : v8::GCType,
19481 : v8::GCCallbackFlags flags) {
19482 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19483 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19484 20 : ++prologue_call_count;
19485 20 : }
19486 :
19487 20 : void EpilogueCallback(v8::Isolate* isolate,
19488 : v8::GCType,
19489 : v8::GCCallbackFlags flags) {
19490 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19491 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19492 20 : ++epilogue_call_count;
19493 20 : }
19494 :
19495 :
19496 20 : void PrologueCallbackSecond(v8::Isolate* isolate,
19497 : v8::GCType,
19498 : v8::GCCallbackFlags flags) {
19499 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19500 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19501 20 : ++prologue_call_count_second;
19502 20 : }
19503 :
19504 :
19505 20 : void EpilogueCallbackSecond(v8::Isolate* isolate,
19506 : v8::GCType,
19507 : v8::GCCallbackFlags flags) {
19508 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19509 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19510 20 : ++epilogue_call_count_second;
19511 20 : }
19512 :
19513 20 : void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
19514 : v8::GCCallbackFlags flags, void* data) {
19515 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19516 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19517 20 : ++*static_cast<int*>(data);
19518 20 : }
19519 :
19520 20 : void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
19521 : v8::GCCallbackFlags flags, void* data) {
19522 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19523 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19524 20 : ++*static_cast<int*>(data);
19525 20 : }
19526 :
19527 5 : void PrologueCallbackAlloc(v8::Isolate* isolate,
19528 : v8::GCType,
19529 : v8::GCCallbackFlags flags) {
19530 5 : v8::HandleScope scope(isolate);
19531 :
19532 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19533 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19534 5 : ++prologue_call_count_alloc;
19535 :
19536 : // Simulate full heap to see if we will reenter this callback
19537 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19538 :
19539 5 : Local<Object> obj = Object::New(isolate);
19540 5 : CHECK(!obj.IsEmpty());
19541 :
19542 5 : CcTest::PreciseCollectAllGarbage();
19543 5 : }
19544 :
19545 :
19546 5 : void EpilogueCallbackAlloc(v8::Isolate* isolate,
19547 : v8::GCType,
19548 : v8::GCCallbackFlags flags) {
19549 5 : v8::HandleScope scope(isolate);
19550 :
19551 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19552 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19553 5 : ++epilogue_call_count_alloc;
19554 :
19555 : // Simulate full heap to see if we will reenter this callback
19556 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19557 :
19558 5 : Local<Object> obj = Object::New(isolate);
19559 5 : CHECK(!obj.IsEmpty());
19560 :
19561 5 : CcTest::PreciseCollectAllGarbage();
19562 5 : }
19563 :
19564 :
19565 25880 : TEST(GCCallbacksOld) {
19566 5 : LocalContext context;
19567 :
19568 5 : gc_callbacks_isolate = context->GetIsolate();
19569 :
19570 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
19571 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
19572 5 : CHECK_EQ(0, prologue_call_count);
19573 5 : CHECK_EQ(0, epilogue_call_count);
19574 5 : CcTest::CollectAllGarbage();
19575 5 : CHECK_EQ(1, prologue_call_count);
19576 5 : CHECK_EQ(1, epilogue_call_count);
19577 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
19578 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
19579 5 : CcTest::CollectAllGarbage();
19580 5 : CHECK_EQ(2, prologue_call_count);
19581 5 : CHECK_EQ(2, epilogue_call_count);
19582 5 : CHECK_EQ(1, prologue_call_count_second);
19583 5 : CHECK_EQ(1, epilogue_call_count_second);
19584 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
19585 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
19586 5 : CcTest::CollectAllGarbage();
19587 5 : CHECK_EQ(2, prologue_call_count);
19588 5 : CHECK_EQ(2, epilogue_call_count);
19589 5 : CHECK_EQ(2, prologue_call_count_second);
19590 5 : CHECK_EQ(2, epilogue_call_count_second);
19591 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
19592 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19593 5 : CcTest::CollectAllGarbage();
19594 5 : CHECK_EQ(2, prologue_call_count);
19595 5 : CHECK_EQ(2, epilogue_call_count);
19596 5 : CHECK_EQ(2, prologue_call_count_second);
19597 5 : CHECK_EQ(2, epilogue_call_count_second);
19598 5 : }
19599 :
19600 25880 : TEST(GCCallbacksWithData) {
19601 5 : LocalContext context;
19602 :
19603 5 : gc_callbacks_isolate = context->GetIsolate();
19604 5 : int prologue1 = 0;
19605 5 : int epilogue1 = 0;
19606 5 : int prologue2 = 0;
19607 5 : int epilogue2 = 0;
19608 :
19609 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
19610 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
19611 5 : CHECK_EQ(0, prologue1);
19612 5 : CHECK_EQ(0, epilogue1);
19613 5 : CHECK_EQ(0, prologue2);
19614 5 : CHECK_EQ(0, epilogue2);
19615 5 : CcTest::CollectAllGarbage();
19616 5 : CHECK_EQ(1, prologue1);
19617 5 : CHECK_EQ(1, epilogue1);
19618 5 : CHECK_EQ(0, prologue2);
19619 5 : CHECK_EQ(0, epilogue2);
19620 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
19621 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
19622 5 : CcTest::CollectAllGarbage();
19623 5 : CHECK_EQ(2, prologue1);
19624 5 : CHECK_EQ(2, epilogue1);
19625 5 : CHECK_EQ(1, prologue2);
19626 5 : CHECK_EQ(1, epilogue2);
19627 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19628 5 : &prologue1);
19629 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19630 5 : &epilogue1);
19631 5 : CcTest::CollectAllGarbage();
19632 5 : CHECK_EQ(2, prologue1);
19633 5 : CHECK_EQ(2, epilogue1);
19634 5 : CHECK_EQ(2, prologue2);
19635 5 : CHECK_EQ(2, epilogue2);
19636 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19637 5 : &prologue2);
19638 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19639 5 : &epilogue2);
19640 5 : CcTest::CollectAllGarbage();
19641 5 : CHECK_EQ(2, prologue1);
19642 5 : CHECK_EQ(2, epilogue1);
19643 5 : CHECK_EQ(2, prologue2);
19644 5 : CHECK_EQ(2, epilogue2);
19645 5 : }
19646 :
19647 25880 : TEST(GCCallbacks) {
19648 5 : LocalContext context;
19649 5 : v8::Isolate* isolate = context->GetIsolate();
19650 5 : gc_callbacks_isolate = isolate;
19651 5 : isolate->AddGCPrologueCallback(PrologueCallback);
19652 5 : isolate->AddGCEpilogueCallback(EpilogueCallback);
19653 5 : CHECK_EQ(0, prologue_call_count);
19654 5 : CHECK_EQ(0, epilogue_call_count);
19655 5 : CcTest::CollectAllGarbage();
19656 5 : CHECK_EQ(1, prologue_call_count);
19657 5 : CHECK_EQ(1, epilogue_call_count);
19658 5 : isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19659 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19660 5 : CcTest::CollectAllGarbage();
19661 5 : CHECK_EQ(2, prologue_call_count);
19662 5 : CHECK_EQ(2, epilogue_call_count);
19663 5 : CHECK_EQ(1, prologue_call_count_second);
19664 5 : CHECK_EQ(1, epilogue_call_count_second);
19665 5 : isolate->RemoveGCPrologueCallback(PrologueCallback);
19666 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19667 5 : CcTest::CollectAllGarbage();
19668 5 : CHECK_EQ(2, prologue_call_count);
19669 5 : CHECK_EQ(2, epilogue_call_count);
19670 5 : CHECK_EQ(2, prologue_call_count_second);
19671 5 : CHECK_EQ(2, epilogue_call_count_second);
19672 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19673 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19674 5 : CcTest::CollectAllGarbage();
19675 5 : CHECK_EQ(2, prologue_call_count);
19676 5 : CHECK_EQ(2, epilogue_call_count);
19677 5 : CHECK_EQ(2, prologue_call_count_second);
19678 5 : CHECK_EQ(2, epilogue_call_count_second);
19679 :
19680 5 : CHECK_EQ(0, prologue_call_count_alloc);
19681 5 : CHECK_EQ(0, epilogue_call_count_alloc);
19682 5 : isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19683 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19684 5 : CcTest::PreciseCollectAllGarbage();
19685 5 : CHECK_EQ(1, prologue_call_count_alloc);
19686 5 : CHECK_EQ(1, epilogue_call_count_alloc);
19687 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19688 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19689 5 : }
19690 :
19691 :
19692 25881 : THREADED_TEST(TwoByteStringInOneByteCons) {
19693 : // See Chromium issue 47824.
19694 6 : LocalContext context;
19695 12 : v8::HandleScope scope(context->GetIsolate());
19696 :
19697 : const char* init_code =
19698 : "var str1 = 'abelspendabel';"
19699 : "var str2 = str1 + str1 + str1;"
19700 : "str2;";
19701 : Local<Value> result = CompileRun(init_code);
19702 :
19703 6 : Local<Value> indexof = CompileRun("str2.indexOf('els')");
19704 6 : Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19705 :
19706 6 : CHECK(result->IsString());
19707 : i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19708 : int length = string->length();
19709 6 : CHECK(string->IsOneByteRepresentation());
19710 :
19711 6 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
19712 6 : i::Handle<i::String> flat_string = i::String::Flatten(i_isolate, string);
19713 :
19714 6 : CHECK(string->IsOneByteRepresentation());
19715 6 : CHECK(flat_string->IsOneByteRepresentation());
19716 :
19717 : // Create external resource.
19718 6 : uint16_t* uc16_buffer = new uint16_t[length + 1];
19719 :
19720 6 : i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19721 6 : uc16_buffer[length] = 0;
19722 :
19723 6 : TestResource resource(uc16_buffer);
19724 :
19725 6 : flat_string->MakeExternal(&resource);
19726 :
19727 6 : CHECK(flat_string->IsTwoByteRepresentation());
19728 :
19729 : // If the cons string has been short-circuited, skip the following checks.
19730 6 : if (!string.is_identical_to(flat_string)) {
19731 : // At this point, we should have a Cons string which is flat and one-byte,
19732 : // with a first half that is a two-byte string (although it only contains
19733 : // one-byte characters). This is a valid sequence of steps, and it can
19734 : // happen in real pages.
19735 6 : CHECK(string->IsOneByteRepresentation());
19736 6 : i::ConsString cons = i::ConsString::cast(*string);
19737 12 : CHECK_EQ(0, cons->second()->length());
19738 6 : CHECK(cons->first()->IsTwoByteRepresentation());
19739 : }
19740 :
19741 : // Check that some string operations work.
19742 :
19743 : // Atom RegExp.
19744 : Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19745 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19746 :
19747 : // Nonatom RegExp.
19748 : reresult = CompileRun("str2.match(/abe./g).length;");
19749 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19750 :
19751 : reresult = CompileRun("str2.search(/bel/g);");
19752 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19753 :
19754 : reresult = CompileRun("str2.search(/be./g);");
19755 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19756 :
19757 : ExpectTrue("/bel/g.test(str2);");
19758 :
19759 : ExpectTrue("/be./g.test(str2);");
19760 :
19761 : reresult = CompileRun("/bel/g.exec(str2);");
19762 6 : CHECK(!reresult->IsNull());
19763 :
19764 : reresult = CompileRun("/be./g.exec(str2);");
19765 6 : CHECK(!reresult->IsNull());
19766 :
19767 6 : ExpectString("str2.substring(2, 10);", "elspenda");
19768 :
19769 6 : ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19770 :
19771 6 : ExpectString("str2.charAt(2);", "e");
19772 :
19773 6 : ExpectObject("str2.indexOf('els');", indexof);
19774 :
19775 6 : ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19776 :
19777 : reresult = CompileRun("str2.charCodeAt(2);");
19778 12 : CHECK_EQ(static_cast<int32_t>('e'),
19779 : reresult->Int32Value(context.local()).FromJust());
19780 : // This avoids the GC from trying to free stack allocated resources.
19781 : i::Handle<i::ExternalTwoByteString>::cast(flat_string)
19782 18 : ->SetResource(i_isolate, nullptr);
19783 6 : }
19784 :
19785 :
19786 25880 : TEST(ContainsOnlyOneByte) {
19787 5 : v8::V8::Initialize();
19788 5 : v8::Isolate* isolate = CcTest::isolate();
19789 5 : v8::HandleScope scope(isolate);
19790 : // Make a buffer long enough that it won't automatically be converted.
19791 : const int length = 512;
19792 : // Ensure word aligned assignment.
19793 : const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19794 5 : std::unique_ptr<uintptr_t[]> aligned_contents(new uintptr_t[aligned_length]);
19795 : uint16_t* string_contents =
19796 : reinterpret_cast<uint16_t*>(aligned_contents.get());
19797 : // Set to contain only one byte.
19798 2560 : for (int i = 0; i < length-1; i++) {
19799 2555 : string_contents[i] = 0x41;
19800 : }
19801 5 : string_contents[length-1] = 0;
19802 : // Simple case.
19803 : Local<String> string =
19804 : String::NewExternalTwoByte(
19805 5 : isolate, new TestResource(string_contents, nullptr, false))
19806 5 : .ToLocalChecked();
19807 5 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19808 : // Counter example.
19809 : string = String::NewFromTwoByte(isolate, string_contents,
19810 : v8::NewStringType::kNormal)
19811 5 : .ToLocalChecked();
19812 5 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19813 : // Test left right and balanced cons strings.
19814 5 : Local<String> base = v8_str("a");
19815 5 : Local<String> left = base;
19816 5 : Local<String> right = base;
19817 5005 : for (int i = 0; i < 1000; i++) {
19818 5000 : left = String::Concat(isolate, base, left);
19819 5000 : right = String::Concat(isolate, right, base);
19820 : }
19821 5 : Local<String> balanced = String::Concat(isolate, left, base);
19822 5 : balanced = String::Concat(isolate, balanced, right);
19823 5 : Local<String> cons_strings[] = {left, balanced, right};
19824 : Local<String> two_byte =
19825 : String::NewExternalTwoByte(
19826 5 : isolate, new TestResource(string_contents, nullptr, false))
19827 10 : .ToLocalChecked();
19828 : USE(two_byte); USE(cons_strings);
19829 20 : for (size_t i = 0; i < arraysize(cons_strings); i++) {
19830 : // Base assumptions.
19831 15 : string = cons_strings[i];
19832 15 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19833 : // Test left and right concatentation.
19834 15 : string = String::Concat(isolate, two_byte, cons_strings[i]);
19835 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19836 15 : string = String::Concat(isolate, cons_strings[i], two_byte);
19837 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19838 : }
19839 : // Set bits in different positions
19840 : // for strings of different lengths and alignments.
19841 35 : for (int alignment = 0; alignment < 7; alignment++) {
19842 280 : for (int size = 2; alignment + size < length; size *= 2) {
19843 : int zero_offset = size + alignment;
19844 280 : string_contents[zero_offset] = 0;
19845 18130 : for (int i = 0; i < size; i++) {
19846 17850 : int shift = 8 + (i % 7);
19847 17850 : string_contents[alignment + i] = 1 << shift;
19848 : string = String::NewExternalTwoByte(
19849 : isolate, new TestResource(string_contents + alignment,
19850 17850 : nullptr, false))
19851 17850 : .ToLocalChecked();
19852 17850 : CHECK_EQ(size, string->Length());
19853 17850 : CHECK(!string->ContainsOnlyOneByte());
19854 17850 : string_contents[alignment + i] = 0x41;
19855 : }
19856 280 : string_contents[zero_offset] = 0x41;
19857 : }
19858 5 : }
19859 5 : }
19860 :
19861 :
19862 : // Failed access check callback that performs a GC on each invocation.
19863 75 : void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19864 : v8::AccessType type,
19865 : Local<v8::Value> data) {
19866 75 : CcTest::CollectAllGarbage();
19867 : CcTest::isolate()->ThrowException(
19868 75 : v8::Exception::Error(v8_str("cross context")));
19869 75 : }
19870 :
19871 :
19872 25880 : TEST(GCInFailedAccessCheckCallback) {
19873 : // Install a failed access check callback that performs a GC on each
19874 : // invocation. Then force the callback to be called from va
19875 :
19876 5 : v8::V8::Initialize();
19877 5 : v8::Isolate* isolate = CcTest::isolate();
19878 :
19879 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19880 :
19881 5 : v8::HandleScope scope(isolate);
19882 :
19883 : // Create an ObjectTemplate for global objects and install access
19884 : // check callbacks that will block access.
19885 : v8::Local<v8::ObjectTemplate> global_template =
19886 5 : v8::ObjectTemplate::New(isolate);
19887 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
19888 :
19889 : // Create a context and set an x property on it's global object.
19890 10 : LocalContext context0(nullptr, global_template);
19891 25 : CHECK(context0->Global()
19892 : ->Set(context0.local(), v8_str("x"), v8_num(42))
19893 : .FromJust());
19894 5 : v8::Local<v8::Object> global0 = context0->Global();
19895 :
19896 : // Create a context with a different security token so that the
19897 : // failed access check callback will be called on each access.
19898 10 : LocalContext context1(nullptr, global_template);
19899 25 : CHECK(context1->Global()
19900 : ->Set(context1.local(), v8_str("other"), global0)
19901 : .FromJust());
19902 :
19903 10 : v8::TryCatch try_catch(isolate);
19904 :
19905 : // Get property with failed access check.
19906 5 : CHECK(CompileRun("other.x").IsEmpty());
19907 5 : CHECK(try_catch.HasCaught());
19908 5 : try_catch.Reset();
19909 :
19910 : // Get element with failed access check.
19911 5 : CHECK(CompileRun("other[0]").IsEmpty());
19912 5 : CHECK(try_catch.HasCaught());
19913 5 : try_catch.Reset();
19914 :
19915 : // Set property with failed access check.
19916 5 : CHECK(CompileRun("other.x = new Object()").IsEmpty());
19917 5 : CHECK(try_catch.HasCaught());
19918 5 : try_catch.Reset();
19919 :
19920 : // Set element with failed access check.
19921 5 : CHECK(CompileRun("other[0] = new Object()").IsEmpty());
19922 5 : CHECK(try_catch.HasCaught());
19923 5 : try_catch.Reset();
19924 :
19925 : // Get property attribute with failed access check.
19926 5 : CHECK(CompileRun("\'x\' in other").IsEmpty());
19927 5 : CHECK(try_catch.HasCaught());
19928 5 : try_catch.Reset();
19929 :
19930 : // Get property attribute for element with failed access check.
19931 5 : CHECK(CompileRun("0 in other").IsEmpty());
19932 5 : CHECK(try_catch.HasCaught());
19933 5 : try_catch.Reset();
19934 :
19935 : // Delete property.
19936 5 : CHECK(CompileRun("delete other.x").IsEmpty());
19937 5 : CHECK(try_catch.HasCaught());
19938 5 : try_catch.Reset();
19939 :
19940 : // Delete element.
19941 10 : CHECK(global0->Delete(context1.local(), 0).IsNothing());
19942 5 : CHECK(try_catch.HasCaught());
19943 5 : try_catch.Reset();
19944 :
19945 : // DefineAccessor.
19946 20 : CHECK(global0
19947 : ->SetAccessor(context1.local(), v8_str("x"), GetXValue, nullptr,
19948 : v8_str("x"))
19949 : .IsNothing());
19950 5 : CHECK(try_catch.HasCaught());
19951 5 : try_catch.Reset();
19952 :
19953 : // Define JavaScript accessor.
19954 5 : CHECK(CompileRun(
19955 : "Object.prototype.__defineGetter__.call("
19956 : " other, \'x\', function() { return 42; })").IsEmpty());
19957 5 : CHECK(try_catch.HasCaught());
19958 5 : try_catch.Reset();
19959 :
19960 : // LookupAccessor.
19961 5 : CHECK(CompileRun(
19962 : "Object.prototype.__lookupGetter__.call("
19963 : " other, \'x\')").IsEmpty());
19964 5 : CHECK(try_catch.HasCaught());
19965 5 : try_catch.Reset();
19966 :
19967 : // HasOwnElement.
19968 5 : CHECK(CompileRun(
19969 : "Object.prototype.hasOwnProperty.call("
19970 : "other, \'0\')").IsEmpty());
19971 5 : CHECK(try_catch.HasCaught());
19972 5 : try_catch.Reset();
19973 :
19974 10 : CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
19975 5 : CHECK(try_catch.HasCaught());
19976 5 : try_catch.Reset();
19977 :
19978 15 : CHECK(
19979 : global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
19980 5 : CHECK(try_catch.HasCaught());
19981 5 : try_catch.Reset();
19982 :
19983 15 : CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
19984 : .IsNothing());
19985 5 : CHECK(try_catch.HasCaught());
19986 5 : try_catch.Reset();
19987 :
19988 : // Reset the failed access check callback so it does not influence
19989 : // the other tests.
19990 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
19991 5 : }
19992 :
19993 :
19994 25880 : TEST(IsolateNewDispose) {
19995 5 : v8::Isolate* current_isolate = CcTest::isolate();
19996 : v8::Isolate::CreateParams create_params;
19997 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19998 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
19999 5 : CHECK_NOT_NULL(isolate);
20000 5 : CHECK(current_isolate != isolate);
20001 5 : CHECK(current_isolate == CcTest::isolate());
20002 :
20003 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20004 5 : last_location = last_message = nullptr;
20005 5 : isolate->Dispose();
20006 5 : CHECK(!last_location);
20007 5 : CHECK(!last_message);
20008 5 : }
20009 :
20010 :
20011 25880 : UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20012 : v8::Isolate::CreateParams create_params;
20013 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20014 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20015 : {
20016 : v8::Isolate::Scope i_scope(isolate);
20017 10 : v8::HandleScope scope(isolate);
20018 5 : LocalContext context(isolate);
20019 : // Run something in this isolate.
20020 : ExpectTrue("true");
20021 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20022 5 : last_location = last_message = nullptr;
20023 : // Still entered, should fail.
20024 5 : isolate->Dispose();
20025 5 : CHECK(last_location);
20026 5 : CHECK(last_message);
20027 : }
20028 5 : isolate->Dispose();
20029 5 : }
20030 :
20031 :
20032 40 : static void BreakArrayGuarantees(const char* script) {
20033 : v8::Isolate::CreateParams create_params;
20034 40 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20035 40 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20036 40 : isolate1->Enter();
20037 : v8::Persistent<v8::Context> context1;
20038 : {
20039 40 : v8::HandleScope scope(isolate1);
20040 80 : context1.Reset(isolate1, Context::New(isolate1));
20041 : }
20042 :
20043 : {
20044 40 : v8::HandleScope scope(isolate1);
20045 : v8::Local<v8::Context> context =
20046 : v8::Local<v8::Context>::New(isolate1, context1);
20047 : v8::Context::Scope context_scope(context);
20048 : v8::internal::Isolate* i_isolate =
20049 : reinterpret_cast<v8::internal::Isolate*>(isolate1);
20050 40 : CHECK(i_isolate->IsNoElementsProtectorIntact());
20051 : // Run something in new isolate.
20052 : CompileRun(script);
20053 80 : CHECK(!i_isolate->IsNoElementsProtectorIntact());
20054 : }
20055 40 : isolate1->Exit();
20056 40 : isolate1->Dispose();
20057 40 : }
20058 :
20059 :
20060 25880 : TEST(VerifyArrayPrototypeGuarantees) {
20061 : // Break fast array hole handling by element changes.
20062 5 : BreakArrayGuarantees("[].__proto__[1] = 3;");
20063 5 : BreakArrayGuarantees("Object.prototype[3] = 'three';");
20064 5 : BreakArrayGuarantees("Array.prototype.push(1);");
20065 5 : BreakArrayGuarantees("Array.prototype.unshift(1);");
20066 : // Break fast array hole handling by changing length.
20067 5 : BreakArrayGuarantees("Array.prototype.length = 30;");
20068 : // Break fast array hole handling by prototype structure changes.
20069 5 : BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
20070 : // By sending elements to dictionary mode.
20071 : BreakArrayGuarantees(
20072 : "Object.defineProperty(Array.prototype, 0, {"
20073 5 : " get: function() { return 3; }});");
20074 : BreakArrayGuarantees(
20075 : "Object.defineProperty(Object.prototype, 0, {"
20076 5 : " get: function() { return 3; }});");
20077 5 : }
20078 :
20079 :
20080 25880 : TEST(RunTwoIsolatesOnSingleThread) {
20081 : // Run isolate 1.
20082 : v8::Isolate::CreateParams create_params;
20083 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20084 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20085 5 : isolate1->Enter();
20086 : v8::Persistent<v8::Context> context1;
20087 : {
20088 5 : v8::HandleScope scope(isolate1);
20089 10 : context1.Reset(isolate1, Context::New(isolate1));
20090 : }
20091 :
20092 : {
20093 5 : v8::HandleScope scope(isolate1);
20094 : v8::Local<v8::Context> context =
20095 : v8::Local<v8::Context>::New(isolate1, context1);
20096 : v8::Context::Scope context_scope(context);
20097 : // Run something in new isolate.
20098 : CompileRun("var foo = 'isolate 1';");
20099 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20100 : }
20101 :
20102 : // Run isolate 2.
20103 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
20104 : v8::Persistent<v8::Context> context2;
20105 :
20106 : {
20107 : v8::Isolate::Scope iscope(isolate2);
20108 10 : v8::HandleScope scope(isolate2);
20109 10 : context2.Reset(isolate2, Context::New(isolate2));
20110 : v8::Local<v8::Context> context =
20111 : v8::Local<v8::Context>::New(isolate2, context2);
20112 : v8::Context::Scope context_scope(context);
20113 :
20114 : // Run something in new isolate.
20115 : CompileRun("var foo = 'isolate 2';");
20116 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20117 : }
20118 :
20119 : {
20120 5 : v8::HandleScope scope(isolate1);
20121 : v8::Local<v8::Context> context =
20122 : v8::Local<v8::Context>::New(isolate1, context1);
20123 : v8::Context::Scope context_scope(context);
20124 : // Now again in isolate 1
20125 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20126 : }
20127 :
20128 5 : isolate1->Exit();
20129 :
20130 : // Run some stuff in default isolate.
20131 : v8::Persistent<v8::Context> context_default;
20132 : {
20133 5 : v8::Isolate* isolate = CcTest::isolate();
20134 : v8::Isolate::Scope iscope(isolate);
20135 10 : v8::HandleScope scope(isolate);
20136 10 : context_default.Reset(isolate, Context::New(isolate));
20137 : }
20138 :
20139 : {
20140 5 : v8::HandleScope scope(CcTest::isolate());
20141 : v8::Local<v8::Context> context =
20142 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20143 : v8::Context::Scope context_scope(context);
20144 : // Variables in other isolates should be not available, verify there
20145 : // is an exception.
20146 : ExpectTrue("function f() {"
20147 : " try {"
20148 : " foo;"
20149 : " return false;"
20150 : " } catch(e) {"
20151 : " return true;"
20152 : " }"
20153 : "};"
20154 : "var isDefaultIsolate = true;"
20155 5 : "f()");
20156 : }
20157 :
20158 5 : isolate1->Enter();
20159 :
20160 : {
20161 : v8::Isolate::Scope iscope(isolate2);
20162 10 : v8::HandleScope scope(isolate2);
20163 : v8::Local<v8::Context> context =
20164 : v8::Local<v8::Context>::New(isolate2, context2);
20165 : v8::Context::Scope context_scope(context);
20166 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20167 : }
20168 :
20169 : {
20170 5 : v8::HandleScope scope(v8::Isolate::GetCurrent());
20171 : v8::Local<v8::Context> context =
20172 5 : v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20173 : v8::Context::Scope context_scope(context);
20174 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20175 : }
20176 :
20177 : {
20178 : v8::Isolate::Scope iscope(isolate2);
20179 : context2.Reset();
20180 : }
20181 :
20182 : context1.Reset();
20183 5 : isolate1->Exit();
20184 :
20185 5 : isolate2->SetFatalErrorHandler(StoringErrorCallback);
20186 5 : last_location = last_message = nullptr;
20187 :
20188 5 : isolate1->Dispose();
20189 5 : CHECK(!last_location);
20190 5 : CHECK(!last_message);
20191 :
20192 5 : isolate2->Dispose();
20193 5 : CHECK(!last_location);
20194 5 : CHECK(!last_message);
20195 :
20196 : // Check that default isolate still runs.
20197 : {
20198 5 : v8::HandleScope scope(CcTest::isolate());
20199 : v8::Local<v8::Context> context =
20200 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20201 : v8::Context::Scope context_scope(context);
20202 5 : ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20203 : }
20204 5 : }
20205 :
20206 :
20207 20 : static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20208 : v8::Isolate::Scope isolate_scope(isolate);
20209 40 : v8::HandleScope scope(isolate);
20210 20 : LocalContext context(isolate);
20211 : i::ScopedVector<char> code(1024);
20212 : i::SNPrintF(code, "function fib(n) {"
20213 : " if (n <= 2) return 1;"
20214 : " return fib(n-1) + fib(n-2);"
20215 : "}"
20216 20 : "fib(%d)", limit);
20217 : Local<Value> value = CompileRun(code.start());
20218 20 : CHECK(value->IsNumber());
20219 60 : return static_cast<int>(value->NumberValue(context.local()).FromJust());
20220 : }
20221 :
20222 5 : class IsolateThread : public v8::base::Thread {
20223 : public:
20224 : explicit IsolateThread(int fib_limit)
20225 10 : : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20226 :
20227 10 : void Run() override {
20228 : v8::Isolate::CreateParams create_params;
20229 10 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20230 10 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20231 10 : result_ = CalcFibonacci(isolate, fib_limit_);
20232 10 : isolate->Dispose();
20233 10 : }
20234 :
20235 : int result() { return result_; }
20236 :
20237 : private:
20238 : int fib_limit_;
20239 : int result_;
20240 : };
20241 :
20242 :
20243 25880 : TEST(MultipleIsolatesOnIndividualThreads) {
20244 : IsolateThread thread1(21);
20245 : IsolateThread thread2(12);
20246 :
20247 : // Compute some fibonacci numbers on 3 threads in 3 isolates.
20248 5 : thread1.Start();
20249 5 : thread2.Start();
20250 :
20251 5 : int result1 = CalcFibonacci(CcTest::isolate(), 21);
20252 5 : int result2 = CalcFibonacci(CcTest::isolate(), 12);
20253 :
20254 5 : thread1.Join();
20255 5 : thread2.Join();
20256 :
20257 : // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20258 : // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20259 5 : CHECK_EQ(result1, 10946);
20260 5 : CHECK_EQ(result2, 144);
20261 5 : CHECK_EQ(result1, thread1.result());
20262 5 : CHECK_EQ(result2, thread2.result());
20263 5 : }
20264 :
20265 :
20266 25880 : TEST(IsolateDifferentContexts) {
20267 : v8::Isolate::CreateParams create_params;
20268 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20269 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20270 : Local<v8::Context> context;
20271 : {
20272 : v8::Isolate::Scope isolate_scope(isolate);
20273 10 : v8::HandleScope handle_scope(isolate);
20274 5 : context = v8::Context::New(isolate);
20275 : v8::Context::Scope context_scope(context);
20276 : Local<Value> v = CompileRun("2");
20277 5 : CHECK(v->IsNumber());
20278 10 : CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
20279 : }
20280 : {
20281 : v8::Isolate::Scope isolate_scope(isolate);
20282 10 : v8::HandleScope handle_scope(isolate);
20283 5 : context = v8::Context::New(isolate);
20284 : v8::Context::Scope context_scope(context);
20285 : Local<Value> v = CompileRun("22");
20286 5 : CHECK(v->IsNumber());
20287 10 : CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
20288 : }
20289 5 : isolate->Dispose();
20290 5 : }
20291 :
20292 20 : class InitDefaultIsolateThread : public v8::base::Thread {
20293 : public:
20294 : enum TestCase {
20295 : SetFatalHandler,
20296 : SetCounterFunction,
20297 : SetCreateHistogramFunction,
20298 : SetAddHistogramSampleFunction
20299 : };
20300 :
20301 : explicit InitDefaultIsolateThread(TestCase testCase)
20302 : : Thread(Options("InitDefaultIsolateThread")),
20303 : testCase_(testCase),
20304 20 : result_(false) {}
20305 :
20306 20 : void Run() override {
20307 : v8::Isolate::CreateParams create_params;
20308 20 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20309 20 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20310 20 : isolate->Enter();
20311 20 : switch (testCase_) {
20312 : case SetFatalHandler:
20313 5 : isolate->SetFatalErrorHandler(nullptr);
20314 5 : break;
20315 :
20316 : case SetCounterFunction:
20317 5 : CcTest::isolate()->SetCounterFunction(nullptr);
20318 5 : break;
20319 :
20320 : case SetCreateHistogramFunction:
20321 5 : CcTest::isolate()->SetCreateHistogramFunction(nullptr);
20322 5 : break;
20323 :
20324 : case SetAddHistogramSampleFunction:
20325 5 : CcTest::isolate()->SetAddHistogramSampleFunction(nullptr);
20326 5 : break;
20327 : }
20328 20 : isolate->Exit();
20329 20 : isolate->Dispose();
20330 20 : result_ = true;
20331 20 : }
20332 :
20333 : bool result() { return result_; }
20334 :
20335 : private:
20336 : TestCase testCase_;
20337 : bool result_;
20338 : };
20339 :
20340 :
20341 20 : static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20342 : InitDefaultIsolateThread thread(testCase);
20343 20 : thread.Start();
20344 20 : thread.Join();
20345 20 : CHECK(thread.result());
20346 20 : }
20347 :
20348 25880 : TEST(InitializeDefaultIsolateOnSecondaryThread_FatalHandler) {
20349 5 : InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20350 5 : }
20351 :
20352 25880 : TEST(InitializeDefaultIsolateOnSecondaryThread_CounterFunction) {
20353 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20354 5 : }
20355 :
20356 25880 : TEST(InitializeDefaultIsolateOnSecondaryThread_CreateHistogramFunction) {
20357 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20358 5 : }
20359 :
20360 25880 : TEST(InitializeDefaultIsolateOnSecondaryThread_AddHistogramSampleFunction) {
20361 5 : InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20362 5 : }
20363 :
20364 :
20365 25880 : TEST(StringCheckMultipleContexts) {
20366 : const char* code =
20367 : "(function() { return \"a\".charAt(0); })()";
20368 :
20369 : {
20370 : // Run the code twice in the first context to initialize the call IC.
20371 5 : LocalContext context1;
20372 10 : v8::HandleScope scope(context1->GetIsolate());
20373 5 : ExpectString(code, "a");
20374 10 : ExpectString(code, "a");
20375 : }
20376 :
20377 : {
20378 : // Change the String.prototype in the second context and check
20379 : // that the right function gets called.
20380 5 : LocalContext context2;
20381 10 : v8::HandleScope scope(context2->GetIsolate());
20382 : CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20383 10 : ExpectString(code, "not a");
20384 : }
20385 5 : }
20386 :
20387 :
20388 25880 : TEST(NumberCheckMultipleContexts) {
20389 : const char* code =
20390 : "(function() { return (42).toString(); })()";
20391 :
20392 : {
20393 : // Run the code twice in the first context to initialize the call IC.
20394 5 : LocalContext context1;
20395 10 : v8::HandleScope scope(context1->GetIsolate());
20396 5 : ExpectString(code, "42");
20397 10 : ExpectString(code, "42");
20398 : }
20399 :
20400 : {
20401 : // Change the Number.prototype in the second context and check
20402 : // that the right function gets called.
20403 5 : LocalContext context2;
20404 10 : v8::HandleScope scope(context2->GetIsolate());
20405 : CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20406 10 : ExpectString(code, "not 42");
20407 : }
20408 5 : }
20409 :
20410 :
20411 25880 : TEST(BooleanCheckMultipleContexts) {
20412 : const char* code =
20413 : "(function() { return true.toString(); })()";
20414 :
20415 : {
20416 : // Run the code twice in the first context to initialize the call IC.
20417 5 : LocalContext context1;
20418 10 : v8::HandleScope scope(context1->GetIsolate());
20419 5 : ExpectString(code, "true");
20420 10 : ExpectString(code, "true");
20421 : }
20422 :
20423 : {
20424 : // Change the Boolean.prototype in the second context and check
20425 : // that the right function gets called.
20426 5 : LocalContext context2;
20427 10 : v8::HandleScope scope(context2->GetIsolate());
20428 : CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20429 10 : ExpectString(code, "");
20430 : }
20431 5 : }
20432 :
20433 :
20434 25880 : TEST(DontDeleteCellLoadIC) {
20435 : const char* function_code =
20436 : "function readCell() { while (true) { return cell; } }";
20437 :
20438 : {
20439 : // Run the code twice in the first context to initialize the load
20440 : // IC for a don't delete cell.
20441 5 : LocalContext context1;
20442 10 : v8::HandleScope scope(context1->GetIsolate());
20443 : CompileRun("var cell = \"first\";");
20444 5 : ExpectBoolean("delete cell", false);
20445 : CompileRun(function_code);
20446 5 : ExpectString("readCell()", "first");
20447 10 : ExpectString("readCell()", "first");
20448 : }
20449 :
20450 : {
20451 : // Use a deletable cell in the second context.
20452 5 : LocalContext context2;
20453 10 : v8::HandleScope scope(context2->GetIsolate());
20454 : CompileRun("cell = \"second\";");
20455 : CompileRun(function_code);
20456 5 : ExpectString("readCell()", "second");
20457 5 : ExpectBoolean("delete cell", true);
20458 : ExpectString("(function() {"
20459 : " try {"
20460 : " return readCell();"
20461 : " } catch(e) {"
20462 : " return e.toString();"
20463 : " }"
20464 : "})()",
20465 5 : "ReferenceError: cell is not defined");
20466 : CompileRun("cell = \"new_second\";");
20467 5 : CcTest::CollectAllGarbage();
20468 5 : ExpectString("readCell()", "new_second");
20469 10 : ExpectString("readCell()", "new_second");
20470 : }
20471 5 : }
20472 :
20473 :
20474 10 : class Visitor42 : public v8::PersistentHandleVisitor {
20475 : public:
20476 : explicit Visitor42(v8::Persistent<v8::Object>* object)
20477 10 : : counter_(0), object_(object) { }
20478 :
20479 10 : void VisitPersistentHandle(Persistent<Value>* value,
20480 : uint16_t class_id) override {
20481 10 : if (class_id != 42) return;
20482 10 : CHECK_EQ(42, value->WrapperClassId());
20483 10 : v8::Isolate* isolate = CcTest::isolate();
20484 10 : v8::HandleScope handle_scope(isolate);
20485 : v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20486 10 : v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
20487 10 : CHECK(handle->IsObject());
20488 20 : CHECK(Local<Object>::Cast(handle)
20489 : ->Equals(isolate->GetCurrentContext(), object)
20490 : .FromJust());
20491 10 : ++counter_;
20492 : }
20493 :
20494 : int counter_;
20495 : v8::Persistent<v8::Object>* object_;
20496 : };
20497 :
20498 :
20499 25880 : TEST(PersistentHandleVisitor) {
20500 5 : LocalContext context;
20501 5 : v8::Isolate* isolate = context->GetIsolate();
20502 10 : v8::HandleScope scope(isolate);
20503 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20504 5 : CHECK_EQ(0, object.WrapperClassId());
20505 : object.SetWrapperClassId(42);
20506 5 : CHECK_EQ(42, object.WrapperClassId());
20507 :
20508 : Visitor42 visitor(&object);
20509 5 : isolate->VisitHandlesWithClassIds(&visitor);
20510 5 : CHECK_EQ(1, visitor.counter_);
20511 :
20512 5 : object.Reset();
20513 5 : }
20514 :
20515 :
20516 25880 : TEST(WrapperClassId) {
20517 5 : LocalContext context;
20518 5 : v8::Isolate* isolate = context->GetIsolate();
20519 10 : v8::HandleScope scope(isolate);
20520 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20521 5 : CHECK_EQ(0, object.WrapperClassId());
20522 : object.SetWrapperClassId(65535);
20523 5 : CHECK_EQ(65535, object.WrapperClassId());
20524 5 : object.Reset();
20525 5 : }
20526 :
20527 :
20528 25880 : TEST(PersistentHandleInNewSpaceVisitor) {
20529 5 : LocalContext context;
20530 5 : v8::Isolate* isolate = context->GetIsolate();
20531 10 : v8::HandleScope scope(isolate);
20532 5 : v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
20533 5 : CHECK_EQ(0, object1.WrapperClassId());
20534 : object1.SetWrapperClassId(42);
20535 5 : CHECK_EQ(42, object1.WrapperClassId());
20536 :
20537 5 : CcTest::CollectAllGarbage();
20538 5 : CcTest::CollectAllGarbage();
20539 :
20540 5 : v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
20541 5 : CHECK_EQ(0, object2.WrapperClassId());
20542 : object2.SetWrapperClassId(42);
20543 5 : CHECK_EQ(42, object2.WrapperClassId());
20544 :
20545 : Visitor42 visitor(&object2);
20546 : #if __clang__
20547 : #pragma clang diagnostic push
20548 : #pragma clang diagnostic ignored "-Wdeprecated"
20549 : #endif
20550 : // VisitHandlesForPartialDependence is marked deprecated. This test will be
20551 : // removed with the API method.
20552 5 : isolate->VisitHandlesForPartialDependence(&visitor);
20553 : #if __clang__
20554 : #pragma clang diagnostic pop
20555 : #endif
20556 :
20557 5 : CHECK_EQ(1, visitor.counter_);
20558 :
20559 : object1.Reset();
20560 5 : object2.Reset();
20561 5 : }
20562 :
20563 :
20564 25880 : TEST(RegExp) {
20565 5 : LocalContext context;
20566 10 : v8::HandleScope scope(context->GetIsolate());
20567 :
20568 : v8::Local<v8::RegExp> re =
20569 5 : v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
20570 5 : .ToLocalChecked();
20571 5 : CHECK(re->IsRegExp());
20572 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
20573 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20574 :
20575 : re = v8::RegExp::New(context.local(), v8_str("bar"),
20576 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20577 5 : v8::RegExp::kGlobal))
20578 5 : .ToLocalChecked();
20579 5 : CHECK(re->IsRegExp());
20580 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
20581 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20582 : static_cast<int>(re->GetFlags()));
20583 :
20584 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20585 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20586 5 : v8::RegExp::kMultiline))
20587 5 : .ToLocalChecked();
20588 5 : CHECK(re->IsRegExp());
20589 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20590 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20591 : static_cast<int>(re->GetFlags()));
20592 :
20593 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20594 : static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
20595 5 : v8::RegExp::kSticky))
20596 5 : .ToLocalChecked();
20597 5 : CHECK(re->IsRegExp());
20598 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20599 5 : CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
20600 : static_cast<int>(re->GetFlags()));
20601 :
20602 : re = CompileRun("/quux/").As<v8::RegExp>();
20603 5 : CHECK(re->IsRegExp());
20604 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20605 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20606 :
20607 : re = CompileRun("/quux/gm").As<v8::RegExp>();
20608 5 : CHECK(re->IsRegExp());
20609 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20610 5 : CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20611 : static_cast<int>(re->GetFlags()));
20612 :
20613 : // Override the RegExp constructor and check the API constructor
20614 : // still works.
20615 : CompileRun("RegExp = function() {}");
20616 :
20617 5 : re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
20618 5 : .ToLocalChecked();
20619 5 : CHECK(re->IsRegExp());
20620 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
20621 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20622 :
20623 : re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
20624 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20625 5 : v8::RegExp::kMultiline))
20626 5 : .ToLocalChecked();
20627 5 : CHECK(re->IsRegExp());
20628 20 : CHECK(
20629 : re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
20630 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20631 : static_cast<int>(re->GetFlags()));
20632 :
20633 25 : CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
20634 : ExpectTrue("re.test('FoobarbaZ')");
20635 :
20636 : // RegExps are objects on which you can set properties.
20637 : re->Set(context.local(), v8_str("property"),
20638 20 : v8::Integer::New(context->GetIsolate(), 32))
20639 10 : .FromJust();
20640 : v8::Local<v8::Value> value(CompileRun("re.property"));
20641 10 : CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
20642 :
20643 10 : v8::TryCatch try_catch(context->GetIsolate());
20644 10 : CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
20645 : .IsEmpty());
20646 5 : CHECK(try_catch.HasCaught());
20647 25 : CHECK(context->Global()
20648 : ->Set(context.local(), v8_str("ex"), try_catch.Exception())
20649 : .FromJust());
20650 5 : ExpectTrue("ex instanceof SyntaxError");
20651 5 : }
20652 :
20653 :
20654 25881 : THREADED_TEST(Equals) {
20655 6 : LocalContext localContext;
20656 12 : v8::HandleScope handleScope(localContext->GetIsolate());
20657 :
20658 6 : v8::Local<v8::Object> globalProxy = localContext->Global();
20659 6 : v8::Local<Value> global = globalProxy->GetPrototype();
20660 :
20661 6 : CHECK(global->StrictEquals(global));
20662 6 : CHECK(!global->StrictEquals(globalProxy));
20663 6 : CHECK(!globalProxy->StrictEquals(global));
20664 6 : CHECK(globalProxy->StrictEquals(globalProxy));
20665 :
20666 12 : CHECK(global->Equals(localContext.local(), global).FromJust());
20667 12 : CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
20668 12 : CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
20669 18 : CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
20670 6 : }
20671 :
20672 :
20673 5 : static void Getter(v8::Local<v8::Name> property,
20674 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20675 5 : info.GetReturnValue().Set(v8_str("42!"));
20676 5 : }
20677 :
20678 :
20679 5 : static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20680 5 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
20681 : result->Set(info.GetIsolate()->GetCurrentContext(), 0,
20682 15 : v8_str("universalAnswer"))
20683 10 : .FromJust();
20684 : info.GetReturnValue().Set(result);
20685 5 : }
20686 :
20687 :
20688 25880 : TEST(NamedEnumeratorAndForIn) {
20689 5 : LocalContext context;
20690 5 : v8::Isolate* isolate = context->GetIsolate();
20691 10 : v8::HandleScope handle_scope(isolate);
20692 5 : v8::Context::Scope context_scope(context.local());
20693 :
20694 5 : v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20695 : tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
20696 5 : Getter, nullptr, nullptr, nullptr, Enumerator));
20697 30 : CHECK(context->Global()
20698 : ->Set(context.local(), v8_str("o"),
20699 : tmpl->NewInstance(context.local()).ToLocalChecked())
20700 : .FromJust());
20701 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
20702 : CompileRun("var result = []; for (var k in o) result.push(k); result"));
20703 5 : CHECK_EQ(1u, result->Length());
20704 20 : CHECK(v8_str("universalAnswer")
20705 : ->Equals(context.local(),
20706 : result->Get(context.local(), 0).ToLocalChecked())
20707 5 : .FromJust());
20708 5 : }
20709 :
20710 :
20711 25880 : TEST(DefinePropertyPostDetach) {
20712 5 : LocalContext context;
20713 10 : v8::HandleScope scope(context->GetIsolate());
20714 5 : v8::Local<v8::Object> proxy = context->Global();
20715 : v8::Local<v8::Function> define_property =
20716 : CompileRun(
20717 : "(function() {"
20718 : " Object.defineProperty("
20719 : " this,"
20720 : " 1,"
20721 : " { configurable: true, enumerable: true, value: 3 });"
20722 : "})")
20723 : .As<Function>();
20724 5 : context->DetachGlobal();
20725 15 : CHECK(define_property->Call(context.local(), proxy, 0, nullptr).IsEmpty());
20726 5 : }
20727 :
20728 :
20729 36 : static void InstallContextId(v8::Local<Context> context, int id) {
20730 : Context::Scope scope(context);
20731 144 : CHECK(CompileRun("Object.prototype")
20732 : .As<Object>()
20733 : ->Set(context, v8_str("context_id"),
20734 : v8::Integer::New(context->GetIsolate(), id))
20735 : .FromJust());
20736 36 : }
20737 :
20738 :
20739 126 : static void CheckContextId(v8::Local<Object> object, int expected) {
20740 126 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20741 504 : CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
20742 : .ToLocalChecked()
20743 : ->Int32Value(context)
20744 : .FromJust());
20745 126 : }
20746 :
20747 :
20748 25881 : THREADED_TEST(CreationContext) {
20749 6 : v8::Isolate* isolate = CcTest::isolate();
20750 6 : HandleScope handle_scope(isolate);
20751 6 : Local<Context> context1 = Context::New(isolate);
20752 6 : InstallContextId(context1, 1);
20753 6 : Local<Context> context2 = Context::New(isolate);
20754 6 : InstallContextId(context2, 2);
20755 6 : Local<Context> context3 = Context::New(isolate);
20756 6 : InstallContextId(context3, 3);
20757 :
20758 6 : Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20759 :
20760 : Local<Object> object1;
20761 : Local<Function> func1;
20762 : {
20763 : Context::Scope scope(context1);
20764 6 : object1 = Object::New(isolate);
20765 6 : func1 = tmpl->GetFunction(context1).ToLocalChecked();
20766 : }
20767 :
20768 : Local<Object> object2;
20769 : Local<Function> func2;
20770 : {
20771 : Context::Scope scope(context2);
20772 6 : object2 = Object::New(isolate);
20773 6 : func2 = tmpl->GetFunction(context2).ToLocalChecked();
20774 : }
20775 :
20776 : Local<Object> instance1;
20777 : Local<Object> instance2;
20778 :
20779 : {
20780 : Context::Scope scope(context3);
20781 : instance1 = func1->NewInstance(context3).ToLocalChecked();
20782 : instance2 = func2->NewInstance(context3).ToLocalChecked();
20783 : }
20784 :
20785 : {
20786 6 : Local<Context> other_context = Context::New(isolate);
20787 : Context::Scope scope(other_context);
20788 12 : CHECK(object1->CreationContext() == context1);
20789 6 : CheckContextId(object1, 1);
20790 12 : CHECK(func1->CreationContext() == context1);
20791 6 : CheckContextId(func1, 1);
20792 12 : CHECK(instance1->CreationContext() == context1);
20793 6 : CheckContextId(instance1, 1);
20794 12 : CHECK(object2->CreationContext() == context2);
20795 6 : CheckContextId(object2, 2);
20796 12 : CHECK(func2->CreationContext() == context2);
20797 6 : CheckContextId(func2, 2);
20798 12 : CHECK(instance2->CreationContext() == context2);
20799 6 : CheckContextId(instance2, 2);
20800 : }
20801 :
20802 : {
20803 : Context::Scope scope(context1);
20804 12 : CHECK(object1->CreationContext() == context1);
20805 6 : CheckContextId(object1, 1);
20806 12 : CHECK(func1->CreationContext() == context1);
20807 6 : CheckContextId(func1, 1);
20808 12 : CHECK(instance1->CreationContext() == context1);
20809 6 : CheckContextId(instance1, 1);
20810 12 : CHECK(object2->CreationContext() == context2);
20811 6 : CheckContextId(object2, 2);
20812 12 : CHECK(func2->CreationContext() == context2);
20813 6 : CheckContextId(func2, 2);
20814 12 : CHECK(instance2->CreationContext() == context2);
20815 6 : CheckContextId(instance2, 2);
20816 : }
20817 :
20818 : {
20819 : Context::Scope scope(context2);
20820 12 : CHECK(object1->CreationContext() == context1);
20821 6 : CheckContextId(object1, 1);
20822 12 : CHECK(func1->CreationContext() == context1);
20823 6 : CheckContextId(func1, 1);
20824 12 : CHECK(instance1->CreationContext() == context1);
20825 6 : CheckContextId(instance1, 1);
20826 12 : CHECK(object2->CreationContext() == context2);
20827 6 : CheckContextId(object2, 2);
20828 12 : CHECK(func2->CreationContext() == context2);
20829 6 : CheckContextId(func2, 2);
20830 12 : CHECK(instance2->CreationContext() == context2);
20831 6 : CheckContextId(instance2, 2);
20832 6 : }
20833 6 : }
20834 :
20835 :
20836 25881 : THREADED_TEST(CreationContextOfJsFunction) {
20837 6 : HandleScope handle_scope(CcTest::isolate());
20838 6 : Local<Context> context = Context::New(CcTest::isolate());
20839 6 : InstallContextId(context, 1);
20840 :
20841 : Local<Object> function;
20842 : {
20843 : Context::Scope scope(context);
20844 : function = CompileRun("function foo() {}; foo").As<Object>();
20845 : }
20846 :
20847 6 : Local<Context> other_context = Context::New(CcTest::isolate());
20848 : Context::Scope scope(other_context);
20849 12 : CHECK(function->CreationContext() == context);
20850 12 : CheckContextId(function, 1);
20851 6 : }
20852 :
20853 :
20854 25881 : THREADED_TEST(CreationContextOfJsBoundFunction) {
20855 6 : HandleScope handle_scope(CcTest::isolate());
20856 6 : Local<Context> context1 = Context::New(CcTest::isolate());
20857 6 : InstallContextId(context1, 1);
20858 6 : Local<Context> context2 = Context::New(CcTest::isolate());
20859 6 : InstallContextId(context2, 2);
20860 :
20861 : Local<Function> target_function;
20862 : {
20863 : Context::Scope scope(context1);
20864 : target_function = CompileRun("function foo() {}; foo").As<Function>();
20865 : }
20866 :
20867 : Local<Function> bound_function1, bound_function2;
20868 : {
20869 : Context::Scope scope(context2);
20870 24 : CHECK(context2->Global()
20871 : ->Set(context2, v8_str("foo"), target_function)
20872 : .FromJust());
20873 : bound_function1 = CompileRun("foo.bind(1)").As<Function>();
20874 : bound_function2 =
20875 : CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
20876 : }
20877 :
20878 6 : Local<Context> other_context = Context::New(CcTest::isolate());
20879 : Context::Scope scope(other_context);
20880 12 : CHECK(bound_function1->CreationContext() == context1);
20881 6 : CheckContextId(bound_function1, 1);
20882 12 : CHECK(bound_function2->CreationContext() == context1);
20883 12 : CheckContextId(bound_function2, 1);
20884 6 : }
20885 :
20886 :
20887 20 : void HasOwnPropertyIndexedPropertyGetter(
20888 : uint32_t index,
20889 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20890 20 : if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20891 20 : }
20892 :
20893 :
20894 10 : void HasOwnPropertyNamedPropertyGetter(
20895 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20896 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20897 20 : .FromJust()) {
20898 5 : info.GetReturnValue().Set(v8_str("yes"));
20899 : }
20900 10 : }
20901 :
20902 :
20903 50 : void HasOwnPropertyIndexedPropertyQuery(
20904 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20905 50 : if (index == 42) info.GetReturnValue().Set(1);
20906 50 : }
20907 :
20908 :
20909 10 : void HasOwnPropertyNamedPropertyQuery(
20910 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20911 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20912 20 : .FromJust()) {
20913 : info.GetReturnValue().Set(1);
20914 : }
20915 10 : }
20916 :
20917 :
20918 10 : void HasOwnPropertyNamedPropertyQuery2(
20919 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20920 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
20921 20 : .FromJust()) {
20922 : info.GetReturnValue().Set(1);
20923 : }
20924 10 : }
20925 :
20926 0 : void HasOwnPropertyAccessorGetter(
20927 : Local<String> property,
20928 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20929 0 : info.GetReturnValue().Set(v8_str("yes"));
20930 0 : }
20931 :
20932 5 : void HasOwnPropertyAccessorNameGetter(
20933 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20934 5 : info.GetReturnValue().Set(v8_str("yes"));
20935 5 : }
20936 :
20937 25880 : TEST(HasOwnProperty) {
20938 5 : LocalContext env;
20939 5 : v8::Isolate* isolate = env->GetIsolate();
20940 10 : v8::HandleScope scope(isolate);
20941 : { // Check normal properties and defined getters.
20942 : Local<Value> value = CompileRun(
20943 : "function Foo() {"
20944 : " this.foo = 11;"
20945 : " this.__defineGetter__('baz', function() { return 1; });"
20946 : "};"
20947 : "function Bar() { "
20948 : " this.bar = 13;"
20949 : " this.__defineGetter__('bla', function() { return 2; });"
20950 : "};"
20951 : "Bar.prototype = new Foo();"
20952 : "new Bar();");
20953 5 : CHECK(value->IsObject());
20954 5 : Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
20955 15 : CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
20956 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20957 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20958 15 : CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
20959 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
20960 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
20961 : }
20962 : { // Check named getter interceptors.
20963 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20964 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20965 5 : HasOwnPropertyNamedPropertyGetter));
20966 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20967 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20968 10 : CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
20969 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20970 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20971 : }
20972 : { // Check indexed getter interceptors.
20973 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20974 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20975 5 : HasOwnPropertyIndexedPropertyGetter));
20976 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20977 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20978 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20979 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
20980 10 : CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
20981 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20982 : }
20983 : { // Check named query interceptors.
20984 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20985 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20986 5 : nullptr, nullptr, HasOwnPropertyNamedPropertyQuery));
20987 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20988 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20989 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20990 : }
20991 : { // Check indexed query interceptors.
20992 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20993 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20994 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
20995 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20996 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20997 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20998 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
20999 10 : CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
21000 : }
21001 : { // Check callbacks.
21002 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21003 5 : templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21004 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21005 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21006 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21007 : }
21008 : { // Check that query wins on disagreement.
21009 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21010 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21011 : HasOwnPropertyNamedPropertyGetter, nullptr,
21012 5 : HasOwnPropertyNamedPropertyQuery2));
21013 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21014 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21015 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21016 : }
21017 : { // Check that non-internalized keys are handled correctly.
21018 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21019 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21020 5 : HasOwnPropertyAccessorNameGetter));
21021 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21022 25 : env->Global()->Set(env.local(), v8_str("obj"), instance).FromJust();
21023 : const char* src =
21024 : "var dyn_string = 'this string ';"
21025 : "dyn_string += 'does not exist elsewhere';"
21026 : "({}).hasOwnProperty.call(obj, dyn_string)";
21027 5 : CHECK(CompileRun(src)->BooleanValue(isolate));
21028 5 : }
21029 5 : }
21030 :
21031 :
21032 25880 : TEST(IndexedInterceptorWithStringProto) {
21033 5 : v8::Isolate* isolate = CcTest::isolate();
21034 5 : v8::HandleScope scope(isolate);
21035 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21036 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21037 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
21038 10 : LocalContext context;
21039 30 : CHECK(context->Global()
21040 : ->Set(context.local(), v8_str("obj"),
21041 : templ->NewInstance(context.local()).ToLocalChecked())
21042 : .FromJust());
21043 : CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21044 : // These should be intercepted.
21045 5 : CHECK(CompileRun("42 in obj")->BooleanValue(isolate));
21046 5 : CHECK(CompileRun("'42' in obj")->BooleanValue(isolate));
21047 : // These should fall through to the String prototype.
21048 5 : CHECK(CompileRun("0 in obj")->BooleanValue(isolate));
21049 5 : CHECK(CompileRun("'0' in obj")->BooleanValue(isolate));
21050 : // And these should both fail.
21051 5 : CHECK(!CompileRun("32 in obj")->BooleanValue(isolate));
21052 10 : CHECK(!CompileRun("'32' in obj")->BooleanValue(isolate));
21053 5 : }
21054 :
21055 :
21056 18 : void CheckCodeGenerationAllowed() {
21057 18 : Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
21058 : Local<Value> result = CompileRun("eval('42')");
21059 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21060 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21061 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21062 : result = CompileRun("var f = new Function('return 42'); f()");
21063 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21064 18 : }
21065 :
21066 :
21067 12 : void CheckCodeGenerationDisallowed() {
21068 12 : TryCatch try_catch(CcTest::isolate());
21069 :
21070 : Local<Value> result = CompileRun("eval('42')");
21071 12 : CHECK(result.IsEmpty());
21072 12 : CHECK(try_catch.HasCaught());
21073 12 : try_catch.Reset();
21074 :
21075 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21076 12 : CHECK(result.IsEmpty());
21077 12 : CHECK(try_catch.HasCaught());
21078 12 : try_catch.Reset();
21079 :
21080 : result = CompileRun("var f = new Function('return 42'); f()");
21081 12 : CHECK(result.IsEmpty());
21082 12 : CHECK(try_catch.HasCaught());
21083 12 : }
21084 :
21085 : char first_fourty_bytes[41];
21086 :
21087 23 : bool CodeGenerationAllowed(Local<Context> context, Local<String> source) {
21088 23 : String::Utf8Value str(CcTest::isolate(), source);
21089 : size_t len = std::min(sizeof(first_fourty_bytes) - 1,
21090 46 : static_cast<size_t>(str.length()));
21091 23 : strncpy(first_fourty_bytes, *str, len);
21092 23 : first_fourty_bytes[len] = 0;
21093 23 : ApiTestFuzzer::Fuzz();
21094 23 : return true;
21095 : }
21096 :
21097 23 : bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) {
21098 23 : ApiTestFuzzer::Fuzz();
21099 23 : return false;
21100 : }
21101 :
21102 :
21103 25881 : THREADED_TEST(AllowCodeGenFromStrings) {
21104 6 : LocalContext context;
21105 12 : v8::HandleScope scope(context->GetIsolate());
21106 :
21107 : // eval and the Function constructor allowed by default.
21108 6 : CHECK(context->IsCodeGenerationFromStringsAllowed());
21109 6 : CheckCodeGenerationAllowed();
21110 :
21111 : // Disallow eval and the Function constructor.
21112 6 : context->AllowCodeGenerationFromStrings(false);
21113 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21114 6 : CheckCodeGenerationDisallowed();
21115 :
21116 : // Allow again.
21117 6 : context->AllowCodeGenerationFromStrings(true);
21118 6 : CheckCodeGenerationAllowed();
21119 :
21120 : // Disallow but setting a global callback that will allow the calls.
21121 6 : context->AllowCodeGenerationFromStrings(false);
21122 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21123 6 : &CodeGenerationAllowed);
21124 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21125 6 : CheckCodeGenerationAllowed();
21126 :
21127 : // Set a callback that disallows the code generation.
21128 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21129 6 : &CodeGenerationDisallowed);
21130 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21131 12 : CheckCodeGenerationDisallowed();
21132 6 : }
21133 :
21134 :
21135 25880 : TEST(SetErrorMessageForCodeGenFromStrings) {
21136 5 : LocalContext context;
21137 10 : v8::HandleScope scope(context->GetIsolate());
21138 10 : TryCatch try_catch(context->GetIsolate());
21139 :
21140 5 : Local<String> message = v8_str("Message");
21141 5 : Local<String> expected_message = v8_str("Uncaught EvalError: Message");
21142 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21143 5 : &CodeGenerationDisallowed);
21144 5 : context->AllowCodeGenerationFromStrings(false);
21145 5 : context->SetErrorMessageForCodeGenerationFromStrings(message);
21146 : Local<Value> result = CompileRun("eval('42')");
21147 5 : CHECK(result.IsEmpty());
21148 5 : CHECK(try_catch.HasCaught());
21149 10 : Local<String> actual_message = try_catch.Message()->Get();
21150 20 : CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
21151 5 : }
21152 :
21153 25880 : TEST(CaptureSourceForCodeGenFromStrings) {
21154 5 : LocalContext context;
21155 10 : v8::HandleScope scope(context->GetIsolate());
21156 10 : TryCatch try_catch(context->GetIsolate());
21157 :
21158 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21159 5 : &CodeGenerationAllowed);
21160 5 : context->AllowCodeGenerationFromStrings(false);
21161 : CompileRun("eval('42')");
21162 10 : CHECK(!strcmp(first_fourty_bytes, "42"));
21163 5 : }
21164 :
21165 6 : static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21166 6 : }
21167 :
21168 :
21169 25881 : THREADED_TEST(CallAPIFunctionOnNonObject) {
21170 6 : LocalContext context;
21171 6 : v8::Isolate* isolate = context->GetIsolate();
21172 12 : v8::HandleScope scope(isolate);
21173 : Local<FunctionTemplate> templ =
21174 6 : v8::FunctionTemplate::New(isolate, NonObjectThis);
21175 : Local<Function> function =
21176 12 : templ->GetFunction(context.local()).ToLocalChecked();
21177 30 : CHECK(context->Global()
21178 : ->Set(context.local(), v8_str("f"), function)
21179 : .FromJust());
21180 12 : TryCatch try_catch(isolate);
21181 6 : CompileRun("f.call(2)");
21182 6 : }
21183 :
21184 :
21185 : // Regression test for issue 1470.
21186 25881 : THREADED_TEST(ReadOnlyIndexedProperties) {
21187 6 : v8::Isolate* isolate = CcTest::isolate();
21188 6 : v8::HandleScope scope(isolate);
21189 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21190 :
21191 12 : LocalContext context;
21192 12 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
21193 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
21194 : obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
21195 24 : v8::ReadOnly)
21196 12 : .FromJust();
21197 24 : obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
21198 30 : CHECK(v8_str("DONT_CHANGE")
21199 : ->Equals(context.local(),
21200 : obj->Get(context.local(), v8_str("1")).ToLocalChecked())
21201 : .FromJust());
21202 : obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
21203 24 : v8::ReadOnly)
21204 12 : .FromJust();
21205 18 : obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
21206 24 : CHECK(v8_str("DONT_CHANGE")
21207 : ->Equals(context.local(),
21208 : obj->Get(context.local(), v8_num(2)).ToLocalChecked())
21209 : .FromJust());
21210 :
21211 : // Test non-smi case.
21212 : obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
21213 24 : v8_str("DONT_CHANGE"), v8::ReadOnly)
21214 12 : .FromJust();
21215 24 : obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
21216 30 : CHECK(v8_str("DONT_CHANGE")
21217 : ->Equals(context.local(),
21218 : obj->Get(context.local(), v8_str("2000000000"))
21219 : .ToLocalChecked())
21220 6 : .FromJust());
21221 6 : }
21222 :
21223 12 : static int CountLiveMapsInMapCache(i::Context context) {
21224 24 : i::WeakFixedArray map_cache = i::WeakFixedArray::cast(context->map_cache());
21225 : int length = map_cache->length();
21226 : int count = 0;
21227 1548 : for (int i = 0; i < length; i++) {
21228 3072 : if (map_cache->Get(i)->IsWeak()) count++;
21229 : }
21230 12 : return count;
21231 : }
21232 :
21233 :
21234 25881 : THREADED_TEST(Regress1516) {
21235 6 : LocalContext context;
21236 12 : v8::HandleScope scope(context->GetIsolate());
21237 :
21238 : // Object with 20 properties is not a common case, so it should be removed
21239 : // from the cache after GC.
21240 6 : { v8::HandleScope temp_scope(context->GetIsolate());
21241 : CompileRun(
21242 : "({"
21243 : "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21244 : "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21245 : "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21246 : "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21247 6 : "})");
21248 : }
21249 :
21250 6 : int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21251 6 : CHECK_LE(1, elements);
21252 :
21253 : // We have to abort incremental marking here to abandon black pages.
21254 6 : CcTest::PreciseCollectAllGarbage();
21255 :
21256 12 : CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21257 6 : }
21258 :
21259 :
21260 84 : static void TestReceiver(Local<Value> expected_result,
21261 : Local<Value> expected_receiver,
21262 : const char* code) {
21263 : Local<Value> result = CompileRun(code);
21264 84 : Local<Context> context = CcTest::isolate()->GetCurrentContext();
21265 84 : CHECK(result->IsObject());
21266 252 : CHECK(expected_receiver
21267 : ->Equals(context,
21268 : result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
21269 : .FromJust());
21270 252 : CHECK(expected_result
21271 : ->Equals(context,
21272 : result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
21273 : .FromJust());
21274 84 : }
21275 :
21276 :
21277 25881 : THREADED_TEST(ForeignFunctionReceiver) {
21278 6 : v8::Isolate* isolate = CcTest::isolate();
21279 6 : HandleScope scope(isolate);
21280 :
21281 : // Create two contexts with different "id" properties ('i' and 'o').
21282 : // Call a function both from its own context and from a the foreign
21283 : // context, and see what "this" is bound to (returning both "this"
21284 : // and "this.id" for comparison).
21285 :
21286 6 : Local<Context> foreign_context = v8::Context::New(isolate);
21287 6 : foreign_context->Enter();
21288 : Local<Value> foreign_function =
21289 : CompileRun("function func() { return { 0: this.id, "
21290 : " 1: this, "
21291 : " toString: function() { "
21292 : " return this[0];"
21293 : " }"
21294 : " };"
21295 : "}"
21296 : "var id = 'i';"
21297 : "func;");
21298 6 : CHECK(foreign_function->IsFunction());
21299 6 : foreign_context->Exit();
21300 :
21301 12 : LocalContext context;
21302 :
21303 6 : Local<String> password = v8_str("Password");
21304 : // Don't get hit by security checks when accessing foreign_context's
21305 : // global receiver (aka. global proxy).
21306 6 : context->SetSecurityToken(password);
21307 6 : foreign_context->SetSecurityToken(password);
21308 :
21309 6 : Local<String> i = v8_str("i");
21310 6 : Local<String> o = v8_str("o");
21311 6 : Local<String> id = v8_str("id");
21312 :
21313 : CompileRun("function ownfunc() { return { 0: this.id, "
21314 : " 1: this, "
21315 : " toString: function() { "
21316 : " return this[0];"
21317 : " }"
21318 : " };"
21319 : "}"
21320 : "var id = 'o';"
21321 : "ownfunc");
21322 30 : CHECK(context->Global()
21323 : ->Set(context.local(), v8_str("func"), foreign_function)
21324 : .FromJust());
21325 :
21326 : // Sanity check the contexts.
21327 24 : CHECK(
21328 : i->Equals(
21329 : context.local(),
21330 : foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
21331 : .FromJust());
21332 30 : CHECK(o->Equals(context.local(),
21333 : context->Global()->Get(context.local(), id).ToLocalChecked())
21334 : .FromJust());
21335 :
21336 : // Checking local function's receiver.
21337 : // Calling function using its call/apply methods.
21338 12 : TestReceiver(o, context->Global(), "ownfunc.call()");
21339 12 : TestReceiver(o, context->Global(), "ownfunc.apply()");
21340 : // Making calls through built-in functions.
21341 12 : TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21342 12 : CHECK(
21343 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
21344 : .FromJust());
21345 12 : CHECK(
21346 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
21347 : .FromJust());
21348 12 : CHECK(
21349 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
21350 : .FromJust());
21351 : // Calling with environment record as base.
21352 12 : TestReceiver(o, context->Global(), "ownfunc()");
21353 : // Calling with no base.
21354 12 : TestReceiver(o, context->Global(), "(1,ownfunc)()");
21355 :
21356 : // Checking foreign function return value.
21357 : // Calling function using its call/apply methods.
21358 12 : TestReceiver(i, foreign_context->Global(), "func.call()");
21359 12 : TestReceiver(i, foreign_context->Global(), "func.apply()");
21360 : // Calling function using another context's call/apply methods.
21361 : TestReceiver(i, foreign_context->Global(),
21362 12 : "Function.prototype.call.call(func)");
21363 : TestReceiver(i, foreign_context->Global(),
21364 12 : "Function.prototype.call.apply(func)");
21365 : TestReceiver(i, foreign_context->Global(),
21366 12 : "Function.prototype.apply.call(func)");
21367 : TestReceiver(i, foreign_context->Global(),
21368 12 : "Function.prototype.apply.apply(func)");
21369 : // Making calls through built-in functions.
21370 12 : TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21371 : // ToString(func()) is func()[0], i.e., the returned this.id.
21372 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
21373 : .FromJust());
21374 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
21375 : .FromJust());
21376 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
21377 : .FromJust());
21378 :
21379 : // Calling with environment record as base.
21380 12 : TestReceiver(i, foreign_context->Global(), "func()");
21381 : // Calling with no base.
21382 18 : TestReceiver(i, foreign_context->Global(), "(1,func)()");
21383 6 : }
21384 :
21385 :
21386 : uint8_t callback_fired = 0;
21387 : uint8_t before_call_entered_callback_count1 = 0;
21388 : uint8_t before_call_entered_callback_count2 = 0;
21389 :
21390 :
21391 5 : void CallCompletedCallback1(v8::Isolate*) {
21392 5 : v8::base::OS::Print("Firing callback 1.\n");
21393 5 : callback_fired ^= 1; // Toggle first bit.
21394 5 : }
21395 :
21396 :
21397 15 : void CallCompletedCallback2(v8::Isolate*) {
21398 15 : v8::base::OS::Print("Firing callback 2.\n");
21399 15 : callback_fired ^= 2; // Toggle second bit.
21400 15 : }
21401 :
21402 :
21403 20 : void BeforeCallEnteredCallback1(v8::Isolate*) {
21404 20 : v8::base::OS::Print("Firing before call entered callback 1.\n");
21405 20 : before_call_entered_callback_count1++;
21406 20 : }
21407 :
21408 :
21409 60 : void BeforeCallEnteredCallback2(v8::Isolate*) {
21410 60 : v8::base::OS::Print("Firing before call entered callback 2.\n");
21411 60 : before_call_entered_callback_count2++;
21412 60 : }
21413 :
21414 :
21415 60 : void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21416 : int32_t level =
21417 180 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
21418 60 : if (level < 3) {
21419 45 : level++;
21420 45 : v8::base::OS::Print("Entering recursion level %d.\n", level);
21421 : char script[64];
21422 : i::Vector<char> script_vector(script, sizeof(script));
21423 45 : i::SNPrintF(script_vector, "recursion(%d)", level);
21424 : CompileRun(script_vector.start());
21425 45 : v8::base::OS::Print("Leaving recursion level %d.\n", level);
21426 90 : CHECK_EQ(0, callback_fired);
21427 : } else {
21428 15 : v8::base::OS::Print("Recursion ends.\n");
21429 30 : CHECK_EQ(0, callback_fired);
21430 : }
21431 60 : }
21432 :
21433 :
21434 25880 : TEST(CallCompletedCallback) {
21435 5 : LocalContext env;
21436 10 : v8::HandleScope scope(env->GetIsolate());
21437 : v8::Local<v8::FunctionTemplate> recursive_runtime =
21438 5 : v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21439 : env->Global()
21440 : ->Set(env.local(), v8_str("recursion"),
21441 30 : recursive_runtime->GetFunction(env.local()).ToLocalChecked())
21442 10 : .FromJust();
21443 : // Adding the same callback a second time has no effect.
21444 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21445 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21446 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21447 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21448 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
21449 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21450 5 : v8::base::OS::Print("--- Script (1) ---\n");
21451 5 : callback_fired = 0;
21452 5 : before_call_entered_callback_count1 = 0;
21453 5 : before_call_entered_callback_count2 = 0;
21454 : Local<Script> script =
21455 5 : v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
21456 5 : script->Run(env.local()).ToLocalChecked();
21457 10 : CHECK_EQ(3, callback_fired);
21458 10 : CHECK_EQ(4, before_call_entered_callback_count1);
21459 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21460 :
21461 5 : v8::base::OS::Print("\n--- Script (2) ---\n");
21462 5 : callback_fired = 0;
21463 5 : before_call_entered_callback_count1 = 0;
21464 5 : before_call_entered_callback_count2 = 0;
21465 5 : env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21466 : env->GetIsolate()->RemoveBeforeCallEnteredCallback(
21467 5 : BeforeCallEnteredCallback1);
21468 5 : script->Run(env.local()).ToLocalChecked();
21469 10 : CHECK_EQ(2, callback_fired);
21470 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21471 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21472 :
21473 5 : v8::base::OS::Print("\n--- Function ---\n");
21474 5 : callback_fired = 0;
21475 5 : before_call_entered_callback_count1 = 0;
21476 5 : before_call_entered_callback_count2 = 0;
21477 : Local<Function> recursive_function = Local<Function>::Cast(
21478 25 : env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
21479 5 : v8::Local<Value> args[] = {v8_num(0)};
21480 15 : recursive_function->Call(env.local(), env->Global(), 1, args)
21481 5 : .ToLocalChecked();
21482 10 : CHECK_EQ(2, callback_fired);
21483 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21484 15 : CHECK_EQ(4, before_call_entered_callback_count2);
21485 5 : }
21486 :
21487 :
21488 5 : void CallCompletedCallbackNoException(v8::Isolate*) {
21489 5 : v8::HandleScope scope(CcTest::isolate());
21490 5 : CompileRun("1+1;");
21491 5 : }
21492 :
21493 :
21494 5 : void CallCompletedCallbackException(v8::Isolate*) {
21495 5 : v8::HandleScope scope(CcTest::isolate());
21496 5 : CompileRun("throw 'second exception';");
21497 5 : }
21498 :
21499 :
21500 25880 : TEST(CallCompletedCallbackOneException) {
21501 5 : LocalContext env;
21502 10 : v8::HandleScope scope(env->GetIsolate());
21503 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21504 5 : CompileRun("throw 'exception';");
21505 5 : }
21506 :
21507 :
21508 25880 : TEST(CallCompletedCallbackTwoExceptions) {
21509 5 : LocalContext env;
21510 10 : v8::HandleScope scope(env->GetIsolate());
21511 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21512 5 : CompileRun("throw 'first exception';");
21513 5 : }
21514 :
21515 :
21516 135 : static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21517 45 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21518 45 : v8::HandleScope scope(info.GetIsolate());
21519 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21520 90 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21521 45 : CompileRun("ext1Calls++;");
21522 45 : }
21523 :
21524 :
21525 150 : static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21526 50 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21527 50 : v8::HandleScope scope(info.GetIsolate());
21528 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21529 100 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21530 50 : CompileRun("ext2Calls++;");
21531 50 : }
21532 :
21533 : void* g_passed_to_three = nullptr;
21534 :
21535 10 : static void MicrotaskThree(void* data) {
21536 10 : g_passed_to_three = data;
21537 10 : }
21538 :
21539 :
21540 25880 : TEST(EnqueueMicrotask) {
21541 5 : LocalContext env;
21542 10 : v8::HandleScope scope(env->GetIsolate());
21543 5 : CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
21544 : CompileRun(
21545 : "var ext1Calls = 0;"
21546 : "var ext2Calls = 0;");
21547 : CompileRun("1+1;");
21548 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21549 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21550 :
21551 : env->GetIsolate()->EnqueueMicrotask(
21552 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21553 : CompileRun("1+1;");
21554 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21555 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21556 :
21557 : env->GetIsolate()->EnqueueMicrotask(
21558 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21559 : env->GetIsolate()->EnqueueMicrotask(
21560 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21561 : CompileRun("1+1;");
21562 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21563 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21564 :
21565 : env->GetIsolate()->EnqueueMicrotask(
21566 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21567 : CompileRun("1+1;");
21568 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21569 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21570 :
21571 : CompileRun("1+1;");
21572 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21573 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21574 :
21575 5 : g_passed_to_three = nullptr;
21576 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21577 : CompileRun("1+1;");
21578 5 : CHECK(!g_passed_to_three);
21579 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21580 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21581 :
21582 : int dummy;
21583 : env->GetIsolate()->EnqueueMicrotask(
21584 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21585 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21586 : env->GetIsolate()->EnqueueMicrotask(
21587 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21588 : CompileRun("1+1;");
21589 5 : CHECK_EQ(&dummy, g_passed_to_three);
21590 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21591 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21592 10 : g_passed_to_three = nullptr;
21593 5 : }
21594 :
21595 :
21596 5 : static void MicrotaskExceptionOne(
21597 10 : const v8::FunctionCallbackInfo<Value>& info) {
21598 5 : v8::HandleScope scope(info.GetIsolate());
21599 : CompileRun("exception1Calls++;");
21600 : info.GetIsolate()->ThrowException(
21601 10 : v8::Exception::Error(v8_str("first")));
21602 5 : }
21603 :
21604 :
21605 5 : static void MicrotaskExceptionTwo(
21606 10 : const v8::FunctionCallbackInfo<Value>& info) {
21607 5 : v8::HandleScope scope(info.GetIsolate());
21608 : CompileRun("exception2Calls++;");
21609 : info.GetIsolate()->ThrowException(
21610 10 : v8::Exception::Error(v8_str("second")));
21611 5 : }
21612 :
21613 :
21614 25880 : TEST(RunMicrotasksIgnoresThrownExceptions) {
21615 5 : LocalContext env;
21616 5 : v8::Isolate* isolate = env->GetIsolate();
21617 10 : v8::HandleScope scope(isolate);
21618 : CompileRun(
21619 : "var exception1Calls = 0;"
21620 : "var exception2Calls = 0;");
21621 : isolate->EnqueueMicrotask(
21622 10 : Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
21623 : isolate->EnqueueMicrotask(
21624 10 : Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
21625 10 : TryCatch try_catch(isolate);
21626 : CompileRun("1+1;");
21627 5 : CHECK(!try_catch.HasCaught());
21628 15 : CHECK_EQ(1,
21629 : CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
21630 15 : CHECK_EQ(1,
21631 5 : CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
21632 5 : }
21633 :
21634 5 : static void ThrowExceptionMicrotask(void* data) {
21635 10 : CcTest::isolate()->ThrowException(v8_str("exception"));
21636 5 : }
21637 :
21638 : int microtask_callback_count = 0;
21639 :
21640 5 : static void IncrementCounterMicrotask(void* data) {
21641 5 : microtask_callback_count++;
21642 5 : }
21643 :
21644 25880 : TEST(RunMicrotasksIgnoresThrownExceptionsFromApi) {
21645 5 : LocalContext env;
21646 5 : v8::Isolate* isolate = CcTest::isolate();
21647 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21648 10 : v8::HandleScope scope(isolate);
21649 10 : v8::TryCatch try_catch(isolate);
21650 : {
21651 5 : CHECK(!isolate->IsExecutionTerminating());
21652 5 : isolate->EnqueueMicrotask(ThrowExceptionMicrotask);
21653 5 : isolate->EnqueueMicrotask(IncrementCounterMicrotask);
21654 5 : isolate->RunMicrotasks();
21655 5 : CHECK_EQ(1, microtask_callback_count);
21656 5 : CHECK(!try_catch.HasCaught());
21657 5 : }
21658 5 : }
21659 :
21660 : uint8_t microtasks_completed_callback_count = 0;
21661 :
21662 :
21663 25 : static void MicrotasksCompletedCallback(v8::Isolate* isolate) {
21664 25 : ++microtasks_completed_callback_count;
21665 25 : }
21666 :
21667 :
21668 25880 : TEST(SetAutorunMicrotasks) {
21669 5 : LocalContext env;
21670 10 : v8::HandleScope scope(env->GetIsolate());
21671 : env->GetIsolate()->AddMicrotasksCompletedCallback(
21672 5 : &MicrotasksCompletedCallback);
21673 : CompileRun(
21674 : "var ext1Calls = 0;"
21675 : "var ext2Calls = 0;");
21676 : CompileRun("1+1;");
21677 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21678 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21679 5 : CHECK_EQ(0u, microtasks_completed_callback_count);
21680 :
21681 : env->GetIsolate()->EnqueueMicrotask(
21682 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21683 : CompileRun("1+1;");
21684 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21685 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21686 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
21687 :
21688 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21689 : env->GetIsolate()->EnqueueMicrotask(
21690 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21691 : env->GetIsolate()->EnqueueMicrotask(
21692 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21693 : CompileRun("1+1;");
21694 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21695 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21696 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
21697 :
21698 5 : env->GetIsolate()->RunMicrotasks();
21699 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21700 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21701 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
21702 :
21703 : env->GetIsolate()->EnqueueMicrotask(
21704 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21705 : CompileRun("1+1;");
21706 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21707 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21708 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
21709 :
21710 5 : env->GetIsolate()->RunMicrotasks();
21711 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21712 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21713 5 : CHECK_EQ(3u, microtasks_completed_callback_count);
21714 :
21715 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21716 : env->GetIsolate()->EnqueueMicrotask(
21717 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21718 : CompileRun("1+1;");
21719 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21720 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21721 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
21722 :
21723 : env->GetIsolate()->EnqueueMicrotask(
21724 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21725 : {
21726 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21727 : CompileRun("1+1;");
21728 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21729 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21730 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
21731 : }
21732 :
21733 : CompileRun("1+1;");
21734 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21735 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21736 5 : CHECK_EQ(5u, microtasks_completed_callback_count);
21737 :
21738 : env->GetIsolate()->RemoveMicrotasksCompletedCallback(
21739 5 : &MicrotasksCompletedCallback);
21740 : env->GetIsolate()->EnqueueMicrotask(
21741 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21742 : CompileRun("1+1;");
21743 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21744 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21745 10 : CHECK_EQ(5u, microtasks_completed_callback_count);
21746 5 : }
21747 :
21748 :
21749 25880 : TEST(RunMicrotasksWithoutEnteringContext) {
21750 5 : v8::Isolate* isolate = CcTest::isolate();
21751 5 : HandleScope handle_scope(isolate);
21752 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21753 5 : Local<Context> context = Context::New(isolate);
21754 : {
21755 : Context::Scope context_scope(context);
21756 : CompileRun("var ext1Calls = 0;");
21757 : isolate->EnqueueMicrotask(
21758 10 : Function::New(context, MicrotaskOne).ToLocalChecked());
21759 : }
21760 5 : isolate->RunMicrotasks();
21761 : {
21762 : Context::Scope context_scope(context);
21763 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
21764 : }
21765 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21766 5 : }
21767 :
21768 6 : static void Regress808911_MicrotaskCallback(void* data) {
21769 : // So here we expect "current context" to be context1 and
21770 : // "entered or microtask context" to be context2.
21771 : v8::Isolate* isolate = static_cast<v8::Isolate*>(data);
21772 12 : CHECK(isolate->GetCurrentContext() !=
21773 : isolate->GetEnteredOrMicrotaskContext());
21774 6 : }
21775 :
21776 6 : static void Regress808911_CurrentContextWrapper(
21777 6 : const v8::FunctionCallbackInfo<Value>& info) {
21778 : // So here we expect "current context" to be context1 and
21779 : // "entered or microtask context" to be context2.
21780 : v8::Isolate* isolate = info.GetIsolate();
21781 12 : CHECK(isolate->GetCurrentContext() !=
21782 : isolate->GetEnteredOrMicrotaskContext());
21783 6 : isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
21784 6 : isolate->RunMicrotasks();
21785 6 : }
21786 :
21787 25881 : THREADED_TEST(Regress808911) {
21788 6 : v8::Isolate* isolate = CcTest::isolate();
21789 6 : HandleScope handle_scope(isolate);
21790 6 : Local<Context> context1 = Context::New(isolate);
21791 : Local<Function> function;
21792 : {
21793 : Context::Scope context_scope(context1);
21794 6 : function = Function::New(context1, Regress808911_CurrentContextWrapper)
21795 6 : .ToLocalChecked();
21796 : }
21797 6 : Local<Context> context2 = Context::New(isolate);
21798 : Context::Scope context_scope(context2);
21799 6 : function->CallAsFunction(context2, v8::Undefined(isolate), 0, nullptr)
21800 12 : .ToLocalChecked();
21801 6 : }
21802 :
21803 25880 : TEST(ScopedMicrotasks) {
21804 5 : LocalContext env;
21805 10 : v8::HandleScope handles(env->GetIsolate());
21806 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
21807 : {
21808 : v8::MicrotasksScope scope1(env->GetIsolate(),
21809 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21810 : env->GetIsolate()->EnqueueMicrotask(
21811 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21812 : CompileRun(
21813 : "var ext1Calls = 0;"
21814 : "var ext2Calls = 0;");
21815 : CompileRun("1+1;");
21816 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21817 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21818 : {
21819 : v8::MicrotasksScope scope2(env->GetIsolate(),
21820 5 : v8::MicrotasksScope::kRunMicrotasks);
21821 : CompileRun("1+1;");
21822 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21823 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21824 : {
21825 : v8::MicrotasksScope scope3(env->GetIsolate(),
21826 5 : v8::MicrotasksScope::kRunMicrotasks);
21827 : CompileRun("1+1;");
21828 15 : CHECK_EQ(0,
21829 : CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21830 15 : CHECK_EQ(0,
21831 5 : CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21832 : }
21833 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21834 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21835 : }
21836 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21837 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21838 : env->GetIsolate()->EnqueueMicrotask(
21839 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21840 : }
21841 :
21842 : {
21843 : v8::MicrotasksScope scope(env->GetIsolate(),
21844 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21845 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21846 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21847 : }
21848 :
21849 : {
21850 : v8::MicrotasksScope scope1(env->GetIsolate(),
21851 5 : v8::MicrotasksScope::kRunMicrotasks);
21852 : CompileRun("1+1;");
21853 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21854 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21855 : {
21856 : v8::MicrotasksScope scope2(env->GetIsolate(),
21857 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21858 : }
21859 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21860 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21861 : }
21862 :
21863 : {
21864 : v8::MicrotasksScope scope(env->GetIsolate(),
21865 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21866 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21867 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21868 : env->GetIsolate()->EnqueueMicrotask(
21869 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21870 : }
21871 :
21872 : {
21873 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21874 : {
21875 : v8::MicrotasksScope scope2(env->GetIsolate(),
21876 5 : v8::MicrotasksScope::kRunMicrotasks);
21877 : }
21878 : v8::MicrotasksScope scope3(env->GetIsolate(),
21879 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21880 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21881 20 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21882 : }
21883 :
21884 : {
21885 : v8::MicrotasksScope scope1(env->GetIsolate(),
21886 5 : v8::MicrotasksScope::kRunMicrotasks);
21887 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21888 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21889 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21890 : }
21891 :
21892 : {
21893 : v8::MicrotasksScope scope(env->GetIsolate(),
21894 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21895 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21896 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21897 : }
21898 :
21899 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21900 :
21901 : {
21902 : v8::MicrotasksScope scope(env->GetIsolate(),
21903 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21904 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21905 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21906 : env->GetIsolate()->EnqueueMicrotask(
21907 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21908 : }
21909 :
21910 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21911 :
21912 : {
21913 : v8::MicrotasksScope scope(env->GetIsolate(),
21914 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21915 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21916 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21917 : }
21918 :
21919 : env->GetIsolate()->EnqueueMicrotask(
21920 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21921 : {
21922 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21923 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21924 : v8::MicrotasksScope scope2(env->GetIsolate(),
21925 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21926 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21927 20 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21928 : }
21929 :
21930 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21931 :
21932 : {
21933 : v8::MicrotasksScope scope(env->GetIsolate(),
21934 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21935 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21936 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21937 : }
21938 :
21939 10 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21940 5 : }
21941 :
21942 : namespace {
21943 :
21944 35 : void AssertCowElements(bool expected, const char* source) {
21945 : Local<Value> object = CompileRun(source);
21946 : i::Handle<i::JSObject> array =
21947 35 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*object.As<Object>()));
21948 35 : CHECK_EQ(expected, array->elements()->IsCowArray());
21949 35 : }
21950 :
21951 : } // namespace
21952 :
21953 25880 : TEST(CheckCOWArraysCreatedRuntimeCounter) {
21954 5 : LocalContext env;
21955 10 : v8::HandleScope scope(env->GetIsolate());
21956 5 : AssertCowElements(true, "[1, 2, 3]");
21957 5 : AssertCowElements(false, "[[1], 2, 3]");
21958 5 : AssertCowElements(true, "[[1], 2, 3][0]");
21959 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.foo)");
21960 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.bar)");
21961 5 : AssertCowElements(false, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo)");
21962 10 : AssertCowElements(true, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo[3])");
21963 5 : }
21964 :
21965 :
21966 25880 : TEST(StaticGetters) {
21967 5 : LocalContext context;
21968 : i::Factory* factory = CcTest::i_isolate()->factory();
21969 5 : v8::Isolate* isolate = CcTest::isolate();
21970 10 : v8::HandleScope scope(isolate);
21971 : i::Handle<i::Object> undefined_value = factory->undefined_value();
21972 5 : CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21973 : i::Handle<i::Object> null_value = factory->null_value();
21974 5 : CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21975 : i::Handle<i::Object> true_value = factory->true_value();
21976 5 : CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21977 : i::Handle<i::Object> false_value = factory->false_value();
21978 10 : CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21979 5 : }
21980 :
21981 :
21982 25880 : UNINITIALIZED_TEST(IsolateEmbedderData) {
21983 5 : CcTest::DisableAutomaticDispose();
21984 : v8::Isolate::CreateParams create_params;
21985 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21986 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
21987 5 : isolate->Enter();
21988 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21989 25 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21990 20 : CHECK(!isolate->GetData(slot));
21991 20 : CHECK(!i_isolate->GetData(slot));
21992 : }
21993 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21994 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21995 : isolate->SetData(slot, data);
21996 : }
21997 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21998 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21999 20 : CHECK_EQ(data, isolate->GetData(slot));
22000 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22001 : }
22002 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22003 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
22004 : isolate->SetData(slot, data);
22005 : }
22006 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22007 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
22008 20 : CHECK_EQ(data, isolate->GetData(slot));
22009 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22010 : }
22011 5 : isolate->Exit();
22012 5 : isolate->Dispose();
22013 5 : }
22014 :
22015 :
22016 25880 : TEST(StringEmpty) {
22017 5 : LocalContext context;
22018 : i::Factory* factory = CcTest::i_isolate()->factory();
22019 5 : v8::Isolate* isolate = CcTest::isolate();
22020 10 : v8::HandleScope scope(isolate);
22021 : i::Handle<i::Object> empty_string = factory->empty_string();
22022 10 : CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22023 5 : }
22024 :
22025 :
22026 : static int instance_checked_getter_count = 0;
22027 120 : static void InstanceCheckedGetter(
22028 : Local<String> name,
22029 : const v8::PropertyCallbackInfo<v8::Value>& info) {
22030 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22031 : .FromJust());
22032 120 : instance_checked_getter_count++;
22033 120 : info.GetReturnValue().Set(v8_num(11));
22034 120 : }
22035 :
22036 :
22037 : static int instance_checked_setter_count = 0;
22038 120 : static void InstanceCheckedSetter(Local<String> name,
22039 : Local<Value> value,
22040 : const v8::PropertyCallbackInfo<void>& info) {
22041 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22042 : .FromJust());
22043 480 : CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
22044 : .FromJust());
22045 120 : instance_checked_setter_count++;
22046 120 : }
22047 :
22048 :
22049 420 : static void CheckInstanceCheckedResult(int getters, int setters,
22050 : bool expects_callbacks,
22051 : TryCatch* try_catch) {
22052 420 : if (expects_callbacks) {
22053 240 : CHECK(!try_catch->HasCaught());
22054 240 : CHECK_EQ(getters, instance_checked_getter_count);
22055 240 : CHECK_EQ(setters, instance_checked_setter_count);
22056 : } else {
22057 180 : CHECK(try_catch->HasCaught());
22058 180 : CHECK_EQ(0, instance_checked_getter_count);
22059 180 : CHECK_EQ(0, instance_checked_setter_count);
22060 : }
22061 420 : try_catch->Reset();
22062 420 : }
22063 :
22064 :
22065 42 : static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22066 42 : instance_checked_getter_count = 0;
22067 42 : instance_checked_setter_count = 0;
22068 42 : TryCatch try_catch(CcTest::isolate());
22069 :
22070 : // Test path through generic runtime code.
22071 : CompileRun("obj.foo");
22072 42 : CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22073 : CompileRun("obj.foo = 23");
22074 42 : CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22075 :
22076 : // Test path through generated LoadIC and StoredIC.
22077 : CompileRun("function test_get(o) { o.foo; }"
22078 : "test_get(obj);");
22079 42 : CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22080 : CompileRun("test_get(obj);");
22081 42 : CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22082 : CompileRun("test_get(obj);");
22083 42 : CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22084 : CompileRun("function test_set(o) { o.foo = 23; }"
22085 : "test_set(obj);");
22086 42 : CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22087 : CompileRun("test_set(obj);");
22088 42 : CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22089 : CompileRun("test_set(obj);");
22090 42 : CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22091 :
22092 : // Test path through optimized code.
22093 : CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22094 : "test_get(obj);");
22095 42 : CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22096 : CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22097 : "test_set(obj);");
22098 42 : CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22099 :
22100 : // Cleanup so that closures start out fresh in next check.
22101 : CompileRun(
22102 : "%DeoptimizeFunction(test_get);"
22103 : "%ClearFunctionFeedback(test_get);"
22104 : "%DeoptimizeFunction(test_set);"
22105 42 : "%ClearFunctionFeedback(test_set);");
22106 42 : }
22107 :
22108 :
22109 25881 : THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22110 6 : v8::internal::FLAG_allow_natives_syntax = true;
22111 6 : LocalContext context;
22112 12 : v8::HandleScope scope(context->GetIsolate());
22113 :
22114 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22115 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22116 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22117 : Local<Value>(), v8::DEFAULT, v8::None,
22118 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22119 36 : CHECK(context->Global()
22120 : ->Set(context.local(), v8_str("f"),
22121 : templ->GetFunction(context.local()).ToLocalChecked())
22122 : .FromJust());
22123 :
22124 : printf("Testing positive ...\n");
22125 : CompileRun("var obj = new f();");
22126 30 : CHECK(templ->HasInstance(
22127 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22128 6 : CheckInstanceCheckedAccessors(true);
22129 :
22130 : printf("Testing negative ...\n");
22131 : CompileRun("var obj = {};"
22132 : "obj.__proto__ = new f();");
22133 30 : CHECK(!templ->HasInstance(
22134 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22135 12 : CheckInstanceCheckedAccessors(false);
22136 6 : }
22137 :
22138 90 : static void EmptyInterceptorGetter(
22139 90 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22140 :
22141 30 : static void EmptyInterceptorSetter(
22142 : Local<Name> name, Local<Value> value,
22143 30 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
22144 :
22145 25881 : THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22146 6 : v8::internal::FLAG_allow_natives_syntax = true;
22147 6 : LocalContext context;
22148 12 : v8::HandleScope scope(context->GetIsolate());
22149 :
22150 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22151 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22152 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
22153 12 : EmptyInterceptorGetter, EmptyInterceptorSetter));
22154 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22155 : Local<Value>(), v8::DEFAULT, v8::None,
22156 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22157 36 : CHECK(context->Global()
22158 : ->Set(context.local(), v8_str("f"),
22159 : templ->GetFunction(context.local()).ToLocalChecked())
22160 : .FromJust());
22161 :
22162 : printf("Testing positive ...\n");
22163 : CompileRun("var obj = new f();");
22164 30 : CHECK(templ->HasInstance(
22165 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22166 6 : CheckInstanceCheckedAccessors(true);
22167 :
22168 : printf("Testing negative ...\n");
22169 : CompileRun("var obj = {};"
22170 : "obj.__proto__ = new f();");
22171 30 : CHECK(!templ->HasInstance(
22172 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22173 12 : CheckInstanceCheckedAccessors(false);
22174 6 : }
22175 :
22176 :
22177 25881 : THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22178 6 : v8::internal::FLAG_allow_natives_syntax = true;
22179 6 : LocalContext context;
22180 12 : v8::HandleScope scope(context->GetIsolate());
22181 :
22182 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22183 6 : Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22184 : proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22185 : InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
22186 : v8::None,
22187 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22188 36 : CHECK(context->Global()
22189 : ->Set(context.local(), v8_str("f"),
22190 : templ->GetFunction(context.local()).ToLocalChecked())
22191 : .FromJust());
22192 :
22193 : printf("Testing positive ...\n");
22194 : CompileRun("var obj = new f();");
22195 30 : CHECK(templ->HasInstance(
22196 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22197 6 : CheckInstanceCheckedAccessors(true);
22198 :
22199 : printf("Testing negative ...\n");
22200 : CompileRun("var obj = {};"
22201 : "obj.__proto__ = new f();");
22202 30 : CHECK(!templ->HasInstance(
22203 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22204 6 : CheckInstanceCheckedAccessors(false);
22205 :
22206 : printf("Testing positive with modified prototype chain ...\n");
22207 : CompileRun("var obj = new f();"
22208 : "var pro = {};"
22209 : "pro.__proto__ = obj.__proto__;"
22210 : "obj.__proto__ = pro;");
22211 30 : CHECK(templ->HasInstance(
22212 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22213 12 : CheckInstanceCheckedAccessors(true);
22214 6 : }
22215 :
22216 :
22217 25880 : TEST(TryFinallyMessage) {
22218 5 : LocalContext context;
22219 10 : v8::HandleScope scope(context->GetIsolate());
22220 : {
22221 : // Test that the original error message is not lost if there is a
22222 : // recursive call into Javascript is done in the finally block, e.g. to
22223 : // initialize an IC. (crbug.com/129171)
22224 5 : TryCatch try_catch(context->GetIsolate());
22225 : const char* trigger_ic =
22226 : "try { \n"
22227 : " throw new Error('test'); \n"
22228 : "} finally { \n"
22229 : " var x = 0; \n"
22230 : " x++; \n" // Trigger an IC initialization here.
22231 : "} \n";
22232 : CompileRun(trigger_ic);
22233 5 : CHECK(try_catch.HasCaught());
22234 5 : Local<Message> message = try_catch.Message();
22235 5 : CHECK(!message.IsEmpty());
22236 10 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
22237 : }
22238 :
22239 : {
22240 : // Test that the original exception message is indeed overwritten if
22241 : // a new error is thrown in the finally block.
22242 5 : TryCatch try_catch(context->GetIsolate());
22243 : const char* throw_again =
22244 : "try { \n"
22245 : " throw new Error('test'); \n"
22246 : "} finally { \n"
22247 : " var x = 0; \n"
22248 : " x++; \n"
22249 : " throw new Error('again'); \n" // This is the new uncaught error.
22250 : "} \n";
22251 : CompileRun(throw_again);
22252 5 : CHECK(try_catch.HasCaught());
22253 5 : Local<Message> message = try_catch.Message();
22254 5 : CHECK(!message.IsEmpty());
22255 10 : CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
22256 5 : }
22257 5 : }
22258 :
22259 :
22260 96 : static void Helper137002(bool do_store,
22261 : bool polymorphic,
22262 : bool remove_accessor,
22263 : bool interceptor) {
22264 96 : LocalContext context;
22265 96 : Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22266 96 : if (interceptor) {
22267 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22268 48 : FooSetInterceptor));
22269 : } else {
22270 : templ->SetAccessor(v8_str("foo"),
22271 : GetterWhichReturns42,
22272 48 : SetterWhichSetsYOnThisTo23);
22273 : }
22274 576 : CHECK(context->Global()
22275 : ->Set(context.local(), v8_str("obj"),
22276 : templ->NewInstance(context.local()).ToLocalChecked())
22277 : .FromJust());
22278 :
22279 : // Turn monomorphic on slow object with native accessor, then turn
22280 : // polymorphic, finally optimize to create negative lookup and fail.
22281 : CompileRun(do_store ?
22282 : "function f(x) { x.foo = void 0; }" :
22283 96 : "function f(x) { return x.foo; }");
22284 : CompileRun("obj.y = void 0;");
22285 96 : if (!interceptor) {
22286 : CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22287 : }
22288 : CompileRun("obj.__proto__ = null;"
22289 : "f(obj); f(obj); f(obj);");
22290 96 : if (polymorphic) {
22291 : CompileRun("f({});");
22292 : }
22293 : CompileRun("obj.y = void 0;"
22294 : "%OptimizeFunctionOnNextCall(f);");
22295 96 : if (remove_accessor) {
22296 : CompileRun("delete obj.foo;");
22297 : }
22298 : CompileRun("var result = f(obj);");
22299 96 : if (do_store) {
22300 : CompileRun("result = obj.y;");
22301 : }
22302 96 : if (remove_accessor && !interceptor) {
22303 120 : CHECK(context->Global()
22304 : ->Get(context.local(), v8_str("result"))
22305 : .ToLocalChecked()
22306 : ->IsUndefined());
22307 : } else {
22308 432 : CHECK_EQ(do_store ? 23 : 42, context->Global()
22309 : ->Get(context.local(), v8_str("result"))
22310 : .ToLocalChecked()
22311 : ->Int32Value(context.local())
22312 : .FromJust());
22313 96 : }
22314 96 : }
22315 :
22316 :
22317 25881 : THREADED_TEST(Regress137002a) {
22318 6 : i::FLAG_allow_natives_syntax = true;
22319 6 : i::FLAG_compilation_cache = false;
22320 6 : v8::HandleScope scope(CcTest::isolate());
22321 102 : for (int i = 0; i < 16; i++) {
22322 96 : Helper137002(i & 8, i & 4, i & 2, i & 1);
22323 6 : }
22324 6 : }
22325 :
22326 :
22327 25881 : THREADED_TEST(Regress137002b) {
22328 6 : i::FLAG_allow_natives_syntax = true;
22329 6 : LocalContext context;
22330 6 : v8::Isolate* isolate = context->GetIsolate();
22331 12 : v8::HandleScope scope(isolate);
22332 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22333 : templ->SetAccessor(v8_str("foo"),
22334 : GetterWhichReturns42,
22335 6 : SetterWhichSetsYOnThisTo23);
22336 36 : CHECK(context->Global()
22337 : ->Set(context.local(), v8_str("obj"),
22338 : templ->NewInstance(context.local()).ToLocalChecked())
22339 : .FromJust());
22340 :
22341 : // Turn monomorphic on slow object with native accessor, then just
22342 : // delete the property and fail.
22343 : CompileRun("function load(x) { return x.foo; }"
22344 : "function store(x) { x.foo = void 0; }"
22345 : "function keyed_load(x, key) { return x[key]; }"
22346 : // Second version of function has a different source (add void 0)
22347 : // so that it does not share code with the first version. This
22348 : // ensures that the ICs are monomorphic.
22349 : "function load2(x) { void 0; return x.foo; }"
22350 : "function store2(x) { void 0; x.foo = void 0; }"
22351 : "function keyed_load2(x, key) { void 0; return x[key]; }"
22352 :
22353 : "obj.y = void 0;"
22354 : "obj.__proto__ = null;"
22355 : "var subobj = {};"
22356 : "subobj.y = void 0;"
22357 : "subobj.__proto__ = obj;"
22358 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22359 :
22360 : // Make the ICs monomorphic.
22361 : "load(obj); load(obj);"
22362 : "load2(subobj); load2(subobj);"
22363 : "store(obj); store(obj);"
22364 : "store2(subobj); store2(subobj);"
22365 : "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22366 : "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22367 :
22368 : // Actually test the shiny new ICs and better not crash. This
22369 : // serves as a regression test for issue 142088 as well.
22370 : "load(obj);"
22371 : "load2(subobj);"
22372 : "store(obj);"
22373 : "store2(subobj);"
22374 : "keyed_load(obj, 'foo');"
22375 : "keyed_load2(subobj, 'foo');"
22376 :
22377 : // Delete the accessor. It better not be called any more now.
22378 : "delete obj.foo;"
22379 : "obj.y = void 0;"
22380 : "subobj.y = void 0;"
22381 :
22382 : "var load_result = load(obj);"
22383 : "var load_result2 = load2(subobj);"
22384 : "var keyed_load_result = keyed_load(obj, 'foo');"
22385 : "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22386 : "store(obj);"
22387 : "store2(subobj);"
22388 : "var y_from_obj = obj.y;"
22389 : "var y_from_subobj = subobj.y;");
22390 30 : CHECK(context->Global()
22391 : ->Get(context.local(), v8_str("load_result"))
22392 : .ToLocalChecked()
22393 : ->IsUndefined());
22394 30 : CHECK(context->Global()
22395 : ->Get(context.local(), v8_str("load_result2"))
22396 : .ToLocalChecked()
22397 : ->IsUndefined());
22398 30 : CHECK(context->Global()
22399 : ->Get(context.local(), v8_str("keyed_load_result"))
22400 : .ToLocalChecked()
22401 : ->IsUndefined());
22402 30 : CHECK(context->Global()
22403 : ->Get(context.local(), v8_str("keyed_load_result2"))
22404 : .ToLocalChecked()
22405 : ->IsUndefined());
22406 30 : CHECK(context->Global()
22407 : ->Get(context.local(), v8_str("y_from_obj"))
22408 : .ToLocalChecked()
22409 : ->IsUndefined());
22410 30 : CHECK(context->Global()
22411 : ->Get(context.local(), v8_str("y_from_subobj"))
22412 : .ToLocalChecked()
22413 6 : ->IsUndefined());
22414 6 : }
22415 :
22416 :
22417 25881 : THREADED_TEST(Regress142088) {
22418 6 : i::FLAG_allow_natives_syntax = true;
22419 6 : LocalContext context;
22420 6 : v8::Isolate* isolate = context->GetIsolate();
22421 12 : v8::HandleScope scope(isolate);
22422 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22423 : templ->SetAccessor(v8_str("foo"),
22424 : GetterWhichReturns42,
22425 6 : SetterWhichSetsYOnThisTo23);
22426 36 : CHECK(context->Global()
22427 : ->Set(context.local(), v8_str("obj"),
22428 : templ->NewInstance(context.local()).ToLocalChecked())
22429 : .FromJust());
22430 :
22431 : CompileRun("function load(x) { return x.foo; }"
22432 : "var o = Object.create(obj);"
22433 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22434 6 : "load(o); load(o); load(o); load(o);");
22435 6 : }
22436 :
22437 :
22438 25881 : THREADED_TEST(Regress137496) {
22439 6 : i::FLAG_expose_gc = true;
22440 6 : LocalContext context;
22441 12 : v8::HandleScope scope(context->GetIsolate());
22442 :
22443 : // Compile a try-finally clause where the finally block causes a GC
22444 : // while there still is a message pending for external reporting.
22445 12 : TryCatch try_catch(context->GetIsolate());
22446 6 : try_catch.SetVerbose(true);
22447 : CompileRun("try { throw new Error(); } finally { gc(); }");
22448 12 : CHECK(try_catch.HasCaught());
22449 6 : }
22450 :
22451 :
22452 25881 : THREADED_TEST(Regress157124) {
22453 6 : LocalContext context;
22454 6 : v8::Isolate* isolate = context->GetIsolate();
22455 12 : v8::HandleScope scope(isolate);
22456 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22457 12 : Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
22458 6 : obj->GetIdentityHash();
22459 : obj->DeletePrivate(context.local(),
22460 6 : v8::Private::ForApi(isolate, v8_str("Bug")))
22461 18 : .FromJust();
22462 6 : }
22463 :
22464 :
22465 25881 : THREADED_TEST(Regress2535) {
22466 6 : LocalContext context;
22467 12 : v8::HandleScope scope(context->GetIsolate());
22468 : Local<Value> set_value = CompileRun("new Set();");
22469 : Local<Object> set_object(Local<Object>::Cast(set_value));
22470 6 : CHECK_EQ(0, set_object->InternalFieldCount());
22471 : Local<Value> map_value = CompileRun("new Map();");
22472 : Local<Object> map_object(Local<Object>::Cast(map_value));
22473 12 : CHECK_EQ(0, map_object->InternalFieldCount());
22474 6 : }
22475 :
22476 :
22477 25881 : THREADED_TEST(Regress2746) {
22478 6 : LocalContext context;
22479 6 : v8::Isolate* isolate = context->GetIsolate();
22480 12 : v8::HandleScope scope(isolate);
22481 6 : Local<Object> obj = Object::New(isolate);
22482 6 : Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
22483 12 : CHECK(
22484 : obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
22485 6 : Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
22486 6 : CHECK(!value.IsEmpty());
22487 12 : CHECK(value->IsUndefined());
22488 6 : }
22489 :
22490 :
22491 25881 : THREADED_TEST(Regress260106) {
22492 6 : LocalContext context;
22493 6 : v8::Isolate* isolate = context->GetIsolate();
22494 12 : v8::HandleScope scope(isolate);
22495 : Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22496 6 : DummyCallHandler);
22497 : CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22498 : Local<Function> function =
22499 12 : templ->GetFunction(context.local()).ToLocalChecked();
22500 6 : CHECK(!function.IsEmpty());
22501 12 : CHECK(function->IsFunction());
22502 6 : }
22503 :
22504 25881 : THREADED_TEST(JSONParseObject) {
22505 6 : LocalContext context;
22506 12 : HandleScope scope(context->GetIsolate());
22507 : Local<Value> obj =
22508 12 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22509 6 : Local<Object> global = context->Global();
22510 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22511 12 : ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22512 6 : }
22513 :
22514 25881 : THREADED_TEST(JSONParseNumber) {
22515 6 : LocalContext context;
22516 12 : HandleScope scope(context->GetIsolate());
22517 : Local<Value> obj =
22518 12 : v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
22519 6 : Local<Object> global = context->Global();
22520 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22521 12 : ExpectString("JSON.stringify(obj)", "42");
22522 6 : }
22523 :
22524 : namespace {
22525 42 : void TestJSONParseArray(Local<Context> context, const char* input_str,
22526 : const char* expected_output_str,
22527 : i::ElementsKind expected_elements_kind) {
22528 : Local<Value> obj =
22529 42 : v8::JSON::Parse(context, v8_str(input_str)).ToLocalChecked();
22530 :
22531 : i::Handle<i::JSArray> a =
22532 42 : i::Handle<i::JSArray>::cast(v8::Utils::OpenHandle(*obj));
22533 42 : CHECK_EQ(expected_elements_kind, a->GetElementsKind());
22534 :
22535 42 : Local<Object> global = context->Global();
22536 126 : global->Set(context, v8_str("obj"), obj).FromJust();
22537 42 : ExpectString("JSON.stringify(obj)", expected_output_str);
22538 42 : }
22539 : } // namespace
22540 :
22541 25881 : THREADED_TEST(JSONParseArray) {
22542 6 : LocalContext context;
22543 12 : HandleScope scope(context->GetIsolate());
22544 :
22545 : TestJSONParseArray(context.local(), "[0, 1, 2]", "[0,1,2]",
22546 6 : i::PACKED_SMI_ELEMENTS);
22547 : TestJSONParseArray(context.local(), "[0, 1.2, 2]", "[0,1.2,2]",
22548 6 : i::PACKED_DOUBLE_ELEMENTS);
22549 : TestJSONParseArray(context.local(), "[0.2, 1, 2]", "[0.2,1,2]",
22550 6 : i::PACKED_DOUBLE_ELEMENTS);
22551 : TestJSONParseArray(context.local(), "[0, \"a\", 2]", "[0,\"a\",2]",
22552 6 : i::PACKED_ELEMENTS);
22553 : TestJSONParseArray(context.local(), "[\"a\", 1, 2]", "[\"a\",1,2]",
22554 6 : i::PACKED_ELEMENTS);
22555 : TestJSONParseArray(context.local(), "[\"a\", 1.2, 2]", "[\"a\",1.2,2]",
22556 6 : i::PACKED_ELEMENTS);
22557 : TestJSONParseArray(context.local(), "[0, 1.2, \"a\"]", "[0,1.2,\"a\"]",
22558 12 : i::PACKED_ELEMENTS);
22559 6 : }
22560 :
22561 25881 : THREADED_TEST(JSONStringifyObject) {
22562 6 : LocalContext context;
22563 12 : HandleScope scope(context->GetIsolate());
22564 : Local<Value> value =
22565 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22566 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22567 6 : Local<Object> global = context->Global();
22568 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22569 : Local<String> json =
22570 12 : v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
22571 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
22572 12 : ExpectString("JSON.stringify(obj)", *utf8);
22573 6 : }
22574 :
22575 25881 : THREADED_TEST(JSONStringifyObjectWithGap) {
22576 6 : LocalContext context;
22577 12 : HandleScope scope(context->GetIsolate());
22578 : Local<Value> value =
22579 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22580 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22581 6 : Local<Object> global = context->Global();
22582 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22583 : Local<String> json =
22584 18 : v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
22585 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
22586 12 : ExpectString("JSON.stringify(obj, null, '*')", *utf8);
22587 6 : }
22588 :
22589 : #if V8_OS_POSIX
22590 : class ThreadInterruptTest {
22591 : public:
22592 6 : ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22593 6 : ~ThreadInterruptTest() = default;
22594 :
22595 6 : void RunTest() {
22596 : InterruptThread i_thread(this);
22597 6 : i_thread.Start();
22598 :
22599 6 : sem_.Wait();
22600 6 : CHECK_EQ(kExpectedValue, sem_value_);
22601 6 : }
22602 :
22603 : private:
22604 : static const int kExpectedValue = 1;
22605 :
22606 6 : class InterruptThread : public v8::base::Thread {
22607 : public:
22608 : explicit InterruptThread(ThreadInterruptTest* test)
22609 6 : : Thread(Options("InterruptThread")), test_(test) {}
22610 :
22611 6 : void Run() override {
22612 : struct sigaction action;
22613 :
22614 : // Ensure that we'll enter waiting condition
22615 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22616 :
22617 : // Setup signal handler
22618 : memset(&action, 0, sizeof(action));
22619 6 : action.sa_handler = SignalHandler;
22620 6 : sigaction(SIGCHLD, &action, nullptr);
22621 :
22622 : // Send signal
22623 6 : kill(getpid(), SIGCHLD);
22624 :
22625 : // Ensure that if wait has returned because of error
22626 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22627 :
22628 : // Set value and signal semaphore
22629 6 : test_->sem_value_ = 1;
22630 6 : test_->sem_.Signal();
22631 6 : }
22632 :
22633 6 : static void SignalHandler(int signal) {
22634 6 : }
22635 :
22636 : private:
22637 : ThreadInterruptTest* test_;
22638 : };
22639 :
22640 : v8::base::Semaphore sem_;
22641 : volatile int sem_value_;
22642 : };
22643 :
22644 :
22645 25881 : THREADED_TEST(SemaphoreInterruption) {
22646 12 : ThreadInterruptTest().RunTest();
22647 6 : }
22648 :
22649 :
22650 : #endif // V8_OS_POSIX
22651 :
22652 :
22653 0 : void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22654 0 : UNREACHABLE();
22655 : }
22656 :
22657 :
22658 25880 : TEST(JSONStringifyAccessCheck) {
22659 5 : v8::V8::Initialize();
22660 5 : v8::Isolate* isolate = CcTest::isolate();
22661 5 : v8::HandleScope scope(isolate);
22662 :
22663 : // Create an ObjectTemplate for global objects and install access
22664 : // check callbacks that will block access.
22665 : v8::Local<v8::ObjectTemplate> global_template =
22666 5 : v8::ObjectTemplate::New(isolate);
22667 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22668 :
22669 : // Create a context and set an x property on it's global object.
22670 10 : LocalContext context0(nullptr, global_template);
22671 5 : v8::Local<v8::Object> global0 = context0->Global();
22672 15 : global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
22673 5 : ExpectString("JSON.stringify(this)", "{\"x\":42}");
22674 :
22675 15 : for (int i = 0; i < 2; i++) {
22676 10 : if (i == 1) {
22677 : // Install a toJSON function on the second run.
22678 : v8::Local<v8::FunctionTemplate> toJSON =
22679 5 : v8::FunctionTemplate::New(isolate, UnreachableCallback);
22680 :
22681 : global0->Set(context0.local(), v8_str("toJSON"),
22682 25 : toJSON->GetFunction(context0.local()).ToLocalChecked())
22683 10 : .FromJust();
22684 : }
22685 : // Create a context with a different security token so that the
22686 : // failed access check callback will be called on each access.
22687 10 : LocalContext context1(nullptr, global_template);
22688 50 : CHECK(context1->Global()
22689 : ->Set(context1.local(), v8_str("other"), global0)
22690 : .FromJust());
22691 :
22692 10 : CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22693 10 : CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22694 10 : CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22695 15 : }
22696 5 : }
22697 :
22698 :
22699 : bool access_check_fail_thrown = false;
22700 : bool catch_callback_called = false;
22701 :
22702 :
22703 : // Failed access check callback that performs a GC on each invocation.
22704 80 : void FailedAccessCheckThrows(Local<v8::Object> target,
22705 : v8::AccessType type,
22706 : Local<v8::Value> data) {
22707 80 : access_check_fail_thrown = true;
22708 80 : i::PrintF("Access check failed. Error thrown.\n");
22709 : CcTest::isolate()->ThrowException(
22710 80 : v8::Exception::Error(v8_str("cross context")));
22711 80 : }
22712 :
22713 :
22714 300 : void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22715 300 : for (int i = 0; i < args.Length(); i++) {
22716 75 : i::PrintF("%s\n", *String::Utf8Value(args.GetIsolate(), args[i]));
22717 : }
22718 75 : catch_callback_called = true;
22719 75 : }
22720 :
22721 :
22722 5 : void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22723 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
22724 20 : CHECK(
22725 : args[0]
22726 : ->ToObject(context)
22727 : .ToLocalChecked()
22728 : ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
22729 : .IsNothing());
22730 5 : }
22731 :
22732 :
22733 75 : void CheckCorrectThrow(const char* script) {
22734 : // Test that the script, when wrapped into a try-catch, triggers the catch
22735 : // clause due to failed access check throwing an exception.
22736 : // The subsequent try-catch should run without any exception.
22737 75 : access_check_fail_thrown = false;
22738 75 : catch_callback_called = false;
22739 : i::ScopedVector<char> source(1024);
22740 75 : i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22741 : CompileRun(source.start());
22742 75 : CHECK(access_check_fail_thrown);
22743 75 : CHECK(catch_callback_called);
22744 :
22745 75 : access_check_fail_thrown = false;
22746 75 : catch_callback_called = false;
22747 : CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22748 75 : CHECK(!access_check_fail_thrown);
22749 75 : CHECK(!catch_callback_called);
22750 75 : }
22751 :
22752 :
22753 25880 : TEST(AccessCheckThrows) {
22754 5 : i::FLAG_allow_natives_syntax = true;
22755 5 : v8::V8::Initialize();
22756 5 : v8::Isolate* isolate = CcTest::isolate();
22757 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22758 5 : v8::HandleScope scope(isolate);
22759 :
22760 : // Create an ObjectTemplate for global objects and install access
22761 : // check callbacks that will block access.
22762 : v8::Local<v8::ObjectTemplate> global_template =
22763 5 : v8::ObjectTemplate::New(isolate);
22764 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22765 :
22766 : // Create a context and set an x property on it's global object.
22767 10 : LocalContext context0(nullptr, global_template);
22768 5 : v8::Local<v8::Object> global0 = context0->Global();
22769 15 : CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
22770 :
22771 : // Create a context with a different security token so that the
22772 : // failed access check callback will be called on each access.
22773 10 : LocalContext context1(nullptr, global_template);
22774 25 : CHECK(context1->Global()
22775 : ->Set(context1.local(), v8_str("other"), global0)
22776 : .FromJust());
22777 :
22778 : v8::Local<v8::FunctionTemplate> catcher_fun =
22779 5 : v8::FunctionTemplate::New(isolate, CatcherCallback);
22780 35 : CHECK(context1->Global()
22781 : ->Set(context1.local(), v8_str("catcher"),
22782 : catcher_fun->GetFunction(context1.local()).ToLocalChecked())
22783 : .FromJust());
22784 :
22785 : v8::Local<v8::FunctionTemplate> has_own_property_fun =
22786 5 : v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22787 35 : CHECK(context1->Global()
22788 : ->Set(context1.local(), v8_str("has_own_property"),
22789 : has_own_property_fun->GetFunction(context1.local())
22790 : .ToLocalChecked())
22791 : .FromJust());
22792 :
22793 : {
22794 5 : v8::TryCatch try_catch(isolate);
22795 5 : access_check_fail_thrown = false;
22796 : CompileRun("other.x;");
22797 5 : CHECK(access_check_fail_thrown);
22798 5 : CHECK(try_catch.HasCaught());
22799 : }
22800 :
22801 5 : CheckCorrectThrow("other.x");
22802 5 : CheckCorrectThrow("other[1]");
22803 5 : CheckCorrectThrow("JSON.stringify(other)");
22804 5 : CheckCorrectThrow("has_own_property(other, 'x')");
22805 5 : CheckCorrectThrow("%GetProperty(other, 'x')");
22806 5 : CheckCorrectThrow("%SetKeyedProperty(other, 'x', 'foo')");
22807 5 : CheckCorrectThrow("%SetNamedProperty(other, 'y', 'foo')");
22808 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kSloppy) == 0);
22809 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kStrict) == 1);
22810 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); // 0 == SLOPPY
22811 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 1)"); // 1 == STRICT
22812 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22813 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 1)");
22814 5 : CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
22815 5 : CheckCorrectThrow("%HasProperty(other, 'x')");
22816 5 : CheckCorrectThrow("Object.prototype.propertyIsEnumerable(other, 'x')");
22817 : // PROPERTY_ATTRIBUTES_NONE = 0
22818 : CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22819 5 : "other, 'x', null, null, 1)");
22820 :
22821 : // Reset the failed access check callback so it does not influence
22822 : // the other tests.
22823 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
22824 5 : }
22825 :
22826 : class RequestInterruptTestBase {
22827 : public:
22828 35 : RequestInterruptTestBase()
22829 : : env_(),
22830 35 : isolate_(env_->GetIsolate()),
22831 : sem_(0),
22832 : warmup_(20000),
22833 105 : should_continue_(true) {
22834 35 : }
22835 :
22836 35 : virtual ~RequestInterruptTestBase() = default;
22837 :
22838 : virtual void StartInterruptThread() = 0;
22839 :
22840 : virtual void TestBody() = 0;
22841 :
22842 70 : void RunTest() {
22843 35 : StartInterruptThread();
22844 :
22845 35 : v8::HandleScope handle_scope(isolate_);
22846 :
22847 35 : TestBody();
22848 :
22849 : // Verify we arrived here because interruptor was called
22850 : // not due to a bug causing us to exit the loop too early.
22851 35 : CHECK(!should_continue());
22852 35 : }
22853 :
22854 : void WakeUpInterruptor() {
22855 35 : sem_.Signal();
22856 : }
22857 :
22858 : bool should_continue() const { return should_continue_; }
22859 :
22860 809396 : bool ShouldContinue() {
22861 809396 : if (warmup_ > 0) {
22862 600000 : if (--warmup_ == 0) {
22863 : WakeUpInterruptor();
22864 : }
22865 : }
22866 :
22867 809396 : return should_continue_;
22868 : }
22869 :
22870 708462 : static void ShouldContinueCallback(
22871 1416924 : const v8::FunctionCallbackInfo<Value>& info) {
22872 : RequestInterruptTestBase* test =
22873 : reinterpret_cast<RequestInterruptTestBase*>(
22874 708462 : info.Data().As<v8::External>()->Value());
22875 708462 : info.GetReturnValue().Set(test->ShouldContinue());
22876 708462 : }
22877 :
22878 : LocalContext env_;
22879 : v8::Isolate* isolate_;
22880 : v8::base::Semaphore sem_;
22881 : int warmup_;
22882 : bool should_continue_;
22883 : };
22884 :
22885 :
22886 60 : class RequestInterruptTestBaseWithSimpleInterrupt
22887 : : public RequestInterruptTestBase {
22888 : public:
22889 60 : RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22890 :
22891 30 : void StartInterruptThread() override { i_thread.Start(); }
22892 :
22893 : private:
22894 30 : class InterruptThread : public v8::base::Thread {
22895 : public:
22896 : explicit InterruptThread(RequestInterruptTestBase* test)
22897 30 : : Thread(Options("RequestInterruptTest")), test_(test) {}
22898 :
22899 30 : void Run() override {
22900 30 : test_->sem_.Wait();
22901 30 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22902 30 : }
22903 :
22904 30 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
22905 : reinterpret_cast<RequestInterruptTestBase*>(data)->
22906 30 : should_continue_ = false;
22907 30 : }
22908 :
22909 : private:
22910 : RequestInterruptTestBase* test_;
22911 : };
22912 :
22913 : InterruptThread i_thread;
22914 : };
22915 :
22916 :
22917 10 : class RequestInterruptTestWithFunctionCall
22918 : : public RequestInterruptTestBaseWithSimpleInterrupt {
22919 : public:
22920 5 : void TestBody() override {
22921 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
22922 15 : v8::External::New(isolate_, this))
22923 5 : .ToLocalChecked();
22924 25 : CHECK(env_->Global()
22925 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
22926 : .FromJust());
22927 :
22928 : CompileRun("while (ShouldContinue()) { }");
22929 5 : }
22930 : };
22931 :
22932 :
22933 10 : class RequestInterruptTestWithMethodCall
22934 : : public RequestInterruptTestBaseWithSimpleInterrupt {
22935 : public:
22936 5 : void TestBody() override {
22937 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22938 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
22939 : proto->Set(v8_str("shouldContinue"),
22940 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
22941 20 : v8::External::New(isolate_, this)));
22942 30 : CHECK(env_->Global()
22943 : ->Set(env_.local(), v8_str("Klass"),
22944 : t->GetFunction(env_.local()).ToLocalChecked())
22945 : .FromJust());
22946 :
22947 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22948 5 : }
22949 : };
22950 :
22951 :
22952 10 : class RequestInterruptTestWithAccessor
22953 : : public RequestInterruptTestBaseWithSimpleInterrupt {
22954 : public:
22955 5 : void TestBody() override {
22956 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22957 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
22958 : proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22959 15 : isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22960 30 : CHECK(env_->Global()
22961 : ->Set(env_.local(), v8_str("Klass"),
22962 : t->GetFunction(env_.local()).ToLocalChecked())
22963 : .FromJust());
22964 :
22965 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22966 5 : }
22967 : };
22968 :
22969 :
22970 10 : class RequestInterruptTestWithNativeAccessor
22971 : : public RequestInterruptTestBaseWithSimpleInterrupt {
22972 : public:
22973 5 : void TestBody() override {
22974 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22975 10 : t->InstanceTemplate()->SetNativeDataProperty(
22976 : v8_str("shouldContinue"), &ShouldContinueNativeGetter, nullptr,
22977 20 : v8::External::New(isolate_, this));
22978 30 : CHECK(env_->Global()
22979 : ->Set(env_.local(), v8_str("Klass"),
22980 : t->GetFunction(env_.local()).ToLocalChecked())
22981 : .FromJust());
22982 :
22983 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22984 5 : }
22985 :
22986 : private:
22987 100934 : static void ShouldContinueNativeGetter(
22988 : Local<String> property,
22989 : const v8::PropertyCallbackInfo<v8::Value>& info) {
22990 : RequestInterruptTestBase* test =
22991 : reinterpret_cast<RequestInterruptTestBase*>(
22992 100934 : info.Data().As<v8::External>()->Value());
22993 100934 : info.GetReturnValue().Set(test->ShouldContinue());
22994 100934 : }
22995 : };
22996 :
22997 :
22998 10 : class RequestInterruptTestWithMethodCallAndInterceptor
22999 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23000 : public:
23001 5 : void TestBody() override {
23002 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23003 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23004 : proto->Set(v8_str("shouldContinue"),
23005 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23006 20 : v8::External::New(isolate_, this)));
23007 5 : v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23008 : instance_template->SetHandler(
23009 5 : v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23010 :
23011 30 : CHECK(env_->Global()
23012 : ->Set(env_.local(), v8_str("Klass"),
23013 : t->GetFunction(env_.local()).ToLocalChecked())
23014 : .FromJust());
23015 :
23016 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23017 5 : }
23018 :
23019 : private:
23020 100485 : static void EmptyInterceptor(
23021 100485 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23022 : };
23023 :
23024 :
23025 10 : class RequestInterruptTestWithMathAbs
23026 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23027 : public:
23028 5 : void TestBody() override {
23029 : env_->Global()
23030 : ->Set(env_.local(), v8_str("WakeUpInterruptor"),
23031 : Function::New(env_.local(), WakeUpInterruptorCallback,
23032 15 : v8::External::New(isolate_, this))
23033 25 : .ToLocalChecked())
23034 10 : .FromJust();
23035 :
23036 : env_->Global()
23037 : ->Set(env_.local(), v8_str("ShouldContinue"),
23038 : Function::New(env_.local(), ShouldContinueCallback,
23039 15 : v8::External::New(isolate_, this))
23040 25 : .ToLocalChecked())
23041 10 : .FromJust();
23042 :
23043 5 : i::FLAG_allow_natives_syntax = true;
23044 : CompileRun("function loopish(o) {"
23045 : " var pre = 10;"
23046 : " while (o.abs(1) > 0) {"
23047 : " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23048 : " if (pre > 0) {"
23049 : " if (--pre === 0) WakeUpInterruptor(o === Math);"
23050 : " }"
23051 : " }"
23052 : "}"
23053 : "var i = 50;"
23054 : "var obj = {abs: function () { return i-- }, x: null};"
23055 : "delete obj.x;"
23056 : "loopish(obj);"
23057 : "%OptimizeFunctionOnNextCall(loopish);"
23058 : "loopish(Math);");
23059 :
23060 5 : i::FLAG_allow_natives_syntax = false;
23061 5 : }
23062 :
23063 : private:
23064 10 : static void WakeUpInterruptorCallback(
23065 15 : const v8::FunctionCallbackInfo<Value>& info) {
23066 10 : if (!info[0]->BooleanValue(info.GetIsolate())) {
23067 10 : return;
23068 : }
23069 :
23070 : RequestInterruptTestBase* test =
23071 : reinterpret_cast<RequestInterruptTestBase*>(
23072 5 : info.Data().As<v8::External>()->Value());
23073 : test->WakeUpInterruptor();
23074 : }
23075 :
23076 104923 : static void ShouldContinueCallback(
23077 209846 : const v8::FunctionCallbackInfo<Value>& info) {
23078 104923 : RequestInterruptTestBase* test =
23079 : reinterpret_cast<RequestInterruptTestBase*>(
23080 104923 : info.Data().As<v8::External>()->Value());
23081 : info.GetReturnValue().Set(test->should_continue());
23082 104923 : }
23083 : };
23084 :
23085 :
23086 25880 : TEST(RequestInterruptTestWithFunctionCall) {
23087 15 : RequestInterruptTestWithFunctionCall().RunTest();
23088 5 : }
23089 :
23090 :
23091 25880 : TEST(RequestInterruptTestWithMethodCall) {
23092 15 : RequestInterruptTestWithMethodCall().RunTest();
23093 5 : }
23094 :
23095 :
23096 25880 : TEST(RequestInterruptTestWithAccessor) {
23097 15 : RequestInterruptTestWithAccessor().RunTest();
23098 5 : }
23099 :
23100 :
23101 25880 : TEST(RequestInterruptTestWithNativeAccessor) {
23102 15 : RequestInterruptTestWithNativeAccessor().RunTest();
23103 5 : }
23104 :
23105 :
23106 25880 : TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23107 15 : RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23108 5 : }
23109 :
23110 :
23111 25880 : TEST(RequestInterruptTestWithMathAbs) {
23112 15 : RequestInterruptTestWithMathAbs().RunTest();
23113 5 : }
23114 :
23115 :
23116 10 : class RequestMultipleInterrupts : public RequestInterruptTestBase {
23117 : public:
23118 10 : RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23119 :
23120 5 : void StartInterruptThread() override { i_thread.Start(); }
23121 :
23122 5 : void TestBody() override {
23123 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23124 15 : v8::External::New(isolate_, this))
23125 5 : .ToLocalChecked();
23126 25 : CHECK(env_->Global()
23127 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23128 : .FromJust());
23129 :
23130 : CompileRun("while (ShouldContinue()) { }");
23131 5 : }
23132 :
23133 : private:
23134 5 : class InterruptThread : public v8::base::Thread {
23135 : public:
23136 : enum { NUM_INTERRUPTS = 10 };
23137 : explicit InterruptThread(RequestMultipleInterrupts* test)
23138 5 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23139 :
23140 5 : void Run() override {
23141 5 : test_->sem_.Wait();
23142 55 : for (int i = 0; i < NUM_INTERRUPTS; i++) {
23143 50 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23144 : }
23145 5 : }
23146 :
23147 50 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23148 : RequestMultipleInterrupts* test =
23149 : reinterpret_cast<RequestMultipleInterrupts*>(data);
23150 50 : test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23151 50 : }
23152 :
23153 : private:
23154 : RequestMultipleInterrupts* test_;
23155 : };
23156 :
23157 : InterruptThread i_thread;
23158 : int counter_;
23159 : };
23160 :
23161 :
23162 25880 : TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23163 :
23164 :
23165 : static bool interrupt_was_called = false;
23166 :
23167 :
23168 5 : void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
23169 5 : interrupt_was_called = true;
23170 5 : }
23171 :
23172 :
23173 25880 : TEST(RequestInterruptSmallScripts) {
23174 5 : LocalContext env;
23175 5 : v8::Isolate* isolate = CcTest::isolate();
23176 10 : v8::HandleScope scope(isolate);
23177 :
23178 5 : interrupt_was_called = false;
23179 5 : isolate->RequestInterrupt(&SmallScriptsInterruptCallback, nullptr);
23180 : CompileRun("(function(x){return x;})(1);");
23181 10 : CHECK(interrupt_was_called);
23182 5 : }
23183 :
23184 :
23185 : static Local<Value> function_new_expected_env;
23186 24 : static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23187 36 : CHECK(
23188 : function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
23189 : info.Data())
23190 : .FromJust());
23191 : info.GetReturnValue().Set(17);
23192 12 : }
23193 :
23194 :
23195 25881 : THREADED_TEST(FunctionNew) {
23196 6 : LocalContext env;
23197 6 : v8::Isolate* isolate = env->GetIsolate();
23198 12 : v8::HandleScope scope(isolate);
23199 6 : Local<Object> data = v8::Object::New(isolate);
23200 6 : function_new_expected_env = data;
23201 : Local<Function> func =
23202 12 : Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
23203 30 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
23204 6 : Local<Value> result = CompileRun("func();");
23205 18 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
23206 : // Serial number should be invalid => should not be cached.
23207 : auto serial_number =
23208 : i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
23209 18 : ->shared()
23210 12 : ->get_api_func_data()
23211 12 : ->serial_number())
23212 : ->value();
23213 6 : CHECK_EQ(i::FunctionTemplateInfo::kInvalidSerialNumber, serial_number);
23214 :
23215 : // Verify that each Function::New creates a new function instance
23216 6 : Local<Object> data2 = v8::Object::New(isolate);
23217 6 : function_new_expected_env = data2;
23218 : Local<Function> func2 =
23219 12 : Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
23220 6 : CHECK(!func2->IsNull());
23221 12 : CHECK(!func->Equals(env.local(), func2).FromJust());
23222 30 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
23223 6 : Local<Value> result2 = CompileRun("func2();");
23224 24 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
23225 6 : }
23226 :
23227 : namespace {
23228 :
23229 : void Verify(v8::Isolate* isolate, Local<v8::Object> obj) {
23230 : #if VERIFY_HEAP
23231 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23232 : i::Handle<i::JSReceiver> i_obj = v8::Utils::OpenHandle(*obj);
23233 : i_obj->ObjectVerify(i_isolate);
23234 : #endif
23235 : }
23236 :
23237 : } // namespace
23238 :
23239 25881 : THREADED_TEST(ObjectNew) {
23240 6 : LocalContext env;
23241 6 : v8::Isolate* isolate = env->GetIsolate();
23242 12 : v8::HandleScope scope(isolate);
23243 : {
23244 : // Verify that Object::New(null) produces an object with a null
23245 : // [[Prototype]].
23246 : Local<v8::Object> obj =
23247 6 : v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0);
23248 12 : CHECK(obj->GetPrototype()->IsNull());
23249 : Verify(isolate, obj);
23250 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23251 6 : CHECK_EQ(0, keys->Length());
23252 : }
23253 : {
23254 : // Verify that Object::New(proto) produces an object with
23255 : // proto as it's [[Prototype]].
23256 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23257 : Local<v8::Object> obj =
23258 6 : v8::Object::New(isolate, proto, nullptr, nullptr, 0);
23259 : Verify(isolate, obj);
23260 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23261 : }
23262 : {
23263 : // Verify that the properties are installed correctly.
23264 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("b"), v8_str("c")};
23265 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23266 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23267 6 : values, arraysize(values));
23268 : Verify(isolate, obj);
23269 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23270 6 : CHECK_EQ(arraysize(names), keys->Length());
23271 18 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23272 54 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23273 54 : CHECK(values[i]->SameValue(
23274 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23275 : }
23276 : }
23277 : {
23278 : // Same as above, but with non-null prototype.
23279 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23280 18 : Local<v8::Name> names[3] = {v8_str("x"), v8_str("y"), v8_str("z")};
23281 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23282 : Local<v8::Object> obj =
23283 6 : v8::Object::New(isolate, proto, names, values, arraysize(values));
23284 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23285 : Verify(isolate, obj);
23286 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23287 6 : CHECK_EQ(arraysize(names), keys->Length());
23288 18 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23289 54 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23290 54 : CHECK(values[i]->SameValue(
23291 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23292 : }
23293 : }
23294 : {
23295 : // This has to work with duplicate names too.
23296 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("a"), v8_str("a")};
23297 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23298 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23299 6 : values, arraysize(values));
23300 : Verify(isolate, obj);
23301 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23302 6 : CHECK_EQ(1, keys->Length());
23303 18 : CHECK(v8_str("a")->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23304 24 : CHECK(v8_num(3)->SameValue(
23305 : obj->Get(env.local(), v8_str("a")).ToLocalChecked()));
23306 : }
23307 : {
23308 : // This has to work with array indices too.
23309 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("1")};
23310 6 : Local<v8::Value> values[2] = {v8_num(0), v8_num(1)};
23311 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23312 6 : values, arraysize(values));
23313 : Verify(isolate, obj);
23314 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23315 6 : CHECK_EQ(arraysize(names), keys->Length());
23316 12 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23317 36 : CHECK(v8::Number::New(isolate, i)
23318 : ->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23319 36 : CHECK(values[i]->SameValue(obj->Get(env.local(), i).ToLocalChecked()));
23320 : }
23321 : }
23322 : {
23323 : // This has to work with mixed array indices / property names too.
23324 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("x")};
23325 6 : Local<v8::Value> values[2] = {v8_num(42), v8_num(24)};
23326 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23327 6 : values, arraysize(values));
23328 : Verify(isolate, obj);
23329 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23330 6 : CHECK_EQ(arraysize(names), keys->Length());
23331 : // 0 -> 42
23332 18 : CHECK(v8_num(0)->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23333 12 : CHECK(
23334 : values[0]->SameValue(obj->Get(env.local(), names[0]).ToLocalChecked()));
23335 : // "x" -> 24
23336 18 : CHECK(v8_str("x")->SameValue(keys->Get(env.local(), 1).ToLocalChecked()));
23337 12 : CHECK(
23338 : values[1]->SameValue(obj->Get(env.local(), names[1]).ToLocalChecked()));
23339 : }
23340 : {
23341 : // Verify that this also works for a couple thousand properties.
23342 : size_t const kLength = 10 * 1024;
23343 61446 : Local<v8::Name> names[kLength];
23344 61440 : Local<v8::Value> values[kLength];
23345 61440 : for (size_t i = 0; i < arraysize(names); ++i) {
23346 61440 : std::ostringstream ost;
23347 61440 : ost << "a" << i;
23348 122880 : names[i] = v8_str(ost.str().c_str());
23349 61440 : values[i] = v8_num(static_cast<double>(i));
23350 61440 : }
23351 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23352 6 : values, arraysize(names));
23353 : Verify(isolate, obj);
23354 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23355 6 : CHECK_EQ(arraysize(names), keys->Length());
23356 61440 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23357 184320 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23358 184320 : CHECK(values[i]->SameValue(
23359 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23360 : }
23361 6 : }
23362 6 : }
23363 :
23364 25880 : TEST(EscapableHandleScope) {
23365 5 : HandleScope outer_scope(CcTest::isolate());
23366 10 : LocalContext context;
23367 : const int runs = 10;
23368 55 : Local<String> values[runs];
23369 50 : for (int i = 0; i < runs; i++) {
23370 50 : v8::EscapableHandleScope inner_scope(CcTest::isolate());
23371 : Local<String> value;
23372 50 : if (i != 0) value = v8_str("escape value");
23373 50 : if (i < runs / 2) {
23374 25 : values[i] = inner_scope.Escape(value);
23375 : } else {
23376 : values[i] = inner_scope.EscapeMaybe(v8::MaybeLocal<String>(value))
23377 25 : .ToLocalChecked();
23378 : }
23379 : }
23380 50 : for (int i = 0; i < runs; i++) {
23381 : Local<String> expected;
23382 50 : if (i != 0) {
23383 135 : CHECK(v8_str("escape value")
23384 : ->Equals(context.local(), values[i])
23385 : .FromJust());
23386 : } else {
23387 10 : CHECK(values[i].IsEmpty());
23388 : }
23389 5 : }
23390 5 : }
23391 :
23392 :
23393 20 : static void SetterWhichExpectsThisAndHolderToDiffer(
23394 : Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23395 20 : CHECK(info.Holder() != info.This());
23396 20 : }
23397 :
23398 :
23399 25880 : TEST(Regress239669) {
23400 5 : LocalContext context;
23401 5 : v8::Isolate* isolate = context->GetIsolate();
23402 10 : v8::HandleScope scope(isolate);
23403 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23404 : templ->SetAccessor(v8_str("x"), nullptr,
23405 5 : SetterWhichExpectsThisAndHolderToDiffer);
23406 30 : CHECK(context->Global()
23407 : ->Set(context.local(), v8_str("P"),
23408 : templ->NewInstance(context.local()).ToLocalChecked())
23409 : .FromJust());
23410 : CompileRun(
23411 : "function C1() {"
23412 : " this.x = 23;"
23413 : "};"
23414 : "C1.prototype = P;"
23415 : "for (var i = 0; i < 4; i++ ) {"
23416 : " new C1();"
23417 5 : "}");
23418 5 : }
23419 :
23420 :
23421 : class ApiCallOptimizationChecker {
23422 : private:
23423 : static Local<Object> data;
23424 : static Local<Object> receiver;
23425 : static Local<Object> holder;
23426 : static Local<Object> callee;
23427 : static int count;
23428 :
23429 270 : static void OptimizationCallback(
23430 1350 : const v8::FunctionCallbackInfo<v8::Value>& info) {
23431 270 : CHECK(data == info.Data());
23432 270 : CHECK(receiver == info.This());
23433 270 : if (info.Length() == 1) {
23434 270 : CHECK(v8_num(1)
23435 : ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
23436 : .FromJust());
23437 : }
23438 270 : CHECK(holder == info.Holder());
23439 270 : count++;
23440 270 : info.GetReturnValue().Set(v8_str("returned"));
23441 270 : }
23442 :
23443 : public:
23444 : enum SignatureType {
23445 : kNoSignature,
23446 : kSignatureOnReceiver,
23447 : kSignatureOnPrototype
23448 : };
23449 :
23450 5 : void RunAll() {
23451 : SignatureType signature_types[] =
23452 5 : {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23453 20 : for (unsigned i = 0; i < arraysize(signature_types); i++) {
23454 15 : SignatureType signature_type = signature_types[i];
23455 45 : for (int j = 0; j < 2; j++) {
23456 30 : bool global = j == 0;
23457 : int key = signature_type +
23458 30 : arraysize(signature_types) * (global ? 1 : 0);
23459 30 : Run(signature_type, global, key);
23460 : }
23461 : }
23462 5 : }
23463 :
23464 30 : void Run(SignatureType signature_type, bool global, int key) {
23465 30 : v8::Isolate* isolate = CcTest::isolate();
23466 30 : v8::HandleScope scope(isolate);
23467 : // Build a template for signature checks.
23468 : Local<v8::ObjectTemplate> signature_template;
23469 : Local<v8::Signature> signature;
23470 : {
23471 : Local<v8::FunctionTemplate> parent_template =
23472 30 : FunctionTemplate::New(isolate);
23473 : Local<v8::FunctionTemplate> function_template
23474 30 : = FunctionTemplate::New(isolate);
23475 30 : function_template->Inherit(parent_template);
23476 30 : switch (signature_type) {
23477 : case kNoSignature:
23478 : break;
23479 : case kSignatureOnReceiver:
23480 10 : signature = v8::Signature::New(isolate, function_template);
23481 10 : break;
23482 : case kSignatureOnPrototype:
23483 10 : signature = v8::Signature::New(isolate, parent_template);
23484 10 : break;
23485 : }
23486 30 : signature_template = function_template->InstanceTemplate();
23487 : }
23488 : // Global object must pass checks.
23489 : Local<v8::Context> context =
23490 30 : v8::Context::New(isolate, nullptr, signature_template);
23491 : v8::Context::Scope context_scope(context);
23492 : // Install regular object that can pass signature checks.
23493 : Local<Object> function_receiver =
23494 30 : signature_template->NewInstance(context).ToLocalChecked();
23495 120 : CHECK(context->Global()
23496 : ->Set(context, v8_str("function_receiver"), function_receiver)
23497 : .FromJust());
23498 : // Get the holder objects.
23499 : Local<Object> inner_global =
23500 60 : Local<Object>::Cast(context->Global()->GetPrototype());
23501 30 : data = Object::New(isolate);
23502 : Local<FunctionTemplate> function_template = FunctionTemplate::New(
23503 30 : isolate, OptimizationCallback, data, signature);
23504 : Local<Function> function =
23505 30 : function_template->GetFunction(context).ToLocalChecked();
23506 : Local<Object> global_holder = inner_global;
23507 : Local<Object> function_holder = function_receiver;
23508 30 : if (signature_type == kSignatureOnPrototype) {
23509 10 : function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23510 10 : global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23511 : }
23512 90 : global_holder->Set(context, v8_str("g_f"), function).FromJust();
23513 60 : global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23514 90 : function_holder->Set(context, v8_str("f"), function).FromJust();
23515 60 : function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23516 : // Initialize expected values.
23517 30 : callee = function;
23518 30 : count = 0;
23519 30 : if (global) {
23520 15 : receiver = context->Global();
23521 15 : holder = inner_global;
23522 : } else {
23523 15 : holder = function_receiver;
23524 : // If not using a signature, add something else to the prototype chain
23525 : // to test the case that holder != receiver
23526 15 : if (signature_type == kNoSignature) {
23527 : receiver = Local<Object>::Cast(CompileRun(
23528 : "var receiver_subclass = {};\n"
23529 : "receiver_subclass.__proto__ = function_receiver;\n"
23530 5 : "receiver_subclass"));
23531 : } else {
23532 : receiver = Local<Object>::Cast(CompileRun(
23533 : "var receiver_subclass = function_receiver;\n"
23534 10 : "receiver_subclass"));
23535 : }
23536 : }
23537 : // With no signature, the holder is not set.
23538 30 : if (signature_type == kNoSignature) holder = receiver;
23539 : // build wrap_function
23540 : i::ScopedVector<char> wrap_function(200);
23541 30 : if (global) {
23542 : i::SNPrintF(
23543 : wrap_function,
23544 : "function wrap_f_%d() { var f = g_f; return f(); }\n"
23545 : "function wrap_get_%d() { return this.g_acc; }\n"
23546 : "function wrap_set_%d() { return this.g_acc = 1; }\n",
23547 15 : key, key, key);
23548 : } else {
23549 : i::SNPrintF(
23550 : wrap_function,
23551 : "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23552 : "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23553 : "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23554 15 : key, key, key);
23555 : }
23556 : // build source string
23557 : i::ScopedVector<char> source(1000);
23558 : i::SNPrintF(
23559 : source,
23560 : "%s\n" // wrap functions
23561 : "function wrap_f() { return wrap_f_%d(); }\n"
23562 : "function wrap_get() { return wrap_get_%d(); }\n"
23563 : "function wrap_set() { return wrap_set_%d(); }\n"
23564 : "check = function(returned) {\n"
23565 : " if (returned !== 'returned') { throw returned; }\n"
23566 : "}\n"
23567 : "\n"
23568 : "check(wrap_f());\n"
23569 : "check(wrap_f());\n"
23570 : "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23571 : "check(wrap_f());\n"
23572 : "\n"
23573 : "check(wrap_get());\n"
23574 : "check(wrap_get());\n"
23575 : "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23576 : "check(wrap_get());\n"
23577 : "\n"
23578 : "check = function(returned) {\n"
23579 : " if (returned !== 1) { throw returned; }\n"
23580 : "}\n"
23581 : "check(wrap_set());\n"
23582 : "check(wrap_set());\n"
23583 : "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23584 : "check(wrap_set());\n",
23585 30 : wrap_function.start(), key, key, key, key, key, key);
23586 60 : v8::TryCatch try_catch(isolate);
23587 : CompileRun(source.start());
23588 30 : CHECK(!try_catch.HasCaught());
23589 60 : CHECK_EQ(9, count);
23590 30 : }
23591 : };
23592 :
23593 :
23594 : Local<Object> ApiCallOptimizationChecker::data;
23595 : Local<Object> ApiCallOptimizationChecker::receiver;
23596 : Local<Object> ApiCallOptimizationChecker::holder;
23597 : Local<Object> ApiCallOptimizationChecker::callee;
23598 : int ApiCallOptimizationChecker::count = 0;
23599 :
23600 :
23601 25880 : TEST(FunctionCallOptimization) {
23602 5 : i::FLAG_allow_natives_syntax = true;
23603 : ApiCallOptimizationChecker checker;
23604 5 : checker.RunAll();
23605 5 : }
23606 :
23607 :
23608 25880 : TEST(FunctionCallOptimizationMultipleArgs) {
23609 5 : i::FLAG_allow_natives_syntax = true;
23610 5 : LocalContext context;
23611 5 : v8::Isolate* isolate = context->GetIsolate();
23612 10 : v8::HandleScope scope(isolate);
23613 5 : Local<Object> global = context->Global();
23614 : Local<v8::Function> function =
23615 10 : Function::New(context.local(), Returns42).ToLocalChecked();
23616 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
23617 : CompileRun(
23618 : "function x_wrap() {\n"
23619 : " for (var i = 0; i < 5; i++) {\n"
23620 : " x(1,2,3);\n"
23621 : " }\n"
23622 : "}\n"
23623 : "x_wrap();\n"
23624 : "%OptimizeFunctionOnNextCall(x_wrap);"
23625 5 : "x_wrap();\n");
23626 5 : }
23627 :
23628 :
23629 50 : static void ReturnsSymbolCallback(
23630 100 : const v8::FunctionCallbackInfo<v8::Value>& info) {
23631 100 : info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
23632 50 : }
23633 :
23634 :
23635 25880 : TEST(ApiCallbackCanReturnSymbols) {
23636 5 : i::FLAG_allow_natives_syntax = true;
23637 5 : LocalContext context;
23638 5 : v8::Isolate* isolate = context->GetIsolate();
23639 10 : v8::HandleScope scope(isolate);
23640 5 : Local<Object> global = context->Global();
23641 : Local<v8::Function> function =
23642 10 : Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
23643 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
23644 : CompileRun(
23645 : "function x_wrap() {\n"
23646 : " for (var i = 0; i < 5; i++) {\n"
23647 : " x();\n"
23648 : " }\n"
23649 : "}\n"
23650 : "x_wrap();\n"
23651 : "%OptimizeFunctionOnNextCall(x_wrap);"
23652 5 : "x_wrap();\n");
23653 5 : }
23654 :
23655 :
23656 25880 : TEST(EmptyApiCallback) {
23657 5 : LocalContext context;
23658 5 : auto isolate = context->GetIsolate();
23659 10 : v8::HandleScope scope(isolate);
23660 5 : auto global = context->Global();
23661 5 : auto function = FunctionTemplate::New(isolate)
23662 15 : ->GetFunction(context.local())
23663 5 : .ToLocalChecked();
23664 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
23665 :
23666 : auto result = CompileRun("x()");
23667 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23668 :
23669 : result = CompileRun("x(1,2,3)");
23670 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23671 :
23672 : result = CompileRun("x.call(undefined)");
23673 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23674 :
23675 : result = CompileRun("x.call(null)");
23676 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23677 :
23678 : result = CompileRun("7 + x.call(3) + 11");
23679 5 : CHECK(result->IsInt32());
23680 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23681 :
23682 : result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
23683 5 : CHECK(result->IsInt32());
23684 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23685 :
23686 : result = CompileRun("var y = []; x.call(y)");
23687 5 : CHECK(result->IsArray());
23688 :
23689 : result = CompileRun("x.call(y, 1, 2, 3, 4)");
23690 10 : CHECK(result->IsArray());
23691 5 : }
23692 :
23693 :
23694 25880 : TEST(SimpleSignatureCheck) {
23695 5 : LocalContext context;
23696 5 : auto isolate = context->GetIsolate();
23697 10 : v8::HandleScope scope(isolate);
23698 5 : auto global = context->Global();
23699 5 : auto sig_obj = FunctionTemplate::New(isolate);
23700 5 : auto sig = v8::Signature::New(isolate, sig_obj);
23701 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23702 : global->Set(context.local(), v8_str("sig_obj"),
23703 25 : sig_obj->GetFunction(context.local()).ToLocalChecked())
23704 10 : .FromJust();
23705 : global->Set(context.local(), v8_str("x"),
23706 25 : x->GetFunction(context.local()).ToLocalChecked())
23707 10 : .FromJust();
23708 : CompileRun("var s = new sig_obj();");
23709 : {
23710 5 : TryCatch try_catch(isolate);
23711 : CompileRun("x()");
23712 5 : CHECK(try_catch.HasCaught());
23713 : }
23714 : {
23715 5 : TryCatch try_catch(isolate);
23716 : CompileRun("x.call(1)");
23717 5 : CHECK(try_catch.HasCaught());
23718 : }
23719 : {
23720 5 : TryCatch try_catch(isolate);
23721 : auto result = CompileRun("s.x = x; s.x()");
23722 5 : CHECK(!try_catch.HasCaught());
23723 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23724 : }
23725 : {
23726 5 : TryCatch try_catch(isolate);
23727 : auto result = CompileRun("x.call(s)");
23728 5 : CHECK(!try_catch.HasCaught());
23729 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23730 5 : }
23731 5 : }
23732 :
23733 :
23734 25880 : TEST(ChainSignatureCheck) {
23735 5 : LocalContext context;
23736 5 : auto isolate = context->GetIsolate();
23737 10 : v8::HandleScope scope(isolate);
23738 5 : auto global = context->Global();
23739 5 : auto sig_obj = FunctionTemplate::New(isolate);
23740 5 : auto sig = v8::Signature::New(isolate, sig_obj);
23741 25 : for (int i = 0; i < 4; ++i) {
23742 20 : auto temp = FunctionTemplate::New(isolate);
23743 20 : temp->Inherit(sig_obj);
23744 : sig_obj = temp;
23745 : }
23746 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23747 : global->Set(context.local(), v8_str("sig_obj"),
23748 20 : sig_obj->GetFunction(context.local()).ToLocalChecked())
23749 10 : .FromJust();
23750 : global->Set(context.local(), v8_str("x"),
23751 25 : x->GetFunction(context.local()).ToLocalChecked())
23752 10 : .FromJust();
23753 : CompileRun("var s = new sig_obj();");
23754 : {
23755 5 : TryCatch try_catch(isolate);
23756 : CompileRun("x()");
23757 5 : CHECK(try_catch.HasCaught());
23758 : }
23759 : {
23760 5 : TryCatch try_catch(isolate);
23761 : CompileRun("x.call(1)");
23762 5 : CHECK(try_catch.HasCaught());
23763 : }
23764 : {
23765 5 : TryCatch try_catch(isolate);
23766 : auto result = CompileRun("s.x = x; s.x()");
23767 5 : CHECK(!try_catch.HasCaught());
23768 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23769 : }
23770 : {
23771 5 : TryCatch try_catch(isolate);
23772 : auto result = CompileRun("x.call(s)");
23773 5 : CHECK(!try_catch.HasCaught());
23774 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23775 5 : }
23776 5 : }
23777 :
23778 :
23779 : static const char* last_event_message;
23780 : static int last_event_status;
23781 10 : void StoringEventLoggerCallback(const char* message, int status) {
23782 10 : last_event_message = message;
23783 10 : last_event_status = status;
23784 10 : }
23785 :
23786 :
23787 25880 : TEST(EventLogging) {
23788 5 : v8::Isolate* isolate = CcTest::isolate();
23789 5 : isolate->SetEventLogger(StoringEventLoggerCallback);
23790 : v8::internal::HistogramTimer histogramTimer(
23791 : "V8.Test", 0, 10000, v8::internal::HistogramTimerResolution::MILLISECOND,
23792 : 50, reinterpret_cast<v8::internal::Isolate*>(isolate)->counters());
23793 : histogramTimer.Start();
23794 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23795 5 : CHECK_EQ(0, last_event_status);
23796 : histogramTimer.Stop();
23797 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23798 5 : CHECK_EQ(1, last_event_status);
23799 5 : }
23800 :
23801 25880 : TEST(PropertyDescriptor) {
23802 5 : LocalContext context;
23803 5 : v8::Isolate* isolate = context->GetIsolate();
23804 10 : v8::HandleScope scope(isolate);
23805 :
23806 : { // empty descriptor
23807 5 : v8::PropertyDescriptor desc;
23808 5 : CHECK(!desc.has_value());
23809 5 : CHECK(!desc.has_set());
23810 5 : CHECK(!desc.has_get());
23811 5 : CHECK(!desc.has_enumerable());
23812 5 : CHECK(!desc.has_configurable());
23813 5 : CHECK(!desc.has_writable());
23814 : }
23815 : {
23816 : // data descriptor
23817 5 : v8::PropertyDescriptor desc(v8_num(42));
23818 5 : desc.set_enumerable(false);
23819 10 : CHECK(desc.value() == v8_num(42));
23820 5 : CHECK(desc.has_value());
23821 5 : CHECK(!desc.has_set());
23822 5 : CHECK(!desc.has_get());
23823 5 : CHECK(desc.has_enumerable());
23824 5 : CHECK(!desc.enumerable());
23825 5 : CHECK(!desc.has_configurable());
23826 5 : CHECK(!desc.has_writable());
23827 : }
23828 : {
23829 : // data descriptor
23830 5 : v8::PropertyDescriptor desc(v8_num(42));
23831 5 : desc.set_configurable(true);
23832 10 : CHECK(desc.value() == v8_num(42));
23833 5 : CHECK(desc.has_value());
23834 5 : CHECK(!desc.has_set());
23835 5 : CHECK(!desc.has_get());
23836 5 : CHECK(desc.has_configurable());
23837 5 : CHECK(desc.configurable());
23838 5 : CHECK(!desc.has_enumerable());
23839 5 : CHECK(!desc.has_writable());
23840 : }
23841 : {
23842 : // data descriptor
23843 5 : v8::PropertyDescriptor desc(v8_num(42));
23844 5 : desc.set_configurable(false);
23845 10 : CHECK(desc.value() == v8_num(42));
23846 5 : CHECK(desc.has_value());
23847 5 : CHECK(!desc.has_set());
23848 5 : CHECK(!desc.has_get());
23849 5 : CHECK(desc.has_configurable());
23850 5 : CHECK(!desc.configurable());
23851 5 : CHECK(!desc.has_enumerable());
23852 5 : CHECK(!desc.has_writable());
23853 : }
23854 : {
23855 : // data descriptor
23856 5 : v8::PropertyDescriptor desc(v8_num(42), false);
23857 10 : CHECK(desc.value() == v8_num(42));
23858 5 : CHECK(desc.has_value());
23859 5 : CHECK(!desc.has_set());
23860 5 : CHECK(!desc.has_get());
23861 5 : CHECK(!desc.has_enumerable());
23862 5 : CHECK(!desc.has_configurable());
23863 5 : CHECK(desc.has_writable());
23864 5 : CHECK(!desc.writable());
23865 : }
23866 : {
23867 : // data descriptor
23868 5 : v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true);
23869 5 : CHECK(!desc.has_value());
23870 5 : CHECK(!desc.has_set());
23871 5 : CHECK(!desc.has_get());
23872 5 : CHECK(!desc.has_enumerable());
23873 5 : CHECK(!desc.has_configurable());
23874 5 : CHECK(desc.has_writable());
23875 5 : CHECK(desc.writable());
23876 : }
23877 : {
23878 : // accessor descriptor
23879 : CompileRun("var set = function() {return 43;};");
23880 :
23881 : v8::Local<v8::Function> set =
23882 : v8::Local<v8::Function>::Cast(context->Global()
23883 20 : ->Get(context.local(), v8_str("set"))
23884 5 : .ToLocalChecked());
23885 5 : v8::PropertyDescriptor desc(v8::Undefined(isolate), set);
23886 5 : desc.set_configurable(false);
23887 5 : CHECK(!desc.has_value());
23888 5 : CHECK(desc.has_get());
23889 10 : CHECK(desc.get() == v8::Undefined(isolate));
23890 5 : CHECK(desc.has_set());
23891 10 : CHECK(desc.set() == set);
23892 5 : CHECK(!desc.has_enumerable());
23893 5 : CHECK(desc.has_configurable());
23894 5 : CHECK(!desc.configurable());
23895 5 : CHECK(!desc.has_writable());
23896 : }
23897 : {
23898 : // accessor descriptor with Proxy
23899 : CompileRun(
23900 : "var set = new Proxy(function() {}, {});"
23901 : "var get = undefined;");
23902 :
23903 : v8::Local<v8::Value> get =
23904 : v8::Local<v8::Value>::Cast(context->Global()
23905 20 : ->Get(context.local(), v8_str("get"))
23906 10 : .ToLocalChecked());
23907 : v8::Local<v8::Function> set =
23908 : v8::Local<v8::Function>::Cast(context->Global()
23909 20 : ->Get(context.local(), v8_str("set"))
23910 5 : .ToLocalChecked());
23911 5 : v8::PropertyDescriptor desc(get, set);
23912 5 : desc.set_configurable(false);
23913 5 : CHECK(!desc.has_value());
23914 10 : CHECK(desc.get() == v8::Undefined(isolate));
23915 5 : CHECK(desc.has_get());
23916 10 : CHECK(desc.set() == set);
23917 5 : CHECK(desc.has_set());
23918 5 : CHECK(!desc.has_enumerable());
23919 5 : CHECK(desc.has_configurable());
23920 5 : CHECK(!desc.configurable());
23921 5 : CHECK(!desc.has_writable());
23922 : }
23923 : {
23924 : // accessor descriptor with empty function handle
23925 : v8::Local<v8::Function> get = v8::Local<v8::Function>();
23926 5 : v8::PropertyDescriptor desc(get, get);
23927 5 : CHECK(!desc.has_value());
23928 5 : CHECK(!desc.has_get());
23929 5 : CHECK(!desc.has_set());
23930 5 : CHECK(!desc.has_enumerable());
23931 5 : CHECK(!desc.has_configurable());
23932 5 : CHECK(!desc.has_writable());
23933 5 : }
23934 5 : }
23935 :
23936 25880 : TEST(Promises) {
23937 5 : LocalContext context;
23938 5 : v8::Isolate* isolate = context->GetIsolate();
23939 10 : v8::HandleScope scope(isolate);
23940 :
23941 : // Creation.
23942 : Local<v8::Promise::Resolver> pr =
23943 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23944 : Local<v8::Promise::Resolver> rr =
23945 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23946 5 : Local<v8::Promise> p = pr->GetPromise();
23947 5 : Local<v8::Promise> r = rr->GetPromise();
23948 :
23949 : // IsPromise predicate.
23950 5 : CHECK(p->IsPromise());
23951 5 : CHECK(r->IsPromise());
23952 5 : Local<Value> o = v8::Object::New(isolate);
23953 5 : CHECK(!o->IsPromise());
23954 :
23955 : // Resolution and rejection.
23956 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
23957 5 : CHECK(p->IsPromise());
23958 15 : rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
23959 10 : CHECK(r->IsPromise());
23960 5 : }
23961 :
23962 : // Promise.Then(on_fulfilled)
23963 25880 : TEST(PromiseThen) {
23964 5 : LocalContext context;
23965 5 : v8::Isolate* isolate = context->GetIsolate();
23966 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
23967 10 : v8::HandleScope scope(isolate);
23968 5 : Local<Object> global = context->Global();
23969 :
23970 : // Creation.
23971 : Local<v8::Promise::Resolver> pr =
23972 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23973 : Local<v8::Promise::Resolver> qr =
23974 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23975 5 : Local<v8::Promise> p = pr->GetPromise();
23976 5 : Local<v8::Promise> q = qr->GetPromise();
23977 :
23978 5 : CHECK(p->IsPromise());
23979 5 : CHECK(q->IsPromise());
23980 :
23981 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
23982 10 : qr->Resolve(context.local(), p).FromJust();
23983 :
23984 : // Chaining non-pending promises.
23985 : CompileRun(
23986 : "var x1 = 0;\n"
23987 : "var x2 = 0;\n"
23988 : "function f1(x) { x1 = x; return x+1 };\n"
23989 : "function f2(x) { x2 = x; return x+1 };\n");
23990 : Local<Function> f1 = Local<Function>::Cast(
23991 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
23992 : Local<Function> f2 = Local<Function>::Cast(
23993 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
23994 :
23995 : // Then
23996 : CompileRun("x1 = x2 = 0;");
23997 5 : q->Then(context.local(), f1).ToLocalChecked();
23998 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
23999 : .ToLocalChecked()
24000 : ->Int32Value(context.local())
24001 : .FromJust());
24002 5 : isolate->RunMicrotasks();
24003 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24004 : .ToLocalChecked()
24005 : ->Int32Value(context.local())
24006 : .FromJust());
24007 :
24008 : // Then
24009 : CompileRun("x1 = x2 = 0;");
24010 5 : pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24011 5 : qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24012 :
24013 10 : qr->Resolve(context.local(), pr).FromJust();
24014 : qr->GetPromise()
24015 10 : ->Then(context.local(), f1)
24016 5 : .ToLocalChecked()
24017 5 : ->Then(context.local(), f2)
24018 5 : .ToLocalChecked();
24019 :
24020 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24021 : .ToLocalChecked()
24022 : ->Int32Value(context.local())
24023 : .FromJust());
24024 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24025 : .ToLocalChecked()
24026 : ->Int32Value(context.local())
24027 : .FromJust());
24028 5 : isolate->RunMicrotasks();
24029 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24030 : .ToLocalChecked()
24031 : ->Int32Value(context.local())
24032 : .FromJust());
24033 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24034 : .ToLocalChecked()
24035 : ->Int32Value(context.local())
24036 : .FromJust());
24037 :
24038 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
24039 :
24040 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24041 : .ToLocalChecked()
24042 : ->Int32Value(context.local())
24043 : .FromJust());
24044 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24045 : .ToLocalChecked()
24046 : ->Int32Value(context.local())
24047 : .FromJust());
24048 5 : isolate->RunMicrotasks();
24049 20 : CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
24050 : .ToLocalChecked()
24051 : ->Int32Value(context.local())
24052 : .FromJust());
24053 20 : CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
24054 : .ToLocalChecked()
24055 : ->Int32Value(context.local())
24056 5 : .FromJust());
24057 5 : }
24058 :
24059 : // Promise.Then(on_fulfilled, on_rejected)
24060 25880 : TEST(PromiseThen2) {
24061 5 : LocalContext context;
24062 5 : v8::Isolate* isolate = context->GetIsolate();
24063 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24064 10 : v8::HandleScope scope(isolate);
24065 5 : Local<Object> global = context->Global();
24066 :
24067 : // Creation.
24068 : Local<v8::Promise::Resolver> pr =
24069 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24070 5 : Local<v8::Promise> p = pr->GetPromise();
24071 :
24072 5 : CHECK(p->IsPromise());
24073 :
24074 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24075 :
24076 : // Chaining non-pending promises.
24077 : CompileRun(
24078 : "var x1 = 0;\n"
24079 : "var x2 = 0;\n"
24080 : "function f1(x) { x1 = x; return x+1 };\n"
24081 : "function f2(x) { x2 = x; return x+1 };\n"
24082 : "function f3(x) { throw x + 100 };\n");
24083 : Local<Function> f1 = Local<Function>::Cast(
24084 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24085 : Local<Function> f2 = Local<Function>::Cast(
24086 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24087 : Local<Function> f3 = Local<Function>::Cast(
24088 15 : global->Get(context.local(), v8_str("f3")).ToLocalChecked());
24089 :
24090 : // Then
24091 : CompileRun("x1 = x2 = 0;");
24092 5 : Local<v8::Promise> a = p->Then(context.local(), f1, f2).ToLocalChecked();
24093 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24094 : .ToLocalChecked()
24095 : ->Int32Value(context.local())
24096 : .FromJust());
24097 5 : isolate->RunMicrotasks();
24098 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24099 : .ToLocalChecked()
24100 : ->Int32Value(context.local())
24101 : .FromJust());
24102 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24103 : .ToLocalChecked()
24104 : ->Int32Value(context.local())
24105 : .FromJust());
24106 :
24107 5 : Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
24108 5 : isolate->RunMicrotasks();
24109 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24110 : .ToLocalChecked()
24111 : ->Int32Value(context.local())
24112 : .FromJust());
24113 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24114 : .ToLocalChecked()
24115 : ->Int32Value(context.local())
24116 : .FromJust());
24117 :
24118 5 : Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
24119 5 : isolate->RunMicrotasks();
24120 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24121 : .ToLocalChecked()
24122 : ->Int32Value(context.local())
24123 : .FromJust());
24124 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24125 : .ToLocalChecked()
24126 : ->Int32Value(context.local())
24127 : .FromJust());
24128 :
24129 5 : v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
24130 5 : isolate->RunMicrotasks();
24131 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24132 : .ToLocalChecked()
24133 : ->Int32Value(context.local())
24134 : .FromJust());
24135 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24136 : .ToLocalChecked()
24137 : ->Int32Value(context.local())
24138 : .FromJust());
24139 :
24140 5 : v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
24141 5 : isolate->RunMicrotasks();
24142 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24143 : .ToLocalChecked()
24144 : ->Int32Value(context.local())
24145 : .FromJust());
24146 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24147 : .ToLocalChecked()
24148 : ->Int32Value(context.local())
24149 : .FromJust());
24150 :
24151 5 : v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
24152 5 : isolate->RunMicrotasks();
24153 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24154 : .ToLocalChecked()
24155 : ->Int32Value(context.local())
24156 : .FromJust());
24157 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24158 : .ToLocalChecked()
24159 : ->Int32Value(context.local())
24160 : .FromJust());
24161 :
24162 5 : f->Then(context.local(), f1, f2).ToLocalChecked();
24163 5 : isolate->RunMicrotasks();
24164 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24165 : .ToLocalChecked()
24166 : ->Int32Value(context.local())
24167 : .FromJust());
24168 20 : CHECK_EQ(304, global->Get(context.local(), v8_str("x2"))
24169 : .ToLocalChecked()
24170 : ->Int32Value(context.local())
24171 5 : .FromJust());
24172 5 : }
24173 :
24174 25880 : TEST(PromiseStateAndValue) {
24175 5 : LocalContext context;
24176 5 : v8::Isolate* isolate = context->GetIsolate();
24177 10 : v8::HandleScope scope(isolate);
24178 : v8::Local<v8::Value> result = CompileRun(
24179 : "var resolver;"
24180 : "new Promise((res, rej) => { resolver = res; })");
24181 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24182 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24183 :
24184 : CompileRun("resolver('fulfilled')");
24185 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24186 10 : CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24187 :
24188 : result = CompileRun("Promise.reject('rejected')");
24189 : promise = v8::Local<v8::Promise>::Cast(result);
24190 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24191 15 : CHECK(v8_str("rejected")->SameValue(promise->Result()));
24192 5 : }
24193 :
24194 25880 : TEST(ResolvedPromiseReFulfill) {
24195 5 : LocalContext context;
24196 5 : v8::Isolate* isolate = context->GetIsolate();
24197 10 : v8::HandleScope scope(isolate);
24198 : v8::Local<v8::String> value1 =
24199 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24200 5 : .ToLocalChecked();
24201 : v8::Local<v8::String> value2 =
24202 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24203 5 : .ToLocalChecked();
24204 :
24205 : v8::Local<v8::Promise::Resolver> resolver =
24206 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24207 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24208 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24209 :
24210 10 : resolver->Resolve(context.local(), value1).ToChecked();
24211 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24212 10 : CHECK_EQ(promise->Result(), value1);
24213 :
24214 : // This should be a no-op.
24215 10 : resolver->Resolve(context.local(), value2).ToChecked();
24216 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24217 10 : CHECK_EQ(promise->Result(), value1);
24218 :
24219 : // This should be a no-op.
24220 10 : resolver->Reject(context.local(), value2).ToChecked();
24221 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24222 15 : CHECK_EQ(promise->Result(), value1);
24223 5 : }
24224 :
24225 25880 : TEST(RejectedPromiseReFulfill) {
24226 5 : LocalContext context;
24227 5 : v8::Isolate* isolate = context->GetIsolate();
24228 10 : v8::HandleScope scope(isolate);
24229 : v8::Local<v8::String> value1 =
24230 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24231 5 : .ToLocalChecked();
24232 : v8::Local<v8::String> value2 =
24233 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24234 5 : .ToLocalChecked();
24235 :
24236 : v8::Local<v8::Promise::Resolver> resolver =
24237 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24238 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24239 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24240 :
24241 10 : resolver->Reject(context.local(), value1).ToChecked();
24242 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24243 10 : CHECK_EQ(promise->Result(), value1);
24244 :
24245 : // This should be a no-op.
24246 10 : resolver->Reject(context.local(), value2).ToChecked();
24247 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24248 10 : CHECK_EQ(promise->Result(), value1);
24249 :
24250 : // This should be a no-op.
24251 10 : resolver->Resolve(context.local(), value2).ToChecked();
24252 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24253 15 : CHECK_EQ(promise->Result(), value1);
24254 5 : }
24255 :
24256 25875 : TEST(DisallowJavascriptExecutionScope) {
24257 0 : LocalContext context;
24258 0 : v8::Isolate* isolate = context->GetIsolate();
24259 0 : v8::HandleScope scope(isolate);
24260 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24261 0 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24262 0 : CompileRun("2+2");
24263 0 : }
24264 :
24265 25880 : TEST(AllowJavascriptExecutionScope) {
24266 5 : LocalContext context;
24267 5 : v8::Isolate* isolate = context->GetIsolate();
24268 10 : v8::HandleScope scope(isolate);
24269 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24270 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24271 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24272 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24273 5 : { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
24274 5 : CompileRun("1+1");
24275 5 : }
24276 5 : }
24277 :
24278 25880 : TEST(ThrowOnJavascriptExecution) {
24279 5 : LocalContext context;
24280 5 : v8::Isolate* isolate = context->GetIsolate();
24281 10 : v8::HandleScope scope(isolate);
24282 10 : v8::TryCatch try_catch(isolate);
24283 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24284 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24285 : CompileRun("1+1");
24286 10 : CHECK(try_catch.HasCaught());
24287 5 : }
24288 :
24289 : namespace {
24290 :
24291 : class MockPlatform : public TestPlatform {
24292 : public:
24293 10 : MockPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {
24294 : // Now that it's completely constructed, make this the current platform.
24295 5 : i::V8::SetPlatformForTesting(this);
24296 5 : }
24297 10 : ~MockPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
24298 :
24299 : bool dump_without_crashing_called() const {
24300 : return dump_without_crashing_called_;
24301 : }
24302 :
24303 5 : void DumpWithoutCrashing() override { dump_without_crashing_called_ = true; }
24304 :
24305 : private:
24306 : v8::Platform* old_platform_;
24307 : bool dump_without_crashing_called_ = false;
24308 : };
24309 :
24310 : } // namespace
24311 :
24312 25880 : TEST(DumpOnJavascriptExecution) {
24313 5 : MockPlatform platform;
24314 :
24315 10 : LocalContext context;
24316 5 : v8::Isolate* isolate = context->GetIsolate();
24317 10 : v8::HandleScope scope(isolate);
24318 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24319 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::DUMP_ON_FAILURE);
24320 5 : CHECK(!platform.dump_without_crashing_called());
24321 : CompileRun("1+1");
24322 10 : CHECK(platform.dump_without_crashing_called());
24323 5 : }
24324 :
24325 25880 : TEST(Regress354123) {
24326 5 : LocalContext current;
24327 5 : v8::Isolate* isolate = current->GetIsolate();
24328 10 : v8::HandleScope scope(isolate);
24329 :
24330 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
24331 5 : templ->SetAccessCheckCallback(AccessCounter);
24332 30 : CHECK(current->Global()
24333 : ->Set(current.local(), v8_str("friend"),
24334 : templ->NewInstance(current.local()).ToLocalChecked())
24335 : .FromJust());
24336 :
24337 : // Test access using __proto__ from the prototype chain.
24338 5 : access_count = 0;
24339 : CompileRun("friend.__proto__ = {};");
24340 5 : CHECK_EQ(2, access_count);
24341 : CompileRun("friend.__proto__;");
24342 5 : CHECK_EQ(4, access_count);
24343 :
24344 : // Test access using __proto__ as a hijacked function (A).
24345 5 : access_count = 0;
24346 : CompileRun("var p = Object.prototype;"
24347 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
24348 : "f.call(friend, {});");
24349 5 : CHECK_EQ(1, access_count);
24350 : CompileRun("var p = Object.prototype;"
24351 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
24352 : "f.call(friend);");
24353 5 : CHECK_EQ(2, access_count);
24354 :
24355 : // Test access using __proto__ as a hijacked function (B).
24356 5 : access_count = 0;
24357 : CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
24358 : "f.call(friend, {});");
24359 5 : CHECK_EQ(1, access_count);
24360 : CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
24361 : "f.call(friend);");
24362 5 : CHECK_EQ(2, access_count);
24363 :
24364 : // Test access using Object.setPrototypeOf reflective method.
24365 5 : access_count = 0;
24366 : CompileRun("Object.setPrototypeOf(friend, {});");
24367 5 : CHECK_EQ(1, access_count);
24368 : CompileRun("Object.getPrototypeOf(friend);");
24369 10 : CHECK_EQ(2, access_count);
24370 5 : }
24371 :
24372 :
24373 25880 : TEST(CaptureStackTraceForStackOverflow) {
24374 5 : v8::internal::FLAG_stack_size = 150;
24375 5 : LocalContext current;
24376 5 : v8::Isolate* isolate = current->GetIsolate();
24377 10 : v8::HandleScope scope(isolate);
24378 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
24379 5 : v8::StackTrace::kDetailed);
24380 10 : v8::TryCatch try_catch(isolate);
24381 : CompileRun("(function f(x) { f(x+1); })(0)");
24382 10 : CHECK(try_catch.HasCaught());
24383 5 : }
24384 :
24385 : namespace {
24386 5 : bool ValueEqualsString(v8::Isolate* isolate, Local<Value> lhs,
24387 : const char* rhs) {
24388 5 : CHECK(!lhs.IsEmpty());
24389 5 : CHECK(lhs->IsString());
24390 5 : String::Utf8Value utf8_lhs(isolate, lhs);
24391 5 : return strcmp(rhs, *utf8_lhs) == 0;
24392 : }
24393 : } // namespace
24394 :
24395 25880 : TEST(ScriptNameAndLineNumber) {
24396 5 : LocalContext env;
24397 5 : v8::Isolate* isolate = env->GetIsolate();
24398 10 : v8::HandleScope scope(isolate);
24399 : const char* url = "http://www.foo.com/foo.js";
24400 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24401 5 : v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
24402 :
24403 : Local<Script> script =
24404 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24405 10 : CHECK(ValueEqualsString(isolate, script->GetUnboundScript()->GetScriptName(),
24406 : url));
24407 :
24408 10 : int line_number = script->GetUnboundScript()->GetLineNumber(0);
24409 10 : CHECK_EQ(13, line_number);
24410 5 : }
24411 :
24412 25880 : TEST(ScriptPositionInfo) {
24413 5 : LocalContext env;
24414 5 : v8::Isolate* isolate = env->GetIsolate();
24415 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
24416 10 : v8::HandleScope scope(isolate);
24417 : const char* url = "http://www.foo.com/foo.js";
24418 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24419 : v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
24420 : "var bar;\n"
24421 : "var fisk = foo + bar;\n"),
24422 5 : origin);
24423 : Local<Script> script =
24424 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24425 :
24426 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
24427 10 : v8::Utils::OpenHandle(*script->GetUnboundScript()));
24428 10 : CHECK(obj->script()->IsScript());
24429 :
24430 10 : i::Handle<i::Script> script1(i::Script::cast(obj->script()), i_isolate);
24431 :
24432 : v8::internal::Script::PositionInfo info;
24433 :
24434 15 : for (int i = 0; i < 2; ++i) {
24435 : // With offset.
24436 :
24437 : // Behave as if 0 was passed if position is negative.
24438 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
24439 10 : CHECK_EQ(13, info.line);
24440 10 : CHECK_EQ(0, info.column);
24441 10 : CHECK_EQ(0, info.line_start);
24442 10 : CHECK_EQ(8, info.line_end);
24443 :
24444 10 : CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
24445 10 : CHECK_EQ(13, info.line);
24446 10 : CHECK_EQ(0, info.column);
24447 10 : CHECK_EQ(0, info.line_start);
24448 10 : CHECK_EQ(8, info.line_end);
24449 :
24450 10 : CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
24451 10 : CHECK_EQ(13, info.line);
24452 10 : CHECK_EQ(8, info.column);
24453 10 : CHECK_EQ(0, info.line_start);
24454 10 : CHECK_EQ(8, info.line_end);
24455 :
24456 10 : CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
24457 10 : CHECK_EQ(14, info.line);
24458 10 : CHECK_EQ(0, info.column);
24459 10 : CHECK_EQ(9, info.line_start);
24460 10 : CHECK_EQ(17, info.line_end);
24461 :
24462 : // Fail when position is larger than script size.
24463 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
24464 :
24465 : // Without offset.
24466 :
24467 : // Behave as if 0 was passed if position is negative.
24468 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
24469 10 : CHECK_EQ(0, info.line);
24470 10 : CHECK_EQ(0, info.column);
24471 10 : CHECK_EQ(0, info.line_start);
24472 10 : CHECK_EQ(8, info.line_end);
24473 :
24474 10 : CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
24475 10 : CHECK_EQ(0, info.line);
24476 10 : CHECK_EQ(0, info.column);
24477 10 : CHECK_EQ(0, info.line_start);
24478 10 : CHECK_EQ(8, info.line_end);
24479 :
24480 10 : CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
24481 10 : CHECK_EQ(0, info.line);
24482 10 : CHECK_EQ(8, info.column);
24483 10 : CHECK_EQ(0, info.line_start);
24484 10 : CHECK_EQ(8, info.line_end);
24485 :
24486 10 : CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
24487 10 : CHECK_EQ(1, info.line);
24488 10 : CHECK_EQ(0, info.column);
24489 10 : CHECK_EQ(9, info.line_start);
24490 10 : CHECK_EQ(17, info.line_end);
24491 :
24492 : // Fail when position is larger than script size.
24493 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
24494 :
24495 10 : i::Script::InitLineEnds(script1);
24496 5 : }
24497 5 : }
24498 :
24499 155 : void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
24500 : const char* expected_source_url,
24501 : const char* expected_source_mapping_url) {
24502 155 : if (expected_source_url != nullptr) {
24503 : v8::String::Utf8Value url(isolate,
24504 70 : script->GetUnboundScript()->GetSourceURL());
24505 35 : CHECK_EQ(0, strcmp(expected_source_url, *url));
24506 : } else {
24507 360 : CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24508 : }
24509 155 : if (expected_source_mapping_url != nullptr) {
24510 : v8::String::Utf8Value url(
24511 60 : isolate, script->GetUnboundScript()->GetSourceMappingURL());
24512 30 : CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
24513 : } else {
24514 375 : CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24515 : }
24516 155 : }
24517 :
24518 70 : void SourceURLHelper(v8::Isolate* isolate, const char* source,
24519 : const char* expected_source_url,
24520 : const char* expected_source_mapping_url) {
24521 70 : Local<Script> script = v8_compile(source);
24522 : CheckMagicComments(isolate, script, expected_source_url,
24523 70 : expected_source_mapping_url);
24524 70 : }
24525 :
24526 :
24527 25880 : TEST(ScriptSourceURLAndSourceMappingURL) {
24528 5 : LocalContext env;
24529 5 : v8::Isolate* isolate = env->GetIsolate();
24530 10 : v8::HandleScope scope(isolate);
24531 : SourceURLHelper(isolate,
24532 : "function foo() {}\n"
24533 : "//# sourceURL=bar1.js\n",
24534 5 : "bar1.js", nullptr);
24535 : SourceURLHelper(isolate,
24536 : "function foo() {}\n"
24537 : "//# sourceMappingURL=bar2.js\n",
24538 5 : nullptr, "bar2.js");
24539 :
24540 : // Both sourceURL and sourceMappingURL.
24541 : SourceURLHelper(isolate,
24542 : "function foo() {}\n"
24543 : "//# sourceURL=bar3.js\n"
24544 : "//# sourceMappingURL=bar4.js\n",
24545 5 : "bar3.js", "bar4.js");
24546 :
24547 : // Two source URLs; the first one is ignored.
24548 : SourceURLHelper(isolate,
24549 : "function foo() {}\n"
24550 : "//# sourceURL=ignoreme.js\n"
24551 : "//# sourceURL=bar5.js\n",
24552 5 : "bar5.js", nullptr);
24553 : SourceURLHelper(isolate,
24554 : "function foo() {}\n"
24555 : "//# sourceMappingURL=ignoreme.js\n"
24556 : "//# sourceMappingURL=bar6.js\n",
24557 5 : nullptr, "bar6.js");
24558 :
24559 : // SourceURL or sourceMappingURL in the middle of the script.
24560 : SourceURLHelper(isolate,
24561 : "function foo() {}\n"
24562 : "//# sourceURL=bar7.js\n"
24563 : "function baz() {}\n",
24564 5 : "bar7.js", nullptr);
24565 : SourceURLHelper(isolate,
24566 : "function foo() {}\n"
24567 : "//# sourceMappingURL=bar8.js\n"
24568 : "function baz() {}\n",
24569 5 : nullptr, "bar8.js");
24570 :
24571 : // Too much whitespace.
24572 : SourceURLHelper(isolate,
24573 : "function foo() {}\n"
24574 : "//# sourceURL=bar9.js\n"
24575 : "//# sourceMappingURL=bar10.js\n",
24576 5 : nullptr, nullptr);
24577 : SourceURLHelper(isolate,
24578 : "function foo() {}\n"
24579 : "//# sourceURL =bar11.js\n"
24580 : "//# sourceMappingURL =bar12.js\n",
24581 5 : nullptr, nullptr);
24582 :
24583 : // Disallowed characters in value.
24584 : SourceURLHelper(isolate,
24585 : "function foo() {}\n"
24586 : "//# sourceURL=bar13 .js \n"
24587 : "//# sourceMappingURL=bar14 .js \n",
24588 5 : nullptr, nullptr);
24589 : SourceURLHelper(isolate,
24590 : "function foo() {}\n"
24591 : "//# sourceURL=bar15\t.js \n"
24592 : "//# sourceMappingURL=bar16\t.js \n",
24593 5 : nullptr, nullptr);
24594 : SourceURLHelper(isolate,
24595 : "function foo() {}\n"
24596 : "//# sourceURL=bar17'.js \n"
24597 : "//# sourceMappingURL=bar18'.js \n",
24598 5 : nullptr, nullptr);
24599 : SourceURLHelper(isolate,
24600 : "function foo() {}\n"
24601 : "//# sourceURL=bar19\".js \n"
24602 : "//# sourceMappingURL=bar20\".js \n",
24603 5 : nullptr, nullptr);
24604 :
24605 : // Not too much whitespace.
24606 : SourceURLHelper(isolate,
24607 : "function foo() {}\n"
24608 : "//# sourceURL= bar21.js \n"
24609 : "//# sourceMappingURL= bar22.js \n",
24610 10 : "bar21.js", "bar22.js");
24611 5 : }
24612 :
24613 :
24614 25880 : TEST(GetOwnPropertyDescriptor) {
24615 5 : LocalContext env;
24616 5 : v8::Isolate* isolate = env->GetIsolate();
24617 10 : v8::HandleScope scope(isolate);
24618 : CompileRun(
24619 : "var x = { value : 13};"
24620 : "Object.defineProperty(x, 'p0', {value : 12});"
24621 : "Object.defineProperty(x, Symbol.toStringTag, {value: 'foo'});"
24622 : "Object.defineProperty(x, 'p1', {"
24623 : " set : function(value) { this.value = value; },"
24624 : " get : function() { return this.value; },"
24625 : "});");
24626 : Local<Object> x = Local<Object>::Cast(
24627 25 : env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
24628 : Local<Value> desc =
24629 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
24630 5 : .ToLocalChecked();
24631 5 : CHECK(desc->IsUndefined());
24632 : desc =
24633 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
24634 25 : CHECK(v8_num(12)
24635 : ->Equals(env.local(), Local<Object>::Cast(desc)
24636 : ->Get(env.local(), v8_str("value"))
24637 : .ToLocalChecked())
24638 : .FromJust());
24639 : desc =
24640 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
24641 : Local<Function> set =
24642 : Local<Function>::Cast(Local<Object>::Cast(desc)
24643 15 : ->Get(env.local(), v8_str("set"))
24644 5 : .ToLocalChecked());
24645 : Local<Function> get =
24646 : Local<Function>::Cast(Local<Object>::Cast(desc)
24647 15 : ->Get(env.local(), v8_str("get"))
24648 5 : .ToLocalChecked());
24649 20 : CHECK(v8_num(13)
24650 : ->Equals(env.local(),
24651 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24652 : .FromJust());
24653 5 : Local<Value> args[] = {v8_num(14)};
24654 10 : set->Call(env.local(), x, 1, args).ToLocalChecked();
24655 20 : CHECK(v8_num(14)
24656 : ->Equals(env.local(),
24657 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24658 : .FromJust());
24659 : desc =
24660 15 : x->GetOwnPropertyDescriptor(env.local(), Symbol::GetToStringTag(isolate))
24661 5 : .ToLocalChecked();
24662 25 : CHECK(v8_str("foo")
24663 : ->Equals(env.local(), Local<Object>::Cast(desc)
24664 : ->Get(env.local(), v8_str("value"))
24665 : .ToLocalChecked())
24666 5 : .FromJust());
24667 5 : }
24668 :
24669 :
24670 25880 : TEST(Regress411877) {
24671 5 : v8::Isolate* isolate = CcTest::isolate();
24672 5 : v8::HandleScope handle_scope(isolate);
24673 : v8::Local<v8::ObjectTemplate> object_template =
24674 5 : v8::ObjectTemplate::New(isolate);
24675 5 : object_template->SetAccessCheckCallback(AccessCounter);
24676 :
24677 5 : v8::Local<Context> context = Context::New(isolate);
24678 : v8::Context::Scope context_scope(context);
24679 :
24680 25 : CHECK(context->Global()
24681 : ->Set(context, v8_str("o"),
24682 : object_template->NewInstance(context).ToLocalChecked())
24683 : .FromJust());
24684 5 : CompileRun("Object.getOwnPropertyNames(o)");
24685 5 : }
24686 :
24687 :
24688 25880 : TEST(GetHiddenPropertyTableAfterAccessCheck) {
24689 5 : v8::Isolate* isolate = CcTest::isolate();
24690 5 : v8::HandleScope handle_scope(isolate);
24691 : v8::Local<v8::ObjectTemplate> object_template =
24692 5 : v8::ObjectTemplate::New(isolate);
24693 5 : object_template->SetAccessCheckCallback(AccessCounter);
24694 :
24695 5 : v8::Local<Context> context = Context::New(isolate);
24696 : v8::Context::Scope context_scope(context);
24697 :
24698 : v8::Local<v8::Object> obj =
24699 5 : object_template->NewInstance(context).ToLocalChecked();
24700 20 : obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
24701 15 : obj->Delete(context, v8_str("key")).FromJust();
24702 :
24703 : obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
24704 15 : v8_str("hidden value 2"))
24705 15 : .FromJust();
24706 5 : }
24707 :
24708 :
24709 25880 : TEST(Regress411793) {
24710 5 : v8::Isolate* isolate = CcTest::isolate();
24711 5 : v8::HandleScope handle_scope(isolate);
24712 : v8::Local<v8::ObjectTemplate> object_template =
24713 5 : v8::ObjectTemplate::New(isolate);
24714 5 : object_template->SetAccessCheckCallback(AccessCounter);
24715 :
24716 5 : v8::Local<Context> context = Context::New(isolate);
24717 : v8::Context::Scope context_scope(context);
24718 :
24719 25 : CHECK(context->Global()
24720 : ->Set(context, v8_str("o"),
24721 : object_template->NewInstance(context).ToLocalChecked())
24722 : .FromJust());
24723 : CompileRun(
24724 : "Object.defineProperty(o, 'key', "
24725 5 : " { get: function() {}, set: function() {} });");
24726 5 : }
24727 :
24728 210 : class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24729 : public:
24730 105 : explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24731 :
24732 405 : size_t GetMoreData(const uint8_t** src) override {
24733 : // Unlike in real use cases, this function will never block.
24734 405 : if (chunks_[index_] == nullptr) {
24735 : return 0;
24736 : }
24737 : // Copy the data, since the caller takes ownership of it.
24738 310 : size_t len = strlen(chunks_[index_]);
24739 : // We don't need to zero-terminate since we return the length.
24740 310 : uint8_t* copy = new uint8_t[len];
24741 310 : memcpy(copy, chunks_[index_], len);
24742 310 : *src = copy;
24743 310 : ++index_;
24744 310 : return len;
24745 : }
24746 :
24747 : // Helper for constructing a string from chunks (the compilation needs it
24748 : // too).
24749 105 : static char* FullSourceString(const char** chunks) {
24750 : size_t total_len = 0;
24751 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24752 330 : total_len += strlen(chunks[i]);
24753 : }
24754 105 : char* full_string = new char[total_len + 1];
24755 : size_t offset = 0;
24756 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24757 330 : size_t len = strlen(chunks[i]);
24758 330 : memcpy(full_string + offset, chunks[i], len);
24759 330 : offset += len;
24760 : }
24761 105 : full_string[total_len] = 0;
24762 105 : return full_string;
24763 : }
24764 :
24765 : private:
24766 : const char** chunks_;
24767 : unsigned index_;
24768 : };
24769 :
24770 :
24771 : // Helper function for running streaming tests.
24772 95 : void RunStreamingTest(const char** chunks,
24773 : v8::ScriptCompiler::StreamedSource::Encoding encoding =
24774 : v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24775 : bool expected_success = true,
24776 : const char* expected_source_url = nullptr,
24777 : const char* expected_source_mapping_url = nullptr) {
24778 95 : LocalContext env;
24779 95 : v8::Isolate* isolate = env->GetIsolate();
24780 190 : v8::HandleScope scope(isolate);
24781 190 : v8::TryCatch try_catch(isolate);
24782 :
24783 : v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
24784 285 : encoding);
24785 : v8::ScriptCompiler::ScriptStreamingTask* task =
24786 95 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24787 :
24788 : // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24789 : // task here in the main thread.
24790 95 : task->Run();
24791 95 : delete task;
24792 :
24793 : // Possible errors are only produced while compiling.
24794 95 : CHECK(!try_catch.HasCaught());
24795 :
24796 95 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
24797 95 : char* full_source = TestSourceStream::FullSourceString(chunks);
24798 : v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
24799 95 : env.local(), &source, v8_str(full_source), origin);
24800 95 : if (expected_success) {
24801 85 : CHECK(!script.IsEmpty());
24802 : v8::Local<Value> result(
24803 170 : script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
24804 : // All scripts are supposed to return the fixed value 13 when ran.
24805 170 : CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
24806 : CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
24807 85 : expected_source_mapping_url);
24808 : } else {
24809 10 : CHECK(script.IsEmpty());
24810 10 : CHECK(try_catch.HasCaught());
24811 : }
24812 190 : delete[] full_source;
24813 95 : }
24814 :
24815 25880 : TEST(StreamingSimpleScript) {
24816 : // This script is unrealistically small, since no one chunk is enough to fill
24817 : // the backing buffer of Scanner, let alone overflow it.
24818 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24819 5 : nullptr};
24820 5 : RunStreamingTest(chunks);
24821 5 : }
24822 :
24823 25880 : TEST(StreamingScriptConstantArray) {
24824 : // When run with Ignition, tests that the streaming parser canonicalizes
24825 : // handles so that they are only added to the constant pool array once.
24826 : const char* chunks[] = {
24827 : "var a = {};", "var b = {};", "var c = 'testing';",
24828 5 : "var d = 'testing';", "13;", nullptr};
24829 5 : RunStreamingTest(chunks);
24830 5 : }
24831 :
24832 25880 : TEST(StreamingScriptEvalShadowing) {
24833 : // When run with Ignition, tests that the streaming parser canonicalizes
24834 : // handles so the Variable::is_possibly_eval() is correct.
24835 : const char* chunk1 =
24836 : "(function() {\n"
24837 : " var y = 2;\n"
24838 : " return (function() {\n"
24839 : " eval('var y = 13;');\n"
24840 : " function g() {\n"
24841 : " return y\n"
24842 : " }\n"
24843 : " return g();\n"
24844 : " })()\n"
24845 : "})()\n";
24846 5 : const char* chunks[] = {chunk1, nullptr};
24847 5 : RunStreamingTest(chunks);
24848 5 : }
24849 :
24850 25880 : TEST(StreamingBiggerScript) {
24851 : const char* chunk1 =
24852 : "function foo() {\n"
24853 : " // Make this chunk sufficiently long so that it will overflow the\n"
24854 : " // backing buffer of the Scanner.\n"
24855 : " var i = 0;\n"
24856 : " var result = 0;\n"
24857 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24858 : " result = 0;\n"
24859 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24860 : " result = 0;\n"
24861 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24862 : " result = 0;\n"
24863 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24864 : " return result;\n"
24865 : "}\n";
24866 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
24867 5 : RunStreamingTest(chunks);
24868 5 : }
24869 :
24870 :
24871 25880 : TEST(StreamingScriptWithParseError) {
24872 : // Test that parse errors from streamed scripts are propagated correctly.
24873 : {
24874 : char chunk1[] =
24875 : " // This will result in a parse error.\n"
24876 5 : " var if else then foo";
24877 5 : char chunk2[] = " 13\n";
24878 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24879 :
24880 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24881 5 : false);
24882 : }
24883 : // Test that the next script succeeds normally.
24884 : {
24885 : char chunk1[] =
24886 : " // This will be parsed successfully.\n"
24887 5 : " function foo() { return ";
24888 5 : char chunk2[] = " 13; }\n";
24889 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24890 :
24891 5 : RunStreamingTest(chunks);
24892 : }
24893 5 : }
24894 :
24895 :
24896 25880 : TEST(StreamingUtf8Script) {
24897 : // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
24898 : // don't like it.
24899 : const char* chunk1 =
24900 : "function foo() {\n"
24901 : " // This function will contain an UTF-8 character which is not in\n"
24902 : " // ASCII.\n"
24903 : " var foob\xec\x92\x81r = 13;\n"
24904 : " return foob\xec\x92\x81r;\n"
24905 : "}\n";
24906 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
24907 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24908 5 : }
24909 :
24910 :
24911 25880 : TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24912 : // A sanity check to prove that the approach of splitting UTF-8
24913 : // characters is correct. Here is an UTF-8 character which will take three
24914 : // bytes.
24915 : const char* reference = "\xec\x92\x81";
24916 : CHECK_EQ(3, strlen(reference));
24917 :
24918 : char chunk1[] =
24919 : "function foo() {\n"
24920 : " // This function will contain an UTF-8 character which is not in\n"
24921 : " // ASCII.\n"
24922 5 : " var foob";
24923 : char chunk2[] =
24924 : "XXXr = 13;\n"
24925 : " return foob\xec\x92\x81r;\n"
24926 5 : "}\n";
24927 20 : for (int i = 0; i < 3; ++i) {
24928 15 : chunk2[i] = reference[i];
24929 : }
24930 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24931 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24932 5 : }
24933 :
24934 :
24935 25880 : TEST(StreamingUtf8ScriptWithSplitCharacters) {
24936 : // Stream data where a multi-byte UTF-8 character is split between two data
24937 : // chunks.
24938 : const char* reference = "\xec\x92\x81";
24939 : char chunk1[] =
24940 : "function foo() {\n"
24941 : " // This function will contain an UTF-8 character which is not in\n"
24942 : " // ASCII.\n"
24943 5 : " var foobX";
24944 : char chunk2[] =
24945 : "XXr = 13;\n"
24946 : " return foob\xec\x92\x81r;\n"
24947 5 : "}\n";
24948 5 : chunk1[strlen(chunk1) - 1] = reference[0];
24949 5 : chunk2[0] = reference[1];
24950 5 : chunk2[1] = reference[2];
24951 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24952 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24953 5 : }
24954 :
24955 :
24956 25880 : TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24957 : // Tests edge cases which should still be decoded correctly.
24958 :
24959 : // Case 1: a chunk contains only bytes for a split character (and no other
24960 : // data). This kind of a chunk would be exceptionally small, but we should
24961 : // still decode it correctly.
24962 : const char* reference = "\xec\x92\x81";
24963 : // The small chunk is at the beginning of the split character
24964 : {
24965 : char chunk1[] =
24966 : "function foo() {\n"
24967 : " // This function will contain an UTF-8 character which is not in\n"
24968 : " // ASCII.\n"
24969 5 : " var foob";
24970 5 : char chunk2[] = "XX";
24971 : char chunk3[] =
24972 : "Xr = 13;\n"
24973 : " return foob\xec\x92\x81r;\n"
24974 5 : "}\n";
24975 5 : chunk2[0] = reference[0];
24976 5 : chunk2[1] = reference[1];
24977 5 : chunk3[0] = reference[2];
24978 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
24979 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24980 : }
24981 : // The small chunk is at the end of a character
24982 : {
24983 : char chunk1[] =
24984 : "function foo() {\n"
24985 : " // This function will contain an UTF-8 character which is not in\n"
24986 : " // ASCII.\n"
24987 5 : " var foobX";
24988 5 : char chunk2[] = "XX";
24989 : char chunk3[] =
24990 : "r = 13;\n"
24991 : " return foob\xec\x92\x81r;\n"
24992 5 : "}\n";
24993 5 : chunk1[strlen(chunk1) - 1] = reference[0];
24994 5 : chunk2[0] = reference[1];
24995 5 : chunk2[1] = reference[2];
24996 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
24997 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24998 : }
24999 : // Case 2: the script ends with a multi-byte character. Make sure that it's
25000 : // decoded correctly and not just ignored.
25001 : {
25002 : char chunk1[] =
25003 : "var foob\xec\x92\x81 = 13;\n"
25004 5 : "foob\xec\x92\x81";
25005 5 : const char* chunks[] = {chunk1, nullptr};
25006 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25007 : }
25008 5 : }
25009 :
25010 :
25011 25880 : TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
25012 : // Test cases where a UTF-8 character is split over several chunks. Those
25013 : // cases are not supported (the embedder should give the data in big enough
25014 : // chunks), but we shouldn't crash and parse this just fine.
25015 : const char* reference = "\xec\x92\x81";
25016 : char chunk1[] =
25017 : "function foo() {\n"
25018 : " // This function will contain an UTF-8 character which is not in\n"
25019 : " // ASCII.\n"
25020 5 : " var foobX";
25021 5 : char chunk2[] = "X";
25022 : char chunk3[] =
25023 : "Xr = 13;\n"
25024 : " return foob\xec\x92\x81r;\n"
25025 5 : "}\n";
25026 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25027 5 : chunk2[0] = reference[1];
25028 5 : chunk3[0] = reference[2];
25029 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25030 :
25031 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25032 5 : }
25033 :
25034 :
25035 :
25036 25880 : TEST(StreamingWithDebuggingEnabledLate) {
25037 : // The streaming parser can only parse lazily, i.e. inner functions are not
25038 : // fully parsed. However, we may compile inner functions eagerly when
25039 : // debugging. Make sure that we can deal with this when turning on debugging
25040 : // after streaming parser has already finished parsing.
25041 : const char* chunks[] = {"with({x:1}) {",
25042 : " var foo = function foo(y) {",
25043 : " return x + y;",
25044 : " };",
25045 : " foo(2);",
25046 : "}",
25047 5 : nullptr};
25048 :
25049 5 : LocalContext env;
25050 5 : v8::Isolate* isolate = env->GetIsolate();
25051 10 : v8::HandleScope scope(isolate);
25052 10 : v8::TryCatch try_catch(isolate);
25053 :
25054 : v8::ScriptCompiler::StreamedSource source(
25055 : new TestSourceStream(chunks),
25056 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25057 : v8::ScriptCompiler::ScriptStreamingTask* task =
25058 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25059 :
25060 5 : task->Run();
25061 5 : delete task;
25062 :
25063 5 : CHECK(!try_catch.HasCaught());
25064 :
25065 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25066 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25067 :
25068 : EnableDebugger(isolate);
25069 :
25070 : v8::Local<Script> script =
25071 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25072 5 : origin)
25073 5 : .ToLocalChecked();
25074 :
25075 : Maybe<uint32_t> result =
25076 10 : script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
25077 5 : CHECK_EQ(3U, result.FromMaybe(0));
25078 :
25079 5 : delete[] full_source;
25080 :
25081 5 : DisableDebugger(isolate);
25082 5 : }
25083 :
25084 :
25085 25880 : TEST(StreamingScriptWithInvalidUtf8) {
25086 : // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
25087 : // chunk don't produce a crash.
25088 : const char* reference = "\xec\x92\x81\x80\x80";
25089 : char chunk1[] =
25090 : "function foo() {\n"
25091 : " // This function will contain an UTF-8 character which is not in\n"
25092 : " // ASCII.\n"
25093 5 : " var foobXXXXX"; // Too many bytes which look like incomplete chars!
25094 : char chunk2[] =
25095 : "r = 13;\n"
25096 : " return foob\xec\x92\x81\x80\x80r;\n"
25097 5 : "}\n";
25098 5 : for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
25099 :
25100 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25101 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
25102 5 : }
25103 :
25104 :
25105 25880 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
25106 : // Regression test: Stream data where there are several multi-byte UTF-8
25107 : // characters in a sequence and one of them is split between two data chunks.
25108 : const char* reference = "\xec\x92\x81";
25109 : char chunk1[] =
25110 : "function foo() {\n"
25111 : " // This function will contain an UTF-8 character which is not in\n"
25112 : " // ASCII.\n"
25113 5 : " var foob\xec\x92\x81X";
25114 : char chunk2[] =
25115 : "XXr = 13;\n"
25116 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25117 5 : "}\n";
25118 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25119 5 : chunk2[0] = reference[1];
25120 5 : chunk2[1] = reference[2];
25121 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25122 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25123 5 : }
25124 :
25125 :
25126 25880 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
25127 : // Another regression test, similar to the previous one. The difference is
25128 : // that the split character is not the last one in the sequence.
25129 : const char* reference = "\xec\x92\x81";
25130 : char chunk1[] =
25131 : "function foo() {\n"
25132 : " // This function will contain an UTF-8 character which is not in\n"
25133 : " // ASCII.\n"
25134 5 : " var foobX";
25135 : char chunk2[] =
25136 : "XX\xec\x92\x81r = 13;\n"
25137 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25138 5 : "}\n";
25139 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25140 5 : chunk2[0] = reference[1];
25141 5 : chunk2[1] = reference[2];
25142 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25143 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25144 5 : }
25145 :
25146 :
25147 25880 : TEST(StreamingWithHarmonyScopes) {
25148 : // Don't use RunStreamingTest here so that both scripts get to use the same
25149 : // LocalContext and HandleScope.
25150 5 : LocalContext env;
25151 5 : v8::Isolate* isolate = env->GetIsolate();
25152 10 : v8::HandleScope scope(isolate);
25153 :
25154 : // First, run a script with a let variable.
25155 : CompileRun("\"use strict\"; let x = 1;");
25156 :
25157 : // Then stream a script which (erroneously) tries to introduce the same
25158 : // variable again.
25159 5 : const char* chunks[] = {"\"use strict\"; let x = 2;", nullptr};
25160 :
25161 10 : v8::TryCatch try_catch(isolate);
25162 : v8::ScriptCompiler::StreamedSource source(
25163 : new TestSourceStream(chunks),
25164 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25165 : v8::ScriptCompiler::ScriptStreamingTask* task =
25166 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25167 5 : task->Run();
25168 5 : delete task;
25169 :
25170 : // Parsing should succeed (the script will be parsed and compiled in a context
25171 : // independent way, so the error is not detected).
25172 5 : CHECK(!try_catch.HasCaught());
25173 :
25174 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25175 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25176 : v8::Local<Script> script =
25177 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25178 5 : origin)
25179 5 : .ToLocalChecked();
25180 5 : CHECK(!script.IsEmpty());
25181 5 : CHECK(!try_catch.HasCaught());
25182 :
25183 : // Running the script exposes the error.
25184 10 : CHECK(script->Run(env.local()).IsEmpty());
25185 5 : CHECK(try_catch.HasCaught());
25186 10 : delete[] full_source;
25187 5 : }
25188 :
25189 :
25190 25880 : TEST(CodeCache) {
25191 : v8::Isolate::CreateParams create_params;
25192 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25193 :
25194 : const char* source = "Math.sqrt(4)";
25195 : const char* origin = "code cache test";
25196 : v8::ScriptCompiler::CachedData* cache;
25197 :
25198 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
25199 : {
25200 : v8::Isolate::Scope iscope(isolate1);
25201 10 : v8::HandleScope scope(isolate1);
25202 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
25203 : v8::Context::Scope cscope(context);
25204 5 : v8::Local<v8::String> source_string = v8_str(source);
25205 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25206 : v8::ScriptCompiler::Source source(source_string, script_origin);
25207 : v8::ScriptCompiler::CompileOptions option =
25208 : v8::ScriptCompiler::kNoCompileOptions;
25209 : v8::Local<v8::Script> script =
25210 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25211 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25212 : }
25213 5 : isolate1->Dispose();
25214 :
25215 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
25216 : {
25217 : v8::Isolate::Scope iscope(isolate2);
25218 10 : v8::HandleScope scope(isolate2);
25219 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
25220 : v8::Context::Scope cscope(context);
25221 5 : v8::Local<v8::String> source_string = v8_str(source);
25222 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25223 : v8::ScriptCompiler::Source source(source_string, script_origin, cache);
25224 : v8::ScriptCompiler::CompileOptions option =
25225 : v8::ScriptCompiler::kConsumeCodeCache;
25226 : v8::Local<v8::Script> script;
25227 : {
25228 : i::DisallowCompilation no_compile(
25229 : reinterpret_cast<i::Isolate*>(isolate2));
25230 : script = v8::ScriptCompiler::Compile(context, &source, option)
25231 5 : .ToLocalChecked();
25232 : }
25233 20 : CHECK_EQ(2, script->Run(context)
25234 : .ToLocalChecked()
25235 : ->ToInt32(context)
25236 : .ToLocalChecked()
25237 : ->Int32Value(context)
25238 : .FromJust());
25239 : }
25240 5 : isolate2->Dispose();
25241 5 : }
25242 :
25243 0 : v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
25244 : Local<String> specifier,
25245 : Local<Module> referrer) {
25246 0 : CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
25247 : }
25248 :
25249 : namespace {
25250 :
25251 10 : Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
25252 : Local<Context> context,
25253 : const char* resource_name,
25254 : const char* source) {
25255 10 : Local<String> source_string = v8_str(source);
25256 : v8::ScriptOrigin script_origin(
25257 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25258 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25259 10 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25260 : v8::ScriptCompiler::Source script_compiler_source(source_string,
25261 : script_origin);
25262 : Local<Module> module =
25263 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source)
25264 10 : .ToLocalChecked();
25265 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25266 20 : .ToChecked();
25267 :
25268 20 : return module;
25269 : }
25270 :
25271 5 : Local<Module> CompileAndInstantiateModuleFromCache(
25272 : v8::Isolate* isolate, Local<Context> context, const char* resource_name,
25273 : const char* source, v8::ScriptCompiler::CachedData* cache) {
25274 5 : Local<String> source_string = v8_str(source);
25275 : v8::ScriptOrigin script_origin(
25276 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25277 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25278 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25279 : v8::ScriptCompiler::Source script_compiler_source(source_string,
25280 : script_origin, cache);
25281 :
25282 : Local<Module> module =
25283 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source,
25284 : v8::ScriptCompiler::kConsumeCodeCache)
25285 5 : .ToLocalChecked();
25286 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25287 10 : .ToChecked();
25288 :
25289 10 : return module;
25290 : }
25291 :
25292 : } // namespace
25293 :
25294 25880 : TEST(ModuleCodeCache) {
25295 : v8::Isolate::CreateParams create_params;
25296 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25297 :
25298 : const char* origin = "code cache test";
25299 : const char* source =
25300 : "export default 5; export const a = 10; function f() { return 42; } "
25301 : "(function() { return f(); })();";
25302 :
25303 : v8::ScriptCompiler::CachedData* cache;
25304 : {
25305 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25306 : {
25307 : v8::Isolate::Scope iscope(isolate);
25308 10 : v8::HandleScope scope(isolate);
25309 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25310 : v8::Context::Scope cscope(context);
25311 :
25312 : Local<Module> module =
25313 5 : CompileAndInstantiateModule(isolate, context, origin, source);
25314 :
25315 : // Fetch the shared function info before evaluation.
25316 : Local<v8::UnboundModuleScript> unbound_module_script =
25317 5 : module->GetUnboundModuleScript();
25318 :
25319 : // Evaluate for possible lazy compilation.
25320 : Local<Value> completion_value =
25321 5 : module->Evaluate(context).ToLocalChecked();
25322 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25323 :
25324 : // Now create the cache. Note that it is freed, obscurely, when
25325 : // ScriptCompiler::Source goes out of scope below.
25326 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25327 : }
25328 5 : isolate->Dispose();
25329 : }
25330 :
25331 : // Test that the cache is consumed and execution still works.
25332 : {
25333 : // Disable --always_opt, otherwise we try to optimize during module
25334 : // instantiation, violating the DisallowCompilation scope.
25335 5 : i::FLAG_always_opt = false;
25336 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25337 : {
25338 : v8::Isolate::Scope iscope(isolate);
25339 10 : v8::HandleScope scope(isolate);
25340 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25341 : v8::Context::Scope cscope(context);
25342 :
25343 : Local<Module> module;
25344 : {
25345 : i::DisallowCompilation no_compile(
25346 : reinterpret_cast<i::Isolate*>(isolate));
25347 : module = CompileAndInstantiateModuleFromCache(isolate, context, origin,
25348 5 : source, cache);
25349 : }
25350 :
25351 : Local<Value> completion_value =
25352 5 : module->Evaluate(context).ToLocalChecked();
25353 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25354 : }
25355 5 : isolate->Dispose();
25356 : }
25357 5 : }
25358 :
25359 : // Tests that the code cache does not confuse the same source code compiled as a
25360 : // script and as a module.
25361 25880 : TEST(CodeCacheModuleScriptMismatch) {
25362 : v8::Isolate::CreateParams create_params;
25363 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25364 :
25365 : const char* origin = "code cache test";
25366 : const char* source = "42";
25367 :
25368 : v8::ScriptCompiler::CachedData* cache;
25369 : {
25370 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25371 : {
25372 : v8::Isolate::Scope iscope(isolate);
25373 10 : v8::HandleScope scope(isolate);
25374 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25375 : v8::Context::Scope cscope(context);
25376 :
25377 : Local<Module> module =
25378 5 : CompileAndInstantiateModule(isolate, context, origin, source);
25379 :
25380 : // Fetch the shared function info before evaluation.
25381 : Local<v8::UnboundModuleScript> unbound_module_script =
25382 5 : module->GetUnboundModuleScript();
25383 :
25384 : // Evaluate for possible lazy compilation.
25385 : Local<Value> completion_value =
25386 5 : module->Evaluate(context).ToLocalChecked();
25387 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25388 :
25389 : // Now create the cache. Note that it is freed, obscurely, when
25390 : // ScriptCompiler::Source goes out of scope below.
25391 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25392 : }
25393 5 : isolate->Dispose();
25394 : }
25395 :
25396 : // Test that the cache is not consumed when source is compiled as a script.
25397 : {
25398 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25399 : {
25400 : v8::Isolate::Scope iscope(isolate);
25401 10 : v8::HandleScope scope(isolate);
25402 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25403 : v8::Context::Scope cscope(context);
25404 :
25405 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25406 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25407 5 : script_origin, cache);
25408 :
25409 : v8::Local<v8::Script> script =
25410 : v8::ScriptCompiler::Compile(context, &script_compiler_source,
25411 : v8::ScriptCompiler::kConsumeCodeCache)
25412 5 : .ToLocalChecked();
25413 :
25414 5 : CHECK(cache->rejected);
25415 :
25416 20 : CHECK_EQ(42, script->Run(context)
25417 : .ToLocalChecked()
25418 : ->ToInt32(context)
25419 : .ToLocalChecked()
25420 : ->Int32Value(context)
25421 : .FromJust());
25422 : }
25423 5 : isolate->Dispose();
25424 : }
25425 5 : }
25426 :
25427 : // Same as above but other way around.
25428 25880 : TEST(CodeCacheScriptModuleMismatch) {
25429 : v8::Isolate::CreateParams create_params;
25430 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25431 :
25432 : const char* origin = "code cache test";
25433 : const char* source = "42";
25434 :
25435 : v8::ScriptCompiler::CachedData* cache;
25436 : {
25437 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25438 : {
25439 : v8::Isolate::Scope iscope(isolate);
25440 10 : v8::HandleScope scope(isolate);
25441 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25442 : v8::Context::Scope cscope(context);
25443 5 : v8::Local<v8::String> source_string = v8_str(source);
25444 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25445 : v8::ScriptCompiler::Source source(source_string, script_origin);
25446 : v8::ScriptCompiler::CompileOptions option =
25447 : v8::ScriptCompiler::kNoCompileOptions;
25448 : v8::Local<v8::Script> script =
25449 : v8::ScriptCompiler::Compile(context, &source, option)
25450 5 : .ToLocalChecked();
25451 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25452 : }
25453 5 : isolate->Dispose();
25454 : }
25455 :
25456 : // Test that the cache is not consumed when source is compiled as a module.
25457 : {
25458 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25459 : {
25460 : v8::Isolate::Scope iscope(isolate);
25461 10 : v8::HandleScope scope(isolate);
25462 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25463 : v8::Context::Scope cscope(context);
25464 :
25465 : v8::ScriptOrigin script_origin(
25466 : v8_str(origin), Local<v8::Integer>(), Local<v8::Integer>(),
25467 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25468 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25469 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25470 5 : script_origin, cache);
25471 :
25472 : Local<Module> module = v8::ScriptCompiler::CompileModule(
25473 : isolate, &script_compiler_source,
25474 : v8::ScriptCompiler::kConsumeCodeCache)
25475 5 : .ToLocalChecked();
25476 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25477 10 : .ToChecked();
25478 :
25479 5 : CHECK(cache->rejected);
25480 :
25481 : Local<Value> completion_value =
25482 5 : module->Evaluate(context).ToLocalChecked();
25483 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25484 : }
25485 5 : isolate->Dispose();
25486 : }
25487 5 : }
25488 :
25489 : // Tests that compilation can handle a garbled cache.
25490 25880 : TEST(InvalidCodeCacheDataInCompileModule) {
25491 5 : v8::V8::Initialize();
25492 5 : v8::Isolate* isolate = CcTest::isolate();
25493 5 : v8::HandleScope scope(isolate);
25494 10 : LocalContext local_context;
25495 :
25496 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
25497 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25498 5 : Local<String> origin = v8_str("origin");
25499 : int length = 16;
25500 : v8::ScriptCompiler::CachedData* cached_data =
25501 5 : new v8::ScriptCompiler::CachedData(data, length);
25502 5 : CHECK(!cached_data->rejected);
25503 :
25504 : v8::ScriptOrigin script_origin(
25505 : origin, Local<v8::Integer>(), Local<v8::Integer>(), Local<v8::Boolean>(),
25506 : Local<v8::Integer>(), Local<v8::Value>(), Local<v8::Boolean>(),
25507 : Local<v8::Boolean>(), True(isolate));
25508 5 : v8::ScriptCompiler::Source source(v8_str("42"), script_origin, cached_data);
25509 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25510 :
25511 : Local<Module> module =
25512 : v8::ScriptCompiler::CompileModule(isolate, &source,
25513 : v8::ScriptCompiler::kConsumeCodeCache)
25514 5 : .ToLocalChecked();
25515 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25516 10 : .ToChecked();
25517 :
25518 5 : CHECK(cached_data->rejected);
25519 15 : CHECK_EQ(42, module->Evaluate(context)
25520 : .ToLocalChecked()
25521 : ->Int32Value(context)
25522 5 : .FromJust());
25523 5 : }
25524 :
25525 5 : void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
25526 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
25527 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25528 : int length = 16;
25529 : v8::ScriptCompiler::CachedData* cached_data =
25530 5 : new v8::ScriptCompiler::CachedData(data, length);
25531 5 : CHECK(!cached_data->rejected);
25532 5 : v8::ScriptOrigin origin(v8_str("origin"));
25533 5 : v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
25534 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25535 : v8::Local<v8::Script> script =
25536 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25537 5 : CHECK(cached_data->rejected);
25538 15 : CHECK_EQ(
25539 : 42,
25540 : script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
25541 5 : }
25542 :
25543 :
25544 25880 : TEST(InvalidCodeCacheData) {
25545 5 : v8::V8::Initialize();
25546 5 : v8::HandleScope scope(CcTest::isolate());
25547 10 : LocalContext context;
25548 10 : TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
25549 5 : }
25550 :
25551 :
25552 25880 : TEST(StringConcatOverflow) {
25553 5 : v8::V8::Initialize();
25554 5 : v8::Isolate* isolate = CcTest::isolate();
25555 5 : v8::HandleScope scope(isolate);
25556 : RandomLengthOneByteResource* r =
25557 5 : new RandomLengthOneByteResource(i::String::kMaxLength);
25558 : v8::Local<v8::String> str =
25559 5 : v8::String::NewExternalOneByte(isolate, r).ToLocalChecked();
25560 5 : CHECK(!str.IsEmpty());
25561 10 : v8::TryCatch try_catch(isolate);
25562 5 : v8::Local<v8::String> result = v8::String::Concat(isolate, str, str);
25563 5 : v8::String::Concat(CcTest::isolate(), str, str);
25564 5 : CHECK(result.IsEmpty());
25565 10 : CHECK(!try_catch.HasCaught());
25566 5 : }
25567 :
25568 25879 : TEST(TurboAsmDisablesDetach) {
25569 : #ifndef V8_LITE_MODE
25570 4 : i::FLAG_opt = true;
25571 4 : i::FLAG_allow_natives_syntax = true;
25572 4 : v8::V8::Initialize();
25573 4 : v8::HandleScope scope(CcTest::isolate());
25574 8 : LocalContext context;
25575 : const char* load =
25576 : "function Module(stdlib, foreign, heap) {"
25577 : " 'use asm';"
25578 : " var MEM32 = new stdlib.Int32Array(heap);"
25579 : " function load() { return MEM32[0] | 0; }"
25580 : " return { load: load };"
25581 : "}"
25582 : "var buffer = new ArrayBuffer(4096);"
25583 : "var module = Module(this, {}, buffer);"
25584 : "%OptimizeFunctionOnNextCall(module.load);"
25585 : "module.load();"
25586 : "buffer";
25587 :
25588 : v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
25589 4 : CHECK(!result->IsDetachable());
25590 :
25591 : const char* store =
25592 : "function Module(stdlib, foreign, heap) {"
25593 : " 'use asm';"
25594 : " var MEM32 = new stdlib.Int32Array(heap);"
25595 : " function store() { MEM32[0] = 0; }"
25596 : " return { store: store };"
25597 : "}"
25598 : "var buffer = new ArrayBuffer(4096);"
25599 : "var module = Module(this, {}, buffer);"
25600 : "%OptimizeFunctionOnNextCall(module.store);"
25601 : "module.store();"
25602 : "buffer";
25603 :
25604 : result = CompileRun(store).As<v8::ArrayBuffer>();
25605 8 : CHECK(!result->IsDetachable());
25606 : #endif // V8_LITE_MODE
25607 4 : }
25608 :
25609 25880 : TEST(ClassPrototypeCreationContext) {
25610 5 : v8::Isolate* isolate = CcTest::isolate();
25611 5 : v8::HandleScope handle_scope(isolate);
25612 10 : LocalContext env;
25613 :
25614 : Local<Object> result = Local<Object>::Cast(
25615 : CompileRun("'use strict'; class Example { }; Example.prototype"));
25616 15 : CHECK(env.local() == result->CreationContext());
25617 5 : }
25618 :
25619 :
25620 25880 : TEST(SimpleStreamingScriptWithSourceURL) {
25621 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
25622 5 : "//# sourceURL=bar2.js\n", nullptr};
25623 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25624 5 : "bar2.js");
25625 5 : }
25626 :
25627 :
25628 25880 : TEST(StreamingScriptWithSplitSourceURL) {
25629 : const char* chunks[] = {"function foo() { ret", "urn 13; } f",
25630 5 : "oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
25631 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25632 5 : "bar2.js");
25633 5 : }
25634 :
25635 :
25636 25880 : TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
25637 : const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
25638 5 : " sourceMappingURL=bar2.js\n", "foo();", nullptr};
25639 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25640 5 : nullptr, "bar2.js");
25641 5 : }
25642 :
25643 :
25644 25880 : TEST(NewStringRangeError) {
25645 : // This test uses a lot of memory and fails with flaky OOM when run
25646 : // with --stress-incremental-marking on TSAN.
25647 5 : i::FLAG_stress_incremental_marking = false;
25648 5 : v8::Isolate* isolate = CcTest::isolate();
25649 5 : v8::HandleScope handle_scope(isolate);
25650 : const int length = i::String::kMaxLength + 1;
25651 : const int buffer_size = length * sizeof(uint16_t);
25652 5 : void* buffer = malloc(buffer_size);
25653 5 : if (buffer == nullptr) return;
25654 : memset(buffer, 'A', buffer_size);
25655 : {
25656 5 : v8::TryCatch try_catch(isolate);
25657 : char* data = reinterpret_cast<char*>(buffer);
25658 10 : CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
25659 : length)
25660 : .IsEmpty());
25661 5 : CHECK(!try_catch.HasCaught());
25662 : }
25663 : {
25664 5 : v8::TryCatch try_catch(isolate);
25665 : uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
25666 10 : CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
25667 : length)
25668 : .IsEmpty());
25669 5 : CHECK(!try_catch.HasCaught());
25670 : }
25671 : {
25672 5 : v8::TryCatch try_catch(isolate);
25673 : uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
25674 10 : CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
25675 : length)
25676 : .IsEmpty());
25677 5 : CHECK(!try_catch.HasCaught());
25678 : }
25679 5 : free(buffer);
25680 : }
25681 :
25682 :
25683 25875 : TEST(SealHandleScope) {
25684 0 : v8::Isolate* isolate = CcTest::isolate();
25685 0 : v8::HandleScope handle_scope(isolate);
25686 0 : LocalContext env;
25687 :
25688 0 : v8::SealHandleScope seal(isolate);
25689 :
25690 : // Should fail
25691 0 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25692 :
25693 0 : USE(obj);
25694 0 : }
25695 :
25696 :
25697 25880 : TEST(SealHandleScopeNested) {
25698 5 : v8::Isolate* isolate = CcTest::isolate();
25699 5 : v8::HandleScope handle_scope(isolate);
25700 10 : LocalContext env;
25701 :
25702 10 : v8::SealHandleScope seal(isolate);
25703 :
25704 : {
25705 5 : v8::HandleScope handle_scope(isolate);
25706 :
25707 : // Should work
25708 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25709 :
25710 5 : USE(obj);
25711 5 : }
25712 5 : }
25713 :
25714 :
25715 5 : static void ExtrasBindingTestRuntimeFunction(
25716 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
25717 15 : CHECK_EQ(
25718 : 3,
25719 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
25720 5 : args.GetReturnValue().Set(v8_num(7));
25721 5 : }
25722 :
25723 25880 : TEST(ExtrasFunctionSource) {
25724 5 : v8::Isolate* isolate = CcTest::isolate();
25725 5 : v8::HandleScope handle_scope(isolate);
25726 10 : LocalContext env;
25727 :
25728 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25729 :
25730 : // Functions defined in extras do not expose source code.
25731 15 : auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
25732 5 : .ToLocalChecked()
25733 : .As<v8::Function>();
25734 : auto undefined = v8::Undefined(isolate);
25735 10 : auto result = func->Call(env.local(), undefined, 0, {})
25736 5 : .ToLocalChecked()
25737 : .As<v8::String>();
25738 10 : CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
25739 :
25740 : // Functions defined in extras do not show up in the stack trace.
25741 15 : auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
25742 5 : .ToLocalChecked()
25743 : .As<v8::Function>();
25744 25 : CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
25745 : ExpectString(
25746 : "function f(x) { return wrapper(x) }"
25747 : "function g() { return new Error().stack; }"
25748 : "f(g)",
25749 : "Error\n"
25750 : " at g (<anonymous>:1:58)\n"
25751 : " at f (<anonymous>:1:24)\n"
25752 10 : " at <anonymous>:1:78");
25753 5 : }
25754 :
25755 25880 : TEST(ExtrasBindingObject) {
25756 5 : v8::Isolate* isolate = CcTest::isolate();
25757 5 : v8::HandleScope handle_scope(isolate);
25758 10 : LocalContext env;
25759 :
25760 : // standalone.gypi ensures we include the test-extra.js file, which should
25761 : // export the tested functions.
25762 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25763 :
25764 15 : auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
25765 5 : .ToLocalChecked()
25766 : .As<v8::Function>();
25767 : auto undefined = v8::Undefined(isolate);
25768 10 : auto result = func->Call(env.local(), undefined, 0, {})
25769 5 : .ToLocalChecked()
25770 : .As<v8::Number>();
25771 10 : CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
25772 :
25773 : v8::Local<v8::FunctionTemplate> runtimeFunction =
25774 5 : v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
25775 : binding->Set(env.local(), v8_str("runtime"),
25776 25 : runtimeFunction->GetFunction(env.local()).ToLocalChecked())
25777 10 : .FromJust();
25778 15 : func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
25779 5 : .ToLocalChecked()
25780 : .As<v8::Function>();
25781 10 : result = func->Call(env.local(), undefined, 0, {})
25782 5 : .ToLocalChecked()
25783 : .As<v8::Number>();
25784 15 : CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
25785 5 : }
25786 :
25787 :
25788 25880 : TEST(ExtrasCreatePromise) {
25789 5 : i::FLAG_allow_natives_syntax = true;
25790 5 : LocalContext context;
25791 5 : v8::Isolate* isolate = context->GetIsolate();
25792 10 : v8::HandleScope handle_scope(isolate);
25793 :
25794 10 : LocalContext env;
25795 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25796 :
25797 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromise"))
25798 5 : .ToLocalChecked()
25799 : .As<v8::Function>();
25800 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25801 :
25802 : auto promise = CompileRun(
25803 : "func();\n"
25804 : "func();\n"
25805 : "%OptimizeFunctionOnNextCall(func);\n"
25806 : "func()\n")
25807 : .As<v8::Promise>();
25808 10 : CHECK_EQ(v8::Promise::kPending, promise->State());
25809 5 : }
25810 :
25811 25880 : TEST(ExtrasCreatePromiseWithParent) {
25812 5 : i::FLAG_allow_natives_syntax = true;
25813 5 : LocalContext context;
25814 5 : v8::Isolate* isolate = context->GetIsolate();
25815 10 : v8::HandleScope handle_scope(isolate);
25816 :
25817 10 : LocalContext env;
25818 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25819 :
25820 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromiseWithParent"))
25821 5 : .ToLocalChecked()
25822 : .As<v8::Function>();
25823 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25824 :
25825 : auto promise = CompileRun(
25826 : "var parent = new Promise((a, b) => {});\n"
25827 : "func(parent);\n"
25828 : "func(parent);\n"
25829 : "%OptimizeFunctionOnNextCall(func);\n"
25830 : "func(parent)\n")
25831 : .As<v8::Promise>();
25832 10 : CHECK_EQ(v8::Promise::kPending, promise->State());
25833 5 : }
25834 :
25835 25880 : TEST(ExtrasRejectPromise) {
25836 5 : i::FLAG_allow_natives_syntax = true;
25837 5 : LocalContext context;
25838 5 : v8::Isolate* isolate = context->GetIsolate();
25839 10 : v8::HandleScope handle_scope(isolate);
25840 :
25841 10 : LocalContext env;
25842 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25843 :
25844 15 : auto func = binding->Get(env.local(), v8_str("testRejectPromise"))
25845 5 : .ToLocalChecked()
25846 : .As<v8::Function>();
25847 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25848 :
25849 : auto rejected_promise = CompileRun(
25850 : "function newPromise() {\n"
25851 : " return new Promise((a, b) => {});\n"
25852 : "}\n"
25853 : "func(newPromise(), 1);\n"
25854 : "func(newPromise(), 1);\n"
25855 : "%OptimizeFunctionOnNextCall(func);\n"
25856 : "var promise = newPromise();\n"
25857 : "func(promise, 1);\n"
25858 : "promise;\n")
25859 : .As<v8::Promise>();
25860 5 : CHECK_EQ(v8::Promise::kRejected, rejected_promise->State());
25861 20 : CHECK_EQ(1, rejected_promise->Result()->Int32Value(env.local()).FromJust());
25862 5 : }
25863 :
25864 25880 : TEST(ExtrasResolvePromise) {
25865 5 : i::FLAG_allow_natives_syntax = true;
25866 5 : LocalContext context;
25867 5 : v8::Isolate* isolate = context->GetIsolate();
25868 10 : v8::HandleScope handle_scope(isolate);
25869 :
25870 10 : LocalContext env;
25871 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25872 :
25873 15 : auto func = binding->Get(env.local(), v8_str("testResolvePromise"))
25874 5 : .ToLocalChecked()
25875 : .As<v8::Function>();
25876 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25877 :
25878 : auto pending_promise = CompileRun(
25879 : "function newPromise() {\n"
25880 : " return new Promise((a, b) => {});\n"
25881 : "}\n"
25882 : "func(newPromise(), newPromise());\n"
25883 : "func(newPromise(), newPromise());\n"
25884 : "%OptimizeFunctionOnNextCall(func);\n"
25885 : "var promise = newPromise();\n"
25886 : "func(promise, newPromise());\n"
25887 : "promise;\n")
25888 : .As<v8::Promise>();
25889 5 : CHECK_EQ(v8::Promise::kPending, pending_promise->State());
25890 :
25891 : auto fulfilled_promise = CompileRun(
25892 : "function newPromise() {\n"
25893 : " return new Promise((a, b) => {});\n"
25894 : "}\n"
25895 : "func(newPromise(), 1);\n"
25896 : "func(newPromise(), 1);\n"
25897 : "%OptimizeFunctionOnNextCall(func);\n"
25898 : "var promise = newPromise();\n"
25899 : "func(promise, 1);\n"
25900 : "promise;\n")
25901 : .As<v8::Promise>();
25902 5 : CHECK_EQ(v8::Promise::kFulfilled, fulfilled_promise->State());
25903 20 : CHECK_EQ(1, fulfilled_promise->Result()->Int32Value(env.local()).FromJust());
25904 5 : }
25905 :
25906 25880 : TEST(ExtrasUtilsObject) {
25907 5 : LocalContext context;
25908 5 : v8::Isolate* isolate = context->GetIsolate();
25909 10 : v8::HandleScope handle_scope(isolate);
25910 :
25911 10 : LocalContext env;
25912 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25913 :
25914 15 : auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
25915 5 : .ToLocalChecked()
25916 : .As<v8::Function>();
25917 : auto undefined = v8::Undefined(isolate);
25918 10 : auto result = func->Call(env.local(), undefined, 0, {})
25919 5 : .ToLocalChecked()
25920 : .As<v8::Object>();
25921 :
25922 15 : auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
25923 5 : .ToLocalChecked()
25924 : .As<v8::Symbol>();
25925 : i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
25926 5 : CHECK(ips->IsPrivate());
25927 :
25928 : CompileRun("var result = 0; function store(x) { result = x; }");
25929 5 : auto store = CompileRun("store").As<v8::Function>();
25930 :
25931 15 : auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
25932 5 : .ToLocalChecked()
25933 : .As<v8::Promise>();
25934 5 : fulfilled_promise->Then(env.local(), store).ToLocalChecked();
25935 5 : isolate->RunMicrotasks();
25936 15 : CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
25937 :
25938 : auto fulfilled_promise_2 =
25939 15 : result->Get(env.local(), v8_str("fulfilledPromise2"))
25940 5 : .ToLocalChecked()
25941 : .As<v8::Promise>();
25942 5 : fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
25943 5 : isolate->RunMicrotasks();
25944 15 : CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
25945 :
25946 15 : auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
25947 5 : .ToLocalChecked()
25948 : .As<v8::Promise>();
25949 5 : rejected_promise->Catch(env.local(), store).ToLocalChecked();
25950 5 : isolate->RunMicrotasks();
25951 15 : CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
25952 :
25953 : auto rejected_but_handled_promise =
25954 15 : result->Get(env.local(), v8_str("rejectedButHandledPromise"))
25955 5 : .ToLocalChecked()
25956 : .As<v8::Promise>();
25957 5 : CHECK(rejected_but_handled_promise->HasHandler());
25958 :
25959 15 : auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
25960 5 : .ToLocalChecked()
25961 : .As<v8::String>();
25962 10 : String::Utf8Value promise_states_string(isolate, promise_states);
25963 5 : CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
25964 :
25965 15 : auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
25966 5 : .ToLocalChecked()
25967 : .As<v8::Boolean>();
25968 5 : CHECK_EQ(true, promise_is_promise->Value());
25969 :
25970 : auto thenable_is_promise =
25971 15 : result->Get(env.local(), v8_str("thenableIsPromise"))
25972 5 : .ToLocalChecked()
25973 : .As<v8::Boolean>();
25974 10 : CHECK_EQ(false, thenable_is_promise->Value());
25975 :
25976 15 : auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
25977 5 : .ToLocalChecked()
25978 : .As<v8::Boolean>();
25979 10 : CHECK_EQ(true, uncurry_this->Value());
25980 5 : }
25981 :
25982 :
25983 25880 : TEST(Map) {
25984 5 : v8::Isolate* isolate = CcTest::isolate();
25985 5 : v8::HandleScope handle_scope(isolate);
25986 10 : LocalContext env;
25987 :
25988 5 : v8::Local<v8::Map> map = v8::Map::New(isolate);
25989 5 : CHECK(map->IsObject());
25990 5 : CHECK(map->IsMap());
25991 10 : CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
25992 5 : CHECK_EQ(0U, map->Size());
25993 :
25994 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
25995 5 : CHECK(val->IsMap());
25996 : map = v8::Local<v8::Map>::Cast(val);
25997 5 : CHECK_EQ(2U, map->Size());
25998 :
25999 5 : v8::Local<v8::Array> contents = map->AsArray();
26000 5 : CHECK_EQ(4U, contents->Length());
26001 10 : CHECK_EQ(
26002 : 1,
26003 : contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26004 10 : CHECK_EQ(
26005 : 2,
26006 : contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26007 10 : CHECK_EQ(
26008 : 3,
26009 : contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
26010 10 : CHECK_EQ(
26011 : 4,
26012 : contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
26013 :
26014 5 : CHECK_EQ(2U, map->Size());
26015 :
26016 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26017 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26018 :
26019 15 : CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26020 10 : CHECK(!map->Has(env.local(), map).FromJust());
26021 :
26022 20 : CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
26023 : .ToLocalChecked()
26024 : ->Int32Value(env.local())
26025 : .FromJust());
26026 20 : CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
26027 : .ToLocalChecked()
26028 : ->Int32Value(env.local())
26029 : .FromJust());
26030 :
26031 15 : CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
26032 : .ToLocalChecked()
26033 : ->IsUndefined());
26034 :
26035 10 : CHECK(!map->Set(env.local(), map, map).IsEmpty());
26036 5 : CHECK_EQ(3U, map->Size());
26037 10 : CHECK(map->Has(env.local(), map).FromJust());
26038 :
26039 10 : CHECK(map->Delete(env.local(), map).FromJust());
26040 5 : CHECK_EQ(2U, map->Size());
26041 10 : CHECK(!map->Has(env.local(), map).FromJust());
26042 10 : CHECK(!map->Delete(env.local(), map).FromJust());
26043 :
26044 5 : map->Clear();
26045 10 : CHECK_EQ(0U, map->Size());
26046 5 : }
26047 :
26048 :
26049 25880 : TEST(Set) {
26050 5 : v8::Isolate* isolate = CcTest::isolate();
26051 5 : v8::HandleScope handle_scope(isolate);
26052 10 : LocalContext env;
26053 :
26054 5 : v8::Local<v8::Set> set = v8::Set::New(isolate);
26055 5 : CHECK(set->IsObject());
26056 5 : CHECK(set->IsSet());
26057 10 : CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
26058 5 : CHECK_EQ(0U, set->Size());
26059 :
26060 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
26061 5 : CHECK(val->IsSet());
26062 : set = v8::Local<v8::Set>::Cast(val);
26063 5 : CHECK_EQ(2U, set->Size());
26064 :
26065 5 : v8::Local<v8::Array> keys = set->AsArray();
26066 5 : CHECK_EQ(2U, keys->Length());
26067 10 : CHECK_EQ(1,
26068 : keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26069 10 : CHECK_EQ(2,
26070 : keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26071 :
26072 5 : CHECK_EQ(2U, set->Size());
26073 :
26074 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26075 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26076 :
26077 15 : CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26078 10 : CHECK(!set->Has(env.local(), set).FromJust());
26079 :
26080 10 : CHECK(!set->Add(env.local(), set).IsEmpty());
26081 5 : CHECK_EQ(3U, set->Size());
26082 10 : CHECK(set->Has(env.local(), set).FromJust());
26083 :
26084 10 : CHECK(set->Delete(env.local(), set).FromJust());
26085 5 : CHECK_EQ(2U, set->Size());
26086 10 : CHECK(!set->Has(env.local(), set).FromJust());
26087 10 : CHECK(!set->Delete(env.local(), set).FromJust());
26088 :
26089 5 : set->Clear();
26090 10 : CHECK_EQ(0U, set->Size());
26091 5 : }
26092 :
26093 25880 : TEST(SetDeleteThenAsArray) {
26094 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26095 5 : v8::Isolate* isolate = CcTest::isolate();
26096 5 : v8::HandleScope handle_scope(isolate);
26097 10 : LocalContext env;
26098 :
26099 : // make a Set
26100 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
26101 : v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
26102 5 : CHECK_EQ(3U, set->Size());
26103 :
26104 : // delete the "middle" element (using AsArray to
26105 : // determine which element is the "middle" element)
26106 5 : v8::Local<v8::Array> array1 = set->AsArray();
26107 5 : CHECK_EQ(3U, array1->Length());
26108 15 : CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
26109 : .FromJust());
26110 :
26111 : // make sure there are no undefined values when we convert to an array again.
26112 5 : v8::Local<v8::Array> array2 = set->AsArray();
26113 5 : uint32_t length = array2->Length();
26114 5 : CHECK_EQ(2U, length);
26115 10 : for (uint32_t i = 0; i < length; i++) {
26116 20 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26117 5 : }
26118 5 : }
26119 :
26120 25880 : TEST(MapDeleteThenAsArray) {
26121 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26122 5 : v8::Isolate* isolate = CcTest::isolate();
26123 5 : v8::HandleScope handle_scope(isolate);
26124 10 : LocalContext env;
26125 :
26126 : // make a Map
26127 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
26128 : v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
26129 5 : CHECK_EQ(3U, map->Size());
26130 :
26131 : // delete the "middle" element (using AsArray to
26132 : // determine which element is the "middle" element)
26133 5 : v8::Local<v8::Array> array1 = map->AsArray();
26134 5 : CHECK_EQ(6U, array1->Length());
26135 : // Map::AsArray returns a flat array, so the second key is at index 2.
26136 10 : v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
26137 10 : CHECK(map->Delete(env.local(), key).FromJust());
26138 :
26139 : // make sure there are no undefined values when we convert to an array again.
26140 5 : v8::Local<v8::Array> array2 = map->AsArray();
26141 5 : uint32_t length = array2->Length();
26142 5 : CHECK_EQ(4U, length);
26143 20 : for (uint32_t i = 0; i < length; i++) {
26144 40 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26145 5 : }
26146 5 : }
26147 :
26148 25880 : TEST(CompatibleReceiverCheckOnCachedICHandler) {
26149 5 : v8::Isolate* isolate = CcTest::isolate();
26150 5 : v8::HandleScope scope(isolate);
26151 5 : v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
26152 5 : v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
26153 : auto returns_42 =
26154 5 : v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
26155 15 : parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
26156 5 : v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
26157 5 : child->Inherit(parent);
26158 10 : LocalContext env;
26159 30 : CHECK(env->Global()
26160 : ->Set(env.local(), v8_str("Child"),
26161 : child->GetFunction(env.local()).ToLocalChecked())
26162 : .FromJust());
26163 :
26164 : // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
26165 : CompileRun(
26166 : "var real = new Child();\n"
26167 : "for (var i = 0; i < 3; ++i) {\n"
26168 : " real.age;\n"
26169 : "}\n");
26170 :
26171 : // Check that the cached stub is never used.
26172 : ExpectInt32(
26173 : "var fake = Object.create(Child.prototype);\n"
26174 : "var result = 0;\n"
26175 : "function test(d) {\n"
26176 : " if (d == 3) return;\n"
26177 : " try {\n"
26178 : " fake.age;\n"
26179 : " result = 1;\n"
26180 : " } catch (e) {\n"
26181 : " }\n"
26182 : " test(d+1);\n"
26183 : "}\n"
26184 : "test(0);\n"
26185 : "result;\n",
26186 10 : 0);
26187 5 : }
26188 :
26189 25881 : THREADED_TEST(ReceiverConversionForAccessors) {
26190 6 : LocalContext env;
26191 6 : v8::Isolate* isolate = CcTest::isolate();
26192 12 : v8::HandleScope scope(isolate);
26193 : Local<v8::FunctionTemplate> acc =
26194 6 : v8::FunctionTemplate::New(isolate, Returns42);
26195 42 : CHECK(env->Global()
26196 : ->Set(env.local(), v8_str("acc"),
26197 : acc->GetFunction(env.local()).ToLocalChecked())
26198 : .FromJust());
26199 :
26200 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
26201 12 : templ->SetAccessorProperty(v8_str("acc"), acc, acc);
26202 6 : Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
26203 :
26204 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
26205 6 : CHECK(CompileRun("(p.acc == 42)")->BooleanValue(isolate));
26206 6 : CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(isolate));
26207 :
26208 6 : CHECK(!CompileRun("Number.prototype.__proto__ = p;"
26209 : "var a = 1;")
26210 : .IsEmpty());
26211 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26212 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26213 :
26214 6 : CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
26215 : "var a = true;")
26216 : .IsEmpty());
26217 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26218 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26219 :
26220 6 : CHECK(!CompileRun("String.prototype.__proto__ = p;"
26221 : "var a = 'foo';")
26222 : .IsEmpty());
26223 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26224 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26225 :
26226 6 : CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(isolate));
26227 6 : CHECK(CompileRun("acc.call(true)==42")->BooleanValue(isolate));
26228 6 : CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(isolate));
26229 6 : CHECK(CompileRun("acc.call(null) == 42")->BooleanValue(isolate));
26230 12 : CHECK(CompileRun("acc.call(undefined) == 42")->BooleanValue(isolate));
26231 6 : }
26232 :
26233 5 : class FutexInterruptionThread : public v8::base::Thread {
26234 : public:
26235 : explicit FutexInterruptionThread(v8::Isolate* isolate)
26236 5 : : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
26237 :
26238 5 : void Run() override {
26239 : // Wait a bit before terminating.
26240 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
26241 5 : isolate_->TerminateExecution();
26242 5 : }
26243 :
26244 : private:
26245 : v8::Isolate* isolate_;
26246 : };
26247 :
26248 :
26249 25880 : TEST(FutexInterruption) {
26250 5 : i::FLAG_harmony_sharedarraybuffer = true;
26251 5 : v8::Isolate* isolate = CcTest::isolate();
26252 5 : v8::HandleScope scope(isolate);
26253 10 : LocalContext env;
26254 :
26255 : FutexInterruptionThread timeout_thread(isolate);
26256 :
26257 10 : v8::TryCatch try_catch(CcTest::isolate());
26258 5 : timeout_thread.Start();
26259 :
26260 : CompileRun(
26261 : "var ab = new SharedArrayBuffer(4);"
26262 : "var i32a = new Int32Array(ab);"
26263 : "Atomics.wait(i32a, 0, 0);");
26264 5 : CHECK(try_catch.HasTerminated());
26265 10 : timeout_thread.Join();
26266 5 : }
26267 :
26268 25881 : THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
26269 6 : i::FLAG_harmony_sharedarraybuffer = true;
26270 6 : LocalContext env;
26271 6 : v8::Isolate* isolate = env->GetIsolate();
26272 12 : v8::HandleScope handle_scope(isolate);
26273 :
26274 : const size_t ab_size = 1024;
26275 : Local<v8::SharedArrayBuffer> ab =
26276 6 : v8::SharedArrayBuffer::New(isolate, ab_size);
26277 12 : ScopedSharedArrayBufferContents contents(ab->Externalize());
26278 :
26279 : // Array buffers should have normal allocation mode.
26280 6 : CHECK_EQ(contents.AllocationMode(),
26281 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
26282 : // The allocation must contain the buffer (normally they will be equal, but
26283 : // this is not required by the contract).
26284 6 : CHECK_NOT_NULL(contents.AllocationBase());
26285 : const uintptr_t alloc =
26286 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
26287 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
26288 6 : CHECK_LE(alloc, data);
26289 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
26290 6 : }
26291 :
26292 : static int nb_uncaught_exception_callback_calls = 0;
26293 :
26294 :
26295 5 : bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
26296 5 : ++nb_uncaught_exception_callback_calls;
26297 5 : return false;
26298 : }
26299 :
26300 :
26301 25880 : TEST(AbortOnUncaughtExceptionNoAbort) {
26302 5 : v8::Isolate* isolate = CcTest::isolate();
26303 5 : v8::HandleScope handle_scope(isolate);
26304 : v8::Local<v8::ObjectTemplate> global_template =
26305 5 : v8::ObjectTemplate::New(isolate);
26306 10 : LocalContext env(nullptr, global_template);
26307 :
26308 5 : i::FLAG_abort_on_uncaught_exception = true;
26309 5 : isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
26310 :
26311 : CompileRun("function boom() { throw new Error(\"boom\") }");
26312 :
26313 5 : v8::Local<v8::Object> global_object = env->Global();
26314 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
26315 20 : global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
26316 :
26317 10 : CHECK(foo->Call(env.local(), global_object, 0, nullptr).IsEmpty());
26318 :
26319 10 : CHECK_EQ(1, nb_uncaught_exception_callback_calls);
26320 5 : }
26321 :
26322 :
26323 25880 : TEST(AccessCheckedIsConcatSpreadable) {
26324 5 : v8::Isolate* isolate = CcTest::isolate();
26325 5 : HandleScope scope(isolate);
26326 10 : LocalContext env;
26327 :
26328 : // Object with access check
26329 5 : Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
26330 5 : spreadable_template->SetAccessCheckCallback(AccessBlocker);
26331 : spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
26332 10 : v8::Boolean::New(isolate, true));
26333 : Local<Object> object =
26334 5 : spreadable_template->NewInstance(env.local()).ToLocalChecked();
26335 :
26336 5 : allowed_access = true;
26337 25 : CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
26338 15 : object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
26339 15 : object->Set(env.local(), 0U, v8_str("a")).FromJust();
26340 15 : object->Set(env.local(), 1U, v8_str("b")).FromJust();
26341 :
26342 : // Access check is allowed, and the object is spread
26343 : CompileRun("var result = [].concat(object)");
26344 : ExpectTrue("Array.isArray(result)");
26345 5 : ExpectString("result[0]", "a");
26346 5 : ExpectString("result[1]", "b");
26347 : ExpectTrue("result.length === 2");
26348 : ExpectTrue("object[Symbol.isConcatSpreadable]");
26349 :
26350 : // If access check fails, the value of @@isConcatSpreadable is ignored
26351 5 : allowed_access = false;
26352 : CompileRun("var result = [].concat(object)");
26353 : ExpectTrue("Array.isArray(result)");
26354 : ExpectTrue("result[0] === object");
26355 : ExpectTrue("result.length === 1");
26356 5 : ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
26357 5 : }
26358 :
26359 :
26360 25880 : TEST(AccessCheckedToStringTag) {
26361 5 : v8::Isolate* isolate = CcTest::isolate();
26362 5 : HandleScope scope(isolate);
26363 10 : LocalContext env;
26364 :
26365 : // Object with access check
26366 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26367 5 : object_template->SetAccessCheckCallback(AccessBlocker);
26368 : Local<Object> object =
26369 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26370 :
26371 5 : allowed_access = true;
26372 25 : env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
26373 20 : object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
26374 10 : .FromJust();
26375 :
26376 : // Access check is allowed, and the toStringTag is read
26377 : CompileRun("var result = Object.prototype.toString.call(object)");
26378 5 : ExpectString("result", "[object hello]");
26379 5 : ExpectString("object[Symbol.toStringTag]", "hello");
26380 :
26381 : // ToString through the API should succeed too.
26382 : String::Utf8Value result_allowed(
26383 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26384 5 : CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
26385 :
26386 : // If access check fails, the value of @@toStringTag is ignored
26387 5 : allowed_access = false;
26388 : CompileRun("var result = Object.prototype.toString.call(object)");
26389 5 : ExpectString("result", "[object Object]");
26390 : ExpectTrue("object[Symbol.toStringTag] === undefined");
26391 :
26392 : // ToString through the API should also fail.
26393 : String::Utf8Value result_denied(
26394 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26395 10 : CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
26396 5 : }
26397 :
26398 25880 : TEST(TemplateIteratorPrototypeIntrinsics) {
26399 5 : v8::Isolate* isolate = CcTest::isolate();
26400 5 : v8::HandleScope scope(isolate);
26401 10 : LocalContext env;
26402 :
26403 : // Object templates.
26404 : {
26405 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26406 : object_template->SetIntrinsicDataProperty(v8_str("iter_proto"),
26407 10 : v8::kIteratorPrototype);
26408 : Local<Object> object =
26409 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26410 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26411 : ExpectTrue("obj.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26412 : }
26413 : // Setting %IteratorProto% on the function object's prototype template.
26414 : {
26415 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26416 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26417 15 : v8_str("iter_proto"), v8::kIteratorPrototype);
26418 : Local<Function> func1 =
26419 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26420 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26421 : Local<Function> func2 =
26422 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26423 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26424 : ExpectTrue(
26425 : "func1.prototype.iter_proto === "
26426 : "[][Symbol.iterator]().__proto__.__proto__");
26427 : ExpectTrue(
26428 : "func2.prototype.iter_proto === "
26429 : "[][Symbol.iterator]().__proto__.__proto__");
26430 : ExpectTrue("func1.prototype.iter_proto === func2.prototype.iter_proto");
26431 :
26432 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26433 25 : CHECK(env->Global()
26434 : ->Set(env.local(), v8_str("instance1"), instance1)
26435 : .FromJust());
26436 : ExpectFalse("instance1.hasOwnProperty('iter_proto')");
26437 : ExpectTrue("'iter_proto' in instance1.__proto__");
26438 : ExpectTrue(
26439 : "instance1.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26440 : }
26441 : // Put %IteratorProto% in a function object's inheritance chain.
26442 : {
26443 : Local<FunctionTemplate> parent_template =
26444 5 : v8::FunctionTemplate::New(isolate);
26445 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26446 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26447 10 : v8::kIteratorPrototype);
26448 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26449 5 : func_template->Inherit(parent_template);
26450 :
26451 : Local<Function> func =
26452 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26453 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26454 : ExpectTrue(
26455 : "func.prototype.__proto__ === "
26456 : "[][Symbol.iterator]().__proto__.__proto__");
26457 :
26458 : Local<Object> func_instance =
26459 5 : func->NewInstance(env.local()).ToLocalChecked();
26460 25 : CHECK(env->Global()
26461 : ->Set(env.local(), v8_str("instance"), func_instance)
26462 : .FromJust());
26463 : ExpectTrue(
26464 : "instance.__proto__.__proto__ === "
26465 : "[][Symbol.iterator]().__proto__.__proto__");
26466 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26467 5 : }
26468 5 : }
26469 :
26470 25880 : TEST(TemplateErrorPrototypeIntrinsics) {
26471 5 : v8::Isolate* isolate = CcTest::isolate();
26472 5 : v8::HandleScope scope(isolate);
26473 10 : LocalContext env;
26474 :
26475 : // Object templates.
26476 : {
26477 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26478 : object_template->SetIntrinsicDataProperty(v8_str("error_proto"),
26479 10 : v8::kErrorPrototype);
26480 : Local<Object> object =
26481 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26482 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26483 : ExpectTrue("obj.error_proto === Error.prototype");
26484 5 : Local<Value> error = v8::Exception::Error(v8_str("error message"));
26485 25 : CHECK(env->Global()->Set(env.local(), v8_str("err"), error).FromJust());
26486 : ExpectTrue("obj.error_proto === Object.getPrototypeOf(err)");
26487 : }
26488 : // Setting %ErrorPrototype% on the function object's prototype template.
26489 : {
26490 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26491 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26492 15 : v8_str("error_proto"), v8::kErrorPrototype);
26493 : Local<Function> func1 =
26494 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26495 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26496 : Local<Function> func2 =
26497 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26498 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26499 : ExpectTrue("func1.prototype.error_proto === Error.prototype");
26500 : ExpectTrue("func2.prototype.error_proto === Error.prototype");
26501 : ExpectTrue("func1.prototype.error_proto === func2.prototype.error_proto");
26502 :
26503 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26504 25 : CHECK(env->Global()
26505 : ->Set(env.local(), v8_str("instance1"), instance1)
26506 : .FromJust());
26507 : ExpectFalse("instance1.hasOwnProperty('error_proto')");
26508 : ExpectTrue("'error_proto' in instance1.__proto__");
26509 : ExpectTrue("instance1.error_proto === Error.prototype");
26510 : }
26511 : // Put %ErrorPrototype% in a function object's inheritance chain.
26512 : {
26513 : Local<FunctionTemplate> parent_template =
26514 5 : v8::FunctionTemplate::New(isolate);
26515 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26516 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26517 10 : v8::kErrorPrototype);
26518 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26519 5 : func_template->Inherit(parent_template);
26520 :
26521 : Local<Function> func =
26522 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26523 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26524 : ExpectTrue("func.prototype.__proto__ === Error.prototype");
26525 :
26526 : Local<Object> func_instance =
26527 5 : func->NewInstance(env.local()).ToLocalChecked();
26528 25 : CHECK(env->Global()
26529 : ->Set(env.local(), v8_str("instance"), func_instance)
26530 : .FromJust());
26531 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26532 : // Now let's check if %ErrorPrototype% properties are in the instance.
26533 : ExpectTrue("'constructor' in instance");
26534 : ExpectTrue("'message' in instance");
26535 : ExpectTrue("'name' in instance");
26536 : ExpectTrue("'toString' in instance");
26537 5 : }
26538 5 : }
26539 :
26540 25880 : TEST(ObjectTemplateArrayProtoIntrinsics) {
26541 5 : v8::Isolate* isolate = CcTest::isolate();
26542 5 : v8::HandleScope scope(isolate);
26543 10 : LocalContext env;
26544 :
26545 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26546 : object_template->SetIntrinsicDataProperty(v8_str("prop_entries"),
26547 10 : v8::kArrayProto_entries);
26548 : object_template->SetIntrinsicDataProperty(v8_str("prop_forEach"),
26549 10 : v8::kArrayProto_forEach);
26550 : object_template->SetIntrinsicDataProperty(v8_str("prop_keys"),
26551 10 : v8::kArrayProto_keys);
26552 : object_template->SetIntrinsicDataProperty(v8_str("prop_values"),
26553 10 : v8::kArrayProto_values);
26554 : Local<Object> object =
26555 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26556 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26557 :
26558 : const struct {
26559 : const char* const object_property_name;
26560 : const char* const array_property_name;
26561 : } intrinsics_comparisons[] = {
26562 : {"prop_entries", "Array.prototype.entries"},
26563 : {"prop_forEach", "Array.prototype.forEach"},
26564 : {"prop_keys", "Array.prototype.keys"},
26565 : {"prop_values", "Array.prototype[Symbol.iterator]"},
26566 5 : };
26567 :
26568 25 : for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) {
26569 : i::ScopedVector<char> test_string(64);
26570 :
26571 : i::SNPrintF(test_string, "typeof obj1.%s",
26572 20 : intrinsics_comparisons[i].object_property_name);
26573 20 : ExpectString(test_string.start(), "function");
26574 :
26575 : i::SNPrintF(test_string, "obj1.%s === %s",
26576 : intrinsics_comparisons[i].object_property_name,
26577 20 : intrinsics_comparisons[i].array_property_name);
26578 : ExpectTrue(test_string.start());
26579 :
26580 : i::SNPrintF(test_string, "obj1.%s = 42",
26581 20 : intrinsics_comparisons[i].object_property_name);
26582 : CompileRun(test_string.start());
26583 :
26584 : i::SNPrintF(test_string, "obj1.%s === %s",
26585 : intrinsics_comparisons[i].object_property_name,
26586 20 : intrinsics_comparisons[i].array_property_name);
26587 : ExpectFalse(test_string.start());
26588 :
26589 : i::SNPrintF(test_string, "typeof obj1.%s",
26590 20 : intrinsics_comparisons[i].object_property_name);
26591 20 : ExpectString(test_string.start(), "number");
26592 5 : }
26593 5 : }
26594 :
26595 25880 : TEST(ObjectTemplatePerContextIntrinsics) {
26596 5 : v8::Isolate* isolate = CcTest::isolate();
26597 5 : v8::HandleScope scope(isolate);
26598 10 : LocalContext env;
26599 :
26600 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26601 : object_template->SetIntrinsicDataProperty(v8_str("values"),
26602 10 : v8::kArrayProto_values);
26603 : Local<Object> object =
26604 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26605 :
26606 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26607 5 : ExpectString("typeof obj1.values", "function");
26608 :
26609 : auto values = Local<Function>::Cast(
26610 15 : object->Get(env.local(), v8_str("values")).ToLocalChecked());
26611 5 : auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
26612 10 : auto ctx = v8::Utils::OpenHandle(*env.local());
26613 20 : CHECK_EQ(*fn->GetCreationContext(), *ctx);
26614 :
26615 : {
26616 5 : LocalContext env2;
26617 : Local<Object> object2 =
26618 5 : object_template->NewInstance(env2.local()).ToLocalChecked();
26619 25 : CHECK(
26620 : env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
26621 5 : ExpectString("typeof obj2.values", "function");
26622 25 : CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
26623 : *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26624 :
26625 : auto values2 = Local<Function>::Cast(
26626 15 : object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26627 5 : auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
26628 10 : auto ctx2 = v8::Utils::OpenHandle(*env2.local());
26629 20 : CHECK_EQ(*fn2->GetCreationContext(), *ctx2);
26630 5 : }
26631 5 : }
26632 :
26633 :
26634 25880 : TEST(Proxy) {
26635 5 : LocalContext context;
26636 5 : v8::Isolate* isolate = CcTest::isolate();
26637 10 : v8::HandleScope scope(isolate);
26638 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
26639 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
26640 :
26641 : v8::Local<v8::Proxy> proxy =
26642 5 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
26643 5 : CHECK(proxy->IsProxy());
26644 5 : CHECK(!target->IsProxy());
26645 5 : CHECK(!proxy->IsRevoked());
26646 10 : CHECK(proxy->GetTarget()->SameValue(target));
26647 10 : CHECK(proxy->GetHandler()->SameValue(handler));
26648 :
26649 5 : proxy->Revoke();
26650 5 : CHECK(proxy->IsProxy());
26651 5 : CHECK(!target->IsProxy());
26652 5 : CHECK(proxy->IsRevoked());
26653 10 : CHECK(proxy->GetTarget()->IsNull());
26654 15 : CHECK(proxy->GetHandler()->IsNull());
26655 5 : }
26656 :
26657 10 : WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
26658 : v8::Isolate* isolate, WeakCallCounter* counter) {
26659 : v8::Locker locker(isolate);
26660 20 : LocalContext env;
26661 20 : HandleScope scope(isolate);
26662 : WeakCallCounterAndPersistent<Value>* val =
26663 10 : new WeakCallCounterAndPersistent<Value>(counter);
26664 20 : val->handle.Reset(isolate, Object::New(isolate));
26665 : val->handle.SetWeak(val, &WeakPointerCallback,
26666 : v8::WeakCallbackType::kParameter);
26667 10 : return val;
26668 : }
26669 :
26670 5 : class MemoryPressureThread : public v8::base::Thread {
26671 : public:
26672 : explicit MemoryPressureThread(v8::Isolate* isolate,
26673 : v8::MemoryPressureLevel level)
26674 : : Thread(Options("MemoryPressureThread")),
26675 : isolate_(isolate),
26676 5 : level_(level) {}
26677 :
26678 5 : void Run() override { isolate_->MemoryPressureNotification(level_); }
26679 :
26680 : private:
26681 : v8::Isolate* isolate_;
26682 : v8::MemoryPressureLevel level_;
26683 : };
26684 :
26685 25880 : TEST(MemoryPressure) {
26686 5 : if (v8::internal::FLAG_optimize_for_size) return;
26687 5 : v8::Isolate* isolate = CcTest::isolate();
26688 : WeakCallCounter counter(1234);
26689 :
26690 : // Check that critical memory pressure notification sets GC interrupt.
26691 5 : auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26692 5 : CHECK(!v8::Locker::IsLocked(isolate));
26693 : {
26694 : v8::Locker locker(isolate);
26695 10 : v8::HandleScope scope(isolate);
26696 10 : LocalContext env;
26697 : MemoryPressureThread memory_pressure_thread(
26698 : isolate, v8::MemoryPressureLevel::kCritical);
26699 5 : memory_pressure_thread.Start();
26700 5 : memory_pressure_thread.Join();
26701 : // This should trigger GC.
26702 5 : CHECK_EQ(0, counter.NumberOfWeakCalls());
26703 : CompileRun("(function noop() { return 0; })()");
26704 10 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26705 : }
26706 5 : delete garbage;
26707 : // Check that critical memory pressure notification triggers GC.
26708 5 : garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26709 : {
26710 : v8::Locker locker(isolate);
26711 : // If isolate is locked, memory pressure notification should trigger GC.
26712 5 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26713 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
26714 5 : CHECK_EQ(2, counter.NumberOfWeakCalls());
26715 : }
26716 5 : delete garbage;
26717 : // Check that moderate memory pressure notification sets GC into memory
26718 : // optimizing mode.
26719 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
26720 5 : CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26721 : // Check that disabling memory pressure returns GC into normal mode.
26722 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
26723 5 : CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26724 : }
26725 :
26726 25880 : TEST(SetIntegrityLevel) {
26727 5 : LocalContext context;
26728 5 : v8::Isolate* isolate = CcTest::isolate();
26729 10 : v8::HandleScope scope(isolate);
26730 :
26731 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
26732 25 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
26733 :
26734 : v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
26735 5 : CHECK(!is_frozen->BooleanValue(isolate));
26736 :
26737 10 : CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
26738 : .FromJust());
26739 :
26740 : is_frozen = CompileRun("Object.isFrozen(o)");
26741 10 : CHECK(is_frozen->BooleanValue(isolate));
26742 5 : }
26743 :
26744 25880 : TEST(PrivateForApiIsNumber) {
26745 5 : LocalContext context;
26746 5 : v8::Isolate* isolate = CcTest::isolate();
26747 10 : v8::HandleScope scope(isolate);
26748 :
26749 : // Shouldn't crash.
26750 10 : v8::Private::ForApi(isolate, v8_str("42"));
26751 5 : }
26752 :
26753 25881 : THREADED_TEST(ImmutableProto) {
26754 6 : LocalContext context;
26755 6 : v8::Isolate* isolate = context->GetIsolate();
26756 12 : v8::HandleScope handle_scope(isolate);
26757 :
26758 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26759 12 : templ->InstanceTemplate()->SetImmutableProto();
26760 :
26761 6 : Local<v8::Object> object = templ->GetFunction(context.local())
26762 6 : .ToLocalChecked()
26763 6 : ->NewInstance(context.local())
26764 : .ToLocalChecked();
26765 :
26766 : // Look up the prototype
26767 : Local<v8::Value> original_proto =
26768 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26769 :
26770 : // Setting the prototype (e.g., to null) throws
26771 12 : CHECK(object->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26772 :
26773 : // The original prototype is still there
26774 : Local<Value> new_proto =
26775 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26776 6 : CHECK(new_proto->IsObject());
26777 12 : CHECK(new_proto.As<v8::Object>()
26778 : ->Equals(context.local(), original_proto)
26779 6 : .FromJust());
26780 6 : }
26781 :
26782 : Local<v8::Context> call_eval_context;
26783 : Local<v8::Function> call_eval_bound_function;
26784 :
26785 10 : static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
26786 : v8::Context::Scope scope(call_eval_context);
26787 : args.GetReturnValue().Set(
26788 : call_eval_bound_function
26789 10 : ->Call(call_eval_context, call_eval_context->Global(), 0, nullptr)
26790 5 : .ToLocalChecked());
26791 5 : }
26792 :
26793 25880 : TEST(CrossActivationEval) {
26794 5 : LocalContext env;
26795 5 : v8::Isolate* isolate = env->GetIsolate();
26796 10 : v8::HandleScope scope(isolate);
26797 : {
26798 5 : call_eval_context = v8::Context::New(isolate);
26799 : v8::Context::Scope scope(call_eval_context);
26800 : call_eval_bound_function =
26801 5 : Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
26802 : }
26803 : env->Global()
26804 : ->Set(env.local(), v8_str("CallEval"),
26805 5 : v8::FunctionTemplate::New(isolate, CallEval)
26806 15 : ->GetFunction(env.local())
26807 25 : .ToLocalChecked())
26808 10 : .FromJust();
26809 : Local<Value> result = CompileRun("CallEval();");
26810 5 : CHECK(result->IsInt32());
26811 15 : CHECK_EQ(1, result->Int32Value(env.local()).FromJust());
26812 5 : }
26813 :
26814 25880 : TEST(EvalInAccessCheckedContext) {
26815 5 : v8::Isolate* isolate = CcTest::isolate();
26816 5 : v8::HandleScope scope(isolate);
26817 :
26818 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26819 :
26820 5 : obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
26821 :
26822 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
26823 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, obj_template);
26824 :
26825 5 : Local<Value> foo = v8_str("foo");
26826 5 : Local<Value> bar = v8_str("bar");
26827 :
26828 : // Set to different domains.
26829 5 : context0->SetSecurityToken(foo);
26830 5 : context1->SetSecurityToken(bar);
26831 :
26832 : // Set up function in context0 that uses eval from context0.
26833 5 : context0->Enter();
26834 : v8::Local<v8::Value> fun = CompileRun(
26835 : "var x = 42;"
26836 : "(function() {"
26837 : " var e = eval;"
26838 : " return function(s) { return e(s); }"
26839 5 : "})()");
26840 5 : context0->Exit();
26841 :
26842 : // Put the function into context1 and call it. Since the access check
26843 : // callback always returns true, the call succeeds even though the tokens
26844 : // are different.
26845 5 : context1->Enter();
26846 20 : context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
26847 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
26848 10 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
26849 5 : context1->Exit();
26850 5 : }
26851 :
26852 25881 : THREADED_TEST(ImmutableProtoWithParent) {
26853 6 : LocalContext context;
26854 6 : v8::Isolate* isolate = context->GetIsolate();
26855 12 : v8::HandleScope handle_scope(isolate);
26856 :
26857 6 : Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
26858 :
26859 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26860 6 : templ->Inherit(parent);
26861 12 : templ->PrototypeTemplate()->SetImmutableProto();
26862 :
26863 : Local<v8::Function> function =
26864 6 : templ->GetFunction(context.local()).ToLocalChecked();
26865 : Local<v8::Object> instance =
26866 6 : function->NewInstance(context.local()).ToLocalChecked();
26867 : Local<v8::Object> prototype =
26868 18 : instance->Get(context.local(), v8_str("__proto__"))
26869 6 : .ToLocalChecked()
26870 6 : ->ToObject(context.local())
26871 6 : .ToLocalChecked();
26872 :
26873 : // Look up the prototype
26874 : Local<v8::Value> original_proto =
26875 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26876 :
26877 : // Setting the prototype (e.g., to null) throws
26878 12 : CHECK(
26879 : prototype->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26880 :
26881 : // The original prototype is still there
26882 : Local<Value> new_proto =
26883 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26884 6 : CHECK(new_proto->IsObject());
26885 12 : CHECK(new_proto.As<v8::Object>()
26886 : ->Equals(context.local(), original_proto)
26887 6 : .FromJust());
26888 6 : }
26889 :
26890 25880 : TEST(InternalFieldsOnGlobalProxy) {
26891 5 : v8::Isolate* isolate = CcTest::isolate();
26892 5 : v8::HandleScope scope(isolate);
26893 :
26894 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26895 5 : obj_template->SetInternalFieldCount(1);
26896 :
26897 5 : v8::Local<v8::Context> context = Context::New(isolate, nullptr, obj_template);
26898 5 : v8::Local<v8::Object> global = context->Global();
26899 5 : CHECK_EQ(1, global->InternalFieldCount());
26900 5 : }
26901 :
26902 25881 : THREADED_TEST(ImmutableProtoGlobal) {
26903 6 : v8::Isolate* isolate = CcTest::isolate();
26904 6 : v8::HandleScope handle_scope(isolate);
26905 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26906 6 : global_template->SetImmutableProto();
26907 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
26908 : Context::Scope context_scope(context);
26909 : v8::Local<Value> result = CompileRun(
26910 : "global = this;"
26911 : "(function() {"
26912 : " try {"
26913 : " global.__proto__ = {};"
26914 : " return 0;"
26915 : " } catch (e) {"
26916 : " return 1;"
26917 : " }"
26918 : "})()");
26919 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 1))
26920 6 : .FromJust());
26921 6 : }
26922 :
26923 25881 : THREADED_TEST(MutableProtoGlobal) {
26924 6 : v8::Isolate* isolate = CcTest::isolate();
26925 6 : v8::HandleScope handle_scope(isolate);
26926 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26927 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
26928 : Context::Scope context_scope(context);
26929 : v8::Local<Value> result = CompileRun(
26930 : "global = this;"
26931 : "(function() {"
26932 : " try {"
26933 : " global.__proto__ = {};"
26934 : " return 0;"
26935 : " } catch (e) {"
26936 : " return 1;"
26937 : " }"
26938 : "})()");
26939 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 0))
26940 6 : .FromJust());
26941 6 : }
26942 :
26943 25880 : TEST(InternalFieldsOnTypedArray) {
26944 5 : LocalContext env;
26945 5 : v8::Isolate* isolate = env->GetIsolate();
26946 10 : v8::HandleScope scope(isolate);
26947 5 : v8::Local<v8::Context> context = env.local();
26948 : Context::Scope context_scope(context);
26949 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
26950 5 : v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
26951 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
26952 10 : CHECK_EQ(static_cast<void*>(nullptr),
26953 : array->GetAlignedPointerFromInternalField(i));
26954 5 : }
26955 5 : }
26956 :
26957 25880 : TEST(InternalFieldsOnDataView) {
26958 5 : LocalContext env;
26959 5 : v8::Isolate* isolate = env->GetIsolate();
26960 10 : v8::HandleScope scope(isolate);
26961 5 : v8::Local<v8::Context> context = env.local();
26962 : Context::Scope context_scope(context);
26963 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
26964 5 : v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
26965 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
26966 10 : CHECK_EQ(static_cast<void*>(nullptr),
26967 : array->GetAlignedPointerFromInternalField(i));
26968 5 : }
26969 5 : }
26970 :
26971 25880 : TEST(SetPrototypeTemplate) {
26972 5 : LocalContext env;
26973 5 : v8::Isolate* isolate = env->GetIsolate();
26974 10 : v8::HandleScope scope(isolate);
26975 :
26976 5 : Local<FunctionTemplate> HTMLElementTemplate = FunctionTemplate::New(isolate);
26977 : Local<FunctionTemplate> HTMLImageElementTemplate =
26978 5 : FunctionTemplate::New(isolate);
26979 5 : HTMLImageElementTemplate->Inherit(HTMLElementTemplate);
26980 :
26981 5 : Local<FunctionTemplate> ImageTemplate = FunctionTemplate::New(isolate);
26982 5 : ImageTemplate->SetPrototypeProviderTemplate(HTMLImageElementTemplate);
26983 :
26984 : Local<Function> HTMLImageElement =
26985 5 : HTMLImageElementTemplate->GetFunction(env.local()).ToLocalChecked();
26986 : Local<Function> Image =
26987 5 : ImageTemplate->GetFunction(env.local()).ToLocalChecked();
26988 :
26989 25 : CHECK(env->Global()
26990 : ->Set(env.local(), v8_str("HTMLImageElement"), HTMLImageElement)
26991 : .FromJust());
26992 25 : CHECK(env->Global()->Set(env.local(), v8_str("Image"), Image).FromJust());
26993 :
26994 5 : ExpectTrue("Image.prototype === HTMLImageElement.prototype");
26995 5 : }
26996 :
26997 120 : void ensure_receiver_is_global_proxy(
26998 : v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
26999 240 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSGlobalProxy());
27000 120 : }
27001 :
27002 25881 : THREADED_TEST(GlobalAccessorInfo) {
27003 6 : v8::Isolate* isolate = CcTest::isolate();
27004 6 : v8::HandleScope scope(isolate);
27005 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
27006 : global_template->SetAccessor(
27007 : v8::String::NewFromUtf8(isolate, "prop", v8::NewStringType::kInternalized)
27008 : .ToLocalChecked(),
27009 12 : &ensure_receiver_is_global_proxy);
27010 12 : LocalContext env(nullptr, global_template);
27011 : CompileRun("for (var i = 0; i < 10; i++) this.prop");
27012 6 : CompileRun("for (var i = 0; i < 10; i++) prop");
27013 6 : }
27014 :
27015 25880 : TEST(DeterministicRandomNumberGeneration) {
27016 5 : v8::HandleScope scope(CcTest::isolate());
27017 :
27018 5 : int previous_seed = v8::internal::FLAG_random_seed;
27019 5 : v8::internal::FLAG_random_seed = 1234;
27020 :
27021 : double first_value;
27022 : double second_value;
27023 : {
27024 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27025 : Context::Scope context_scope(context);
27026 : v8::Local<Value> result = CompileRun("Math.random();");
27027 10 : first_value = result->ToNumber(context).ToLocalChecked()->Value();
27028 : }
27029 : {
27030 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27031 : Context::Scope context_scope(context);
27032 : v8::Local<Value> result = CompileRun("Math.random();");
27033 10 : second_value = result->ToNumber(context).ToLocalChecked()->Value();
27034 : }
27035 5 : CHECK_EQ(first_value, second_value);
27036 :
27037 5 : v8::internal::FLAG_random_seed = previous_seed;
27038 5 : }
27039 :
27040 25880 : UNINITIALIZED_TEST(AllowAtomicsWait) {
27041 : v8::Isolate::CreateParams create_params;
27042 5 : create_params.allow_atomics_wait = false;
27043 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27044 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
27045 10 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27046 : {
27047 5 : CHECK_EQ(false, i_isolate->allow_atomics_wait());
27048 5 : isolate->SetAllowAtomicsWait(true);
27049 5 : CHECK_EQ(true, i_isolate->allow_atomics_wait());
27050 : }
27051 5 : isolate->Dispose();
27052 5 : }
27053 :
27054 : enum ContextId { EnteredContext, CurrentContext };
27055 :
27056 20 : void CheckContexts(v8::Isolate* isolate) {
27057 60 : CHECK_EQ(CurrentContext, isolate->GetCurrentContext()
27058 : ->GetEmbedderData(1)
27059 : .As<v8::Integer>()
27060 : ->Value());
27061 60 : CHECK_EQ(EnteredContext, isolate->GetEnteredOrMicrotaskContext()
27062 : ->GetEmbedderData(1)
27063 : .As<v8::Integer>()
27064 : ->Value());
27065 20 : }
27066 :
27067 5 : void ContextCheckGetter(Local<String> name,
27068 : const v8::PropertyCallbackInfo<v8::Value>& info) {
27069 5 : CheckContexts(info.GetIsolate());
27070 : info.GetReturnValue().Set(true);
27071 5 : }
27072 :
27073 5 : void ContextCheckSetter(Local<String> name, Local<Value>,
27074 : const v8::PropertyCallbackInfo<void>& info) {
27075 5 : CheckContexts(info.GetIsolate());
27076 5 : }
27077 :
27078 20 : void ContextCheckToString(const v8::FunctionCallbackInfo<v8::Value>& info) {
27079 10 : CheckContexts(info.GetIsolate());
27080 10 : info.GetReturnValue().Set(v8_str("foo"));
27081 10 : }
27082 :
27083 25880 : TEST(CorrectEnteredContext) {
27084 5 : v8::HandleScope scope(CcTest::isolate());
27085 :
27086 10 : LocalContext currentContext;
27087 : currentContext->SetEmbedderData(
27088 10 : 1, v8::Integer::New(currentContext->GetIsolate(), CurrentContext));
27089 10 : LocalContext enteredContext;
27090 : enteredContext->SetEmbedderData(
27091 10 : 1, v8::Integer::New(enteredContext->GetIsolate(), EnteredContext));
27092 :
27093 5 : v8::Context::Scope contextScope(enteredContext.local());
27094 :
27095 : v8::Local<v8::ObjectTemplate> object_template =
27096 5 : ObjectTemplate::New(currentContext->GetIsolate());
27097 : object_template->SetAccessor(v8_str("p"), &ContextCheckGetter,
27098 5 : &ContextCheckSetter);
27099 :
27100 : v8::Local<v8::Object> object =
27101 5 : object_template->NewInstance(currentContext.local()).ToLocalChecked();
27102 :
27103 15 : object->Get(currentContext.local(), v8_str("p")).ToLocalChecked();
27104 15 : object->Set(currentContext.local(), v8_str("p"), v8_int(0)).FromJust();
27105 :
27106 : v8::Local<v8::Function> to_string =
27107 10 : v8::Function::New(currentContext.local(), ContextCheckToString)
27108 5 : .ToLocalChecked();
27109 :
27110 10 : to_string->Call(currentContext.local(), object, 0, nullptr).ToLocalChecked();
27111 :
27112 : object
27113 : ->CreateDataProperty(currentContext.local(), v8_str("toString"),
27114 15 : to_string)
27115 10 : .FromJust();
27116 :
27117 10 : object->ToString(currentContext.local()).ToLocalChecked();
27118 5 : }
27119 :
27120 5 : v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
27121 : Local<Context> context, Local<v8::ScriptOrModule> referrer,
27122 : Local<String> specifier) {
27123 5 : CHECK(!referrer.IsEmpty());
27124 : String::Utf8Value referrer_utf8(
27125 10 : context->GetIsolate(), Local<String>::Cast(referrer->GetResourceName()));
27126 5 : CHECK_EQ(0, strcmp("www.google.com", *referrer_utf8));
27127 15 : CHECK(referrer->GetHostDefinedOptions()
27128 : ->Get(context->GetIsolate(), 0)
27129 : ->IsSymbol());
27130 :
27131 5 : CHECK(!specifier.IsEmpty());
27132 10 : String::Utf8Value specifier_utf8(context->GetIsolate(), specifier);
27133 5 : CHECK_EQ(0, strcmp("index.js", *specifier_utf8));
27134 :
27135 : Local<v8::Promise::Resolver> resolver =
27136 5 : v8::Promise::Resolver::New(context).ToLocalChecked();
27137 5 : auto result = v8_str("hello world");
27138 10 : resolver->Resolve(context, result).ToChecked();
27139 10 : return resolver->GetPromise();
27140 : }
27141 :
27142 25880 : TEST(DynamicImport) {
27143 5 : i::FLAG_harmony_dynamic_import = true;
27144 5 : LocalContext context;
27145 5 : v8::Isolate* isolate = context->GetIsolate();
27146 10 : v8::HandleScope scope(isolate);
27147 :
27148 : isolate->SetHostImportModuleDynamicallyCallback(
27149 5 : HostImportModuleDynamicallyCallbackResolve);
27150 :
27151 10 : i::Handle<i::String> url(v8::Utils::OpenHandle(*v8_str("www.google.com")));
27152 10 : i::Handle<i::Object> specifier(v8::Utils::OpenHandle(*v8_str("index.js")));
27153 10 : i::Handle<i::String> result(v8::Utils::OpenHandle(*v8_str("hello world")));
27154 10 : i::Handle<i::String> source(v8::Utils::OpenHandle(*v8_str("foo")));
27155 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27156 5 : i::Handle<i::FixedArray> options = i_isolate->factory()->NewFixedArray(1);
27157 5 : i::Handle<i::Symbol> symbol = i_isolate->factory()->NewSymbol();
27158 10 : options->set(0, *symbol);
27159 5 : i::Handle<i::Script> referrer = i_isolate->factory()->NewScript(source);
27160 10 : referrer->set_name(*url);
27161 5 : referrer->set_host_defined_options(*options);
27162 : i::MaybeHandle<i::JSPromise> maybe_promise =
27163 5 : i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
27164 : i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
27165 5 : isolate->RunMicrotasks();
27166 10 : CHECK(result->Equals(i::String::cast(promise->result())));
27167 5 : }
27168 :
27169 5 : void HostInitializeImportMetaObjectCallbackStatic(Local<Context> context,
27170 : Local<Module> module,
27171 : Local<Object> meta) {
27172 5 : CHECK(!module.IsEmpty());
27173 :
27174 20 : meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
27175 5 : }
27176 :
27177 25880 : TEST(ImportMeta) {
27178 5 : i::FLAG_harmony_dynamic_import = true;
27179 5 : i::FLAG_harmony_import_meta = true;
27180 5 : LocalContext context;
27181 5 : v8::Isolate* isolate = context->GetIsolate();
27182 10 : v8::HandleScope scope(isolate);
27183 :
27184 : isolate->SetHostInitializeImportMetaObjectCallback(
27185 5 : HostInitializeImportMetaObjectCallbackStatic);
27186 :
27187 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27188 5 : Local<String> url = v8_str("www.google.com");
27189 5 : Local<String> source_text = v8_str("import.meta;");
27190 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27191 : Local<v8::Boolean>(), Local<v8::Integer>(),
27192 : Local<v8::Value>(), Local<v8::Boolean>(),
27193 : Local<v8::Boolean>(), True(isolate));
27194 : v8::ScriptCompiler::Source source(source_text, origin);
27195 : Local<Module> module =
27196 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27197 : i::Handle<i::Object> meta =
27198 : i_isolate->RunHostInitializeImportMetaObjectCallback(
27199 5 : v8::Utils::OpenHandle(*module));
27200 10 : CHECK(meta->IsJSObject());
27201 : Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
27202 15 : CHECK(meta_obj->Get(context.local(), v8_str("foo"))
27203 : .ToLocalChecked()
27204 : ->IsString());
27205 15 : CHECK(meta_obj->Get(context.local(), v8_str("zapp"))
27206 : .ToLocalChecked()
27207 : ->IsUndefined());
27208 :
27209 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27210 10 : .ToChecked();
27211 5 : Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
27212 10 : CHECK(result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
27213 5 : }
27214 :
27215 25880 : TEST(GetModuleNamespace) {
27216 5 : LocalContext context;
27217 5 : v8::Isolate* isolate = context->GetIsolate();
27218 10 : v8::HandleScope scope(isolate);
27219 :
27220 5 : Local<String> url = v8_str("www.google.com");
27221 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27222 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27223 : Local<v8::Boolean>(), Local<v8::Integer>(),
27224 : Local<v8::Value>(), Local<v8::Boolean>(),
27225 : Local<v8::Boolean>(), True(isolate));
27226 : v8::ScriptCompiler::Source source(source_text, origin);
27227 : Local<Module> module =
27228 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27229 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27230 10 : .ToChecked();
27231 5 : module->Evaluate(context.local()).ToLocalChecked();
27232 :
27233 5 : Local<Value> ns_val = module->GetModuleNamespace();
27234 5 : CHECK(ns_val->IsModuleNamespaceObject());
27235 : Local<Object> ns = ns_val.As<Object>();
27236 20 : CHECK(ns->Get(context.local(), v8_str("default"))
27237 : .ToLocalChecked()
27238 : ->StrictEquals(v8::Number::New(isolate, 5)));
27239 20 : CHECK(ns->Get(context.local(), v8_str("a"))
27240 : .ToLocalChecked()
27241 5 : ->StrictEquals(v8::Number::New(isolate, 10)));
27242 5 : }
27243 :
27244 25880 : TEST(ModuleGetUnboundModuleScript) {
27245 5 : LocalContext context;
27246 5 : v8::Isolate* isolate = context->GetIsolate();
27247 10 : v8::HandleScope scope(isolate);
27248 :
27249 5 : Local<String> url = v8_str("www.google.com");
27250 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27251 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27252 : Local<v8::Boolean>(), Local<v8::Integer>(),
27253 : Local<v8::Value>(), Local<v8::Boolean>(),
27254 : Local<v8::Boolean>(), True(isolate));
27255 : v8::ScriptCompiler::Source source(source_text, origin);
27256 : Local<Module> module =
27257 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27258 : Local<v8::UnboundModuleScript> sfi_before_instantiation =
27259 5 : module->GetUnboundModuleScript();
27260 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27261 10 : .ToChecked();
27262 : Local<v8::UnboundModuleScript> sfi_after_instantiation =
27263 5 : module->GetUnboundModuleScript();
27264 :
27265 : // Check object identity.
27266 : {
27267 : i::Handle<i::Object> s1 = v8::Utils::OpenHandle(*sfi_before_instantiation);
27268 : i::Handle<i::Object> s2 = v8::Utils::OpenHandle(*sfi_after_instantiation);
27269 15 : CHECK_EQ(*s1, *s2);
27270 5 : }
27271 5 : }
27272 :
27273 25880 : TEST(GlobalTemplateWithDoubleProperty) {
27274 5 : v8::Isolate* isolate = CcTest::isolate();
27275 5 : v8::HandleScope handle_scope(isolate);
27276 :
27277 5 : v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
27278 15 : global->Set(v8_str("double"), v8_num(3.14));
27279 :
27280 5 : v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
27281 :
27282 : v8::Context::Scope context_scope(context);
27283 :
27284 : Local<Value> result = CompileRun("double");
27285 5 : CHECK(result->IsNumber());
27286 15 : CheckDoubleEquals(3.14, result->NumberValue(context).ToChecked());
27287 5 : }
27288 :
27289 25880 : TEST(PrimitiveArray) {
27290 5 : v8::Isolate* isolate = CcTest::isolate();
27291 5 : v8::HandleScope scope(isolate);
27292 10 : LocalContext env;
27293 :
27294 : int length = 5;
27295 5 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 5));
27296 5 : CHECK_EQ(length, array->Length());
27297 :
27298 25 : for (int i = 0; i < length; i++) {
27299 25 : Local<v8::Primitive> item = array->Get(isolate, i);
27300 25 : CHECK(item->IsUndefined());
27301 : }
27302 :
27303 5 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
27304 5 : array->Set(isolate, 0, symbol);
27305 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27306 :
27307 : Local<v8::String> string =
27308 : v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kInternalized)
27309 5 : .ToLocalChecked();
27310 5 : array->Set(isolate, 1, string);
27311 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27312 10 : CHECK(array->Get(isolate, 1)->IsString());
27313 :
27314 5 : Local<v8::Number> num = v8::Number::New(env->GetIsolate(), 3.1415926);
27315 5 : array->Set(isolate, 2, num);
27316 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27317 10 : CHECK(array->Get(isolate, 1)->IsString());
27318 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27319 :
27320 : v8::Local<v8::Boolean> f = v8::False(isolate);
27321 5 : array->Set(isolate, 3, f);
27322 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27323 10 : CHECK(array->Get(isolate, 1)->IsString());
27324 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27325 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
27326 :
27327 5 : v8::Local<v8::Primitive> n = v8::Null(isolate);
27328 5 : array->Set(isolate, 4, n);
27329 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27330 10 : CHECK(array->Get(isolate, 1)->IsString());
27331 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27332 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
27333 15 : CHECK(array->Get(isolate, 4)->IsNull());
27334 5 : }
27335 :
27336 25880 : TEST(PersistentValueMap) {
27337 5 : v8::Isolate* isolate = CcTest::isolate();
27338 5 : v8::HandleScope scope(isolate);
27339 10 : LocalContext env;
27340 :
27341 : v8::PersistentValueMap<
27342 : std::string, v8::Value,
27343 : v8::DefaultPersistentValueMapTraits<std::string, v8::Value>>
27344 : map(isolate);
27345 : v8::Local<v8::Value> value =
27346 : v8::String::NewFromUtf8(isolate, "value",
27347 : v8::NewStringType::kInternalized)
27348 5 : .ToLocalChecked();
27349 20 : map.Set("key", value);
27350 5 : }
27351 :
27352 : namespace {
27353 :
27354 : bool wasm_streaming_callback_got_called = false;
27355 : bool wasm_streaming_data_got_collected = false;
27356 :
27357 8 : void WasmStreamingTestFinalizer(const v8::WeakCallbackInfo<void>& data) {
27358 4 : CHECK(!wasm_streaming_data_got_collected);
27359 4 : wasm_streaming_data_got_collected = true;
27360 4 : i::GlobalHandles::Destroy(reinterpret_cast<i::Address*>(data.GetParameter()));
27361 4 : }
27362 :
27363 4 : void WasmStreamingCallbackTestCallbackIsCalled(
27364 8 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27365 4 : CHECK(!wasm_streaming_callback_got_called);
27366 4 : wasm_streaming_callback_got_called = true;
27367 :
27368 : i::Handle<i::Object> global_handle =
27369 : reinterpret_cast<i::Isolate*>(args.GetIsolate())
27370 : ->global_handles()
27371 4 : ->Create(*v8::Utils::OpenHandle(*args.Data()));
27372 : i::GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
27373 : WasmStreamingTestFinalizer,
27374 4 : v8::WeakCallbackType::kParameter);
27375 4 : }
27376 :
27377 4 : void WasmStreamingCallbackTestOnBytesReceived(
27378 4 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27379 : std::shared_ptr<v8::WasmStreaming> streaming =
27380 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27381 :
27382 : // The first bytes of the WebAssembly magic word.
27383 4 : const uint8_t bytes[]{0x00, 0x61, 0x73};
27384 4 : streaming->OnBytesReceived(bytes, arraysize(bytes));
27385 4 : }
27386 :
27387 4 : void WasmStreamingCallbackTestFinishWithSuccess(
27388 4 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27389 : std::shared_ptr<v8::WasmStreaming> streaming =
27390 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27391 : // The bytes of a minimal WebAssembly module.
27392 4 : const uint8_t bytes[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
27393 4 : streaming->OnBytesReceived(bytes, arraysize(bytes));
27394 4 : streaming->Finish();
27395 4 : }
27396 :
27397 4 : void WasmStreamingCallbackTestFinishWithFailure(
27398 4 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27399 : std::shared_ptr<v8::WasmStreaming> streaming =
27400 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27401 4 : streaming->Finish();
27402 4 : }
27403 :
27404 4 : void WasmStreamingCallbackTestAbortWithReject(
27405 8 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27406 : std::shared_ptr<v8::WasmStreaming> streaming =
27407 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27408 8 : streaming->Abort(v8::Object::New(args.GetIsolate()));
27409 4 : }
27410 :
27411 4 : void WasmStreamingCallbackTestAbortNoReject(
27412 4 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27413 : std::shared_ptr<v8::WasmStreaming> streaming =
27414 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27415 4 : streaming->Abort({});
27416 4 : }
27417 :
27418 24 : void TestWasmStreaming(v8::WasmStreamingCallback callback,
27419 : v8::Promise::PromiseState expected_state) {
27420 24 : CcTest::isolate()->SetWasmStreamingCallback(callback);
27421 24 : LocalContext env;
27422 24 : v8::Isolate* isolate = env->GetIsolate();
27423 48 : v8::HandleScope scope(isolate);
27424 :
27425 : // Call {WebAssembly.compileStreaming} with {null} as parameter. The parameter
27426 : // is only really processed by the embedder, so for this test the value is
27427 : // irrelevant.
27428 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(
27429 : CompileRun("WebAssembly.compileStreaming(null)"));
27430 :
27431 24 : EmptyMessageQueues(isolate);
27432 48 : CHECK_EQ(expected_state, promise->State());
27433 24 : }
27434 :
27435 : } // namespace
27436 :
27437 25879 : TEST(WasmStreamingCallback) {
27438 : TestWasmStreaming(WasmStreamingCallbackTestCallbackIsCalled,
27439 4 : v8::Promise::kPending);
27440 4 : CHECK(wasm_streaming_callback_got_called);
27441 4 : CcTest::CollectAllAvailableGarbage();
27442 4 : CHECK(wasm_streaming_data_got_collected);
27443 4 : }
27444 :
27445 25879 : TEST(WasmStreamingOnBytesReceived) {
27446 : TestWasmStreaming(WasmStreamingCallbackTestOnBytesReceived,
27447 4 : v8::Promise::kPending);
27448 4 : }
27449 :
27450 25879 : TEST(WasmStreamingFinishWithSuccess) {
27451 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithSuccess,
27452 4 : v8::Promise::kFulfilled);
27453 4 : }
27454 :
27455 25879 : TEST(WasmStreamingFinishWithFailure) {
27456 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithFailure,
27457 4 : v8::Promise::kRejected);
27458 4 : }
27459 :
27460 25879 : TEST(WasmStreamingAbortWithReject) {
27461 : TestWasmStreaming(WasmStreamingCallbackTestAbortWithReject,
27462 4 : v8::Promise::kRejected);
27463 4 : }
27464 :
27465 25879 : TEST(WasmStreamingAbortWithoutReject) {
27466 : TestWasmStreaming(WasmStreamingCallbackTestAbortNoReject,
27467 4 : v8::Promise::kPending);
27468 4 : }
27469 :
27470 : enum class AtomicsWaitCallbackAction {
27471 : Interrupt,
27472 : StopAndThrowInFirstCall,
27473 : StopAndThrowInSecondCall,
27474 : StopFromThreadAndThrow,
27475 : KeepWaiting
27476 : };
27477 :
27478 : class StopAtomicsWaitThread;
27479 :
27480 10 : struct AtomicsWaitCallbackInfo {
27481 : v8::Isolate* isolate;
27482 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle;
27483 : std::unique_ptr<StopAtomicsWaitThread> stop_thread;
27484 : AtomicsWaitCallbackAction action;
27485 :
27486 : Local<v8::SharedArrayBuffer> expected_sab;
27487 : v8::Isolate::AtomicsWaitEvent expected_event;
27488 : double expected_timeout;
27489 : int64_t expected_value;
27490 : size_t expected_offset;
27491 :
27492 : size_t ncalls = 0;
27493 : };
27494 :
27495 5 : class StopAtomicsWaitThread : public v8::base::Thread {
27496 : public:
27497 : explicit StopAtomicsWaitThread(AtomicsWaitCallbackInfo* info)
27498 5 : : Thread(Options("StopAtomicsWaitThread")), info_(info) {}
27499 :
27500 5 : void Run() override {
27501 5 : CHECK_NOT_NULL(info_->wake_handle);
27502 5 : info_->wake_handle->Wake();
27503 5 : }
27504 :
27505 : private:
27506 : AtomicsWaitCallbackInfo* info_;
27507 : };
27508 :
27509 65 : void AtomicsWaitCallbackForTesting(
27510 : v8::Isolate::AtomicsWaitEvent event, Local<v8::SharedArrayBuffer> sab,
27511 : size_t offset_in_bytes, int64_t value, double timeout_in_ms,
27512 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle, void* data) {
27513 65 : AtomicsWaitCallbackInfo* info = static_cast<AtomicsWaitCallbackInfo*>(data);
27514 65 : info->ncalls++;
27515 65 : info->wake_handle = wake_handle;
27516 65 : CHECK(sab->StrictEquals(info->expected_sab));
27517 65 : CHECK_EQ(timeout_in_ms, info->expected_timeout);
27518 65 : CHECK_EQ(value, info->expected_value);
27519 65 : CHECK_EQ(offset_in_bytes, info->expected_offset);
27520 :
27521 20 : auto ThrowSomething = [&]() {
27522 40 : info->isolate->ThrowException(v8::Integer::New(info->isolate, 42));
27523 85 : };
27524 :
27525 65 : if (event == v8::Isolate::AtomicsWaitEvent::kStartWait) {
27526 35 : CHECK_NOT_NULL(wake_handle);
27527 35 : switch (info->action) {
27528 : case AtomicsWaitCallbackAction::Interrupt:
27529 5 : info->isolate->TerminateExecution();
27530 5 : break;
27531 : case AtomicsWaitCallbackAction::StopAndThrowInFirstCall:
27532 5 : ThrowSomething();
27533 : V8_FALLTHROUGH;
27534 : case AtomicsWaitCallbackAction::StopAndThrowInSecondCall:
27535 15 : wake_handle->Wake();
27536 15 : break;
27537 : case AtomicsWaitCallbackAction::StopFromThreadAndThrow:
27538 10 : info->stop_thread = v8::base::make_unique<StopAtomicsWaitThread>(info);
27539 10 : info->stop_thread->Start();
27540 5 : break;
27541 : case AtomicsWaitCallbackAction::KeepWaiting:
27542 : break;
27543 : }
27544 : } else {
27545 30 : CHECK_EQ(event, info->expected_event);
27546 30 : CHECK_NULL(wake_handle);
27547 :
27548 30 : if (info->stop_thread) {
27549 5 : info->stop_thread->Join();
27550 5 : info->stop_thread.reset();
27551 : }
27552 :
27553 30 : if (info->action == AtomicsWaitCallbackAction::StopAndThrowInSecondCall ||
27554 : info->action == AtomicsWaitCallbackAction::StopFromThreadAndThrow) {
27555 15 : ThrowSomething();
27556 : }
27557 : }
27558 65 : }
27559 :
27560 25880 : TEST(AtomicsWaitCallback) {
27561 5 : LocalContext env;
27562 5 : v8::Isolate* isolate = env->GetIsolate();
27563 10 : v8::HandleScope scope(isolate);
27564 :
27565 : Local<Value> sab = CompileRun(
27566 : "sab = new SharedArrayBuffer(12);"
27567 : "int32arr = new Int32Array(sab, 4);"
27568 : "sab");
27569 5 : CHECK(sab->IsSharedArrayBuffer());
27570 :
27571 : AtomicsWaitCallbackInfo info;
27572 5 : info.isolate = isolate;
27573 5 : info.expected_sab = sab.As<v8::SharedArrayBuffer>();
27574 5 : isolate->SetAtomicsWaitCallback(AtomicsWaitCallbackForTesting, &info);
27575 :
27576 : {
27577 5 : v8::TryCatch try_catch(isolate);
27578 5 : info.expected_offset = 4;
27579 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27580 5 : info.expected_value = 0;
27581 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
27582 5 : info.action = AtomicsWaitCallbackAction::Interrupt;
27583 5 : info.ncalls = 0;
27584 : CompileRun("Atomics.wait(int32arr, 0, 0);");
27585 10 : CHECK_EQ(info.ncalls, 2);
27586 5 : CHECK(try_catch.HasTerminated());
27587 : }
27588 :
27589 : {
27590 5 : v8::TryCatch try_catch(isolate);
27591 5 : info.expected_offset = 8;
27592 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27593 5 : info.expected_value = 1;
27594 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
27595 5 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
27596 5 : info.ncalls = 0;
27597 : CompileRun("Atomics.wait(int32arr, 1, 1);"); // real value is 0 != 1
27598 10 : CHECK_EQ(info.ncalls, 2);
27599 5 : CHECK(!try_catch.HasCaught());
27600 : }
27601 :
27602 : {
27603 5 : v8::TryCatch try_catch(isolate);
27604 5 : info.expected_offset = 8;
27605 5 : info.expected_timeout = 0.125;
27606 5 : info.expected_value = 0;
27607 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
27608 5 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
27609 5 : info.ncalls = 0;
27610 : CompileRun("Atomics.wait(int32arr, 1, 0, 0.125);"); // timeout
27611 10 : CHECK_EQ(info.ncalls, 2);
27612 5 : CHECK(!try_catch.HasCaught());
27613 : }
27614 :
27615 : {
27616 5 : v8::TryCatch try_catch(isolate);
27617 5 : info.expected_offset = 8;
27618 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27619 5 : info.expected_value = 0;
27620 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27621 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
27622 5 : info.ncalls = 0;
27623 : CompileRun("Atomics.wait(int32arr, 1, 0);");
27624 10 : CHECK_EQ(info.ncalls, 1); // Only one extra call
27625 5 : CHECK(try_catch.HasCaught());
27626 10 : CHECK(try_catch.Exception()->IsInt32());
27627 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27628 : }
27629 :
27630 : {
27631 5 : v8::TryCatch try_catch(isolate);
27632 5 : info.expected_offset = 8;
27633 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27634 5 : info.expected_value = 0;
27635 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27636 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27637 5 : info.ncalls = 0;
27638 : CompileRun("Atomics.wait(int32arr, 1, 0);");
27639 10 : CHECK_EQ(info.ncalls, 2);
27640 5 : CHECK(try_catch.HasCaught());
27641 10 : CHECK(try_catch.Exception()->IsInt32());
27642 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27643 : }
27644 :
27645 : {
27646 : // Same test as before, but with a different `expected_value`.
27647 5 : v8::TryCatch try_catch(isolate);
27648 5 : info.expected_offset = 8;
27649 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27650 5 : info.expected_value = 200;
27651 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27652 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27653 5 : info.ncalls = 0;
27654 : CompileRun(
27655 : "int32arr[1] = 200;"
27656 : "Atomics.wait(int32arr, 1, 200);");
27657 10 : CHECK_EQ(info.ncalls, 2);
27658 5 : CHECK(try_catch.HasCaught());
27659 10 : CHECK(try_catch.Exception()->IsInt32());
27660 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27661 : }
27662 :
27663 : {
27664 : // Wake the `Atomics.wait()` call from a thread.
27665 5 : v8::TryCatch try_catch(isolate);
27666 5 : info.expected_offset = 4;
27667 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
27668 5 : info.expected_value = 0;
27669 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27670 5 : info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
27671 5 : info.ncalls = 0;
27672 : CompileRun("Atomics.wait(int32arr, 0, 0);");
27673 10 : CHECK_EQ(info.ncalls, 2);
27674 5 : CHECK(try_catch.HasCaught());
27675 10 : CHECK(try_catch.Exception()->IsInt32());
27676 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27677 5 : }
27678 5 : }
27679 :
27680 25880 : TEST(BigIntAPI) {
27681 5 : LocalContext env;
27682 5 : v8::Isolate* isolate = env->GetIsolate();
27683 10 : v8::HandleScope scope(isolate);
27684 : bool lossless;
27685 : uint64_t words1[10];
27686 : uint64_t words2[10];
27687 :
27688 : {
27689 : Local<Value> bi = CompileRun("12n");
27690 5 : CHECK(bi->IsBigInt());
27691 :
27692 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 12);
27693 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless), 12);
27694 5 : CHECK_EQ(lossless, true);
27695 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 12);
27696 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 12);
27697 5 : CHECK_EQ(lossless, true);
27698 : }
27699 :
27700 : {
27701 : Local<Value> bi = CompileRun("-12n");
27702 5 : CHECK(bi->IsBigInt());
27703 :
27704 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), static_cast<uint64_t>(-12));
27705 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27706 : static_cast<uint64_t>(-12));
27707 10 : CHECK_EQ(lossless, false);
27708 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -12);
27709 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), -12);
27710 5 : CHECK_EQ(lossless, true);
27711 : }
27712 :
27713 : {
27714 : Local<Value> bi = CompileRun("123456789012345678901234567890n");
27715 5 : CHECK(bi->IsBigInt());
27716 :
27717 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 14083847773837265618ULL);
27718 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27719 : 14083847773837265618ULL);
27720 10 : CHECK_EQ(lossless, false);
27721 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -4362896299872285998LL);
27722 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless),
27723 : -4362896299872285998LL);
27724 10 : CHECK_EQ(lossless, false);
27725 : }
27726 :
27727 : {
27728 : Local<Value> bi = CompileRun("-123456789012345678901234567890n");
27729 5 : CHECK(bi->IsBigInt());
27730 :
27731 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 4362896299872285998LL);
27732 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27733 : 4362896299872285998LL);
27734 10 : CHECK_EQ(lossless, false);
27735 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 4362896299872285998LL);
27736 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 4362896299872285998LL);
27737 10 : CHECK_EQ(lossless, false);
27738 : }
27739 :
27740 : {
27741 : Local<v8::BigInt> bi =
27742 5 : v8::BigInt::NewFromWords(env.local(), 0, 0, words1).ToLocalChecked();
27743 10 : CHECK_EQ(bi->Uint64Value(), 0);
27744 5 : CHECK_EQ(bi->WordCount(), 0);
27745 : }
27746 :
27747 : {
27748 5 : TryCatch try_catch(isolate);
27749 : v8::MaybeLocal<v8::BigInt> bi = v8::BigInt::NewFromWords(
27750 5 : env.local(), 0, std::numeric_limits<int>::max(), words1);
27751 5 : CHECK(bi.IsEmpty());
27752 5 : CHECK(try_catch.HasCaught());
27753 : }
27754 :
27755 : {
27756 5 : TryCatch try_catch(isolate);
27757 : v8::MaybeLocal<v8::BigInt> bi =
27758 5 : v8::BigInt::NewFromWords(env.local(), 0, -1, words1);
27759 5 : CHECK(bi.IsEmpty());
27760 5 : CHECK(try_catch.HasCaught());
27761 : }
27762 :
27763 : {
27764 5 : TryCatch try_catch(isolate);
27765 : v8::MaybeLocal<v8::BigInt> bi =
27766 5 : v8::BigInt::NewFromWords(env.local(), 0, 1 << 30, words1);
27767 5 : CHECK(bi.IsEmpty());
27768 5 : CHECK(try_catch.HasCaught());
27769 : }
27770 :
27771 15 : for (int sign_bit = 0; sign_bit <= 1; sign_bit++) {
27772 10 : words1[0] = 0xffffffff00000000ULL;
27773 10 : words1[1] = 0x00000000ffffffffULL;
27774 : v8::Local<v8::BigInt> bi =
27775 10 : v8::BigInt::NewFromWords(env.local(), sign_bit, 2, words1)
27776 10 : .ToLocalChecked();
27777 10 : CHECK_EQ(bi->Uint64Value(&lossless),
27778 : sign_bit ? static_cast<uint64_t>(-static_cast<int64_t>(words1[0]))
27779 : : words1[0]);
27780 20 : CHECK_EQ(lossless, false);
27781 10 : CHECK_EQ(bi->Int64Value(&lossless), sign_bit
27782 : ? -static_cast<int64_t>(words1[0])
27783 : : static_cast<int64_t>(words1[0]));
27784 20 : CHECK_EQ(lossless, false);
27785 10 : CHECK_EQ(bi->WordCount(), 2);
27786 : int real_sign_bit;
27787 10 : int word_count = arraysize(words2);
27788 10 : bi->ToWordsArray(&real_sign_bit, &word_count, words2);
27789 10 : CHECK_EQ(real_sign_bit, sign_bit);
27790 10 : CHECK_EQ(word_count, 2);
27791 5 : }
27792 5 : }
27793 :
27794 : namespace {
27795 :
27796 : bool wasm_threads_enabled_value = false;
27797 :
27798 10 : bool MockWasmThreadsEnabledCallback(Local<Context>) {
27799 10 : return wasm_threads_enabled_value;
27800 : }
27801 :
27802 : } // namespace
27803 :
27804 25880 : TEST(TestSetWasmThreadsEnabledCallback) {
27805 5 : LocalContext env;
27806 5 : v8::Isolate* isolate = env->GetIsolate();
27807 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27808 10 : v8::HandleScope scope(isolate);
27809 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27810 5 : i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context);
27811 :
27812 : // {Isolate::AreWasmThreadsEnabled} calls the callback set by the embedder if
27813 : // such a callback exists. Otherwise it returns
27814 : // {FLAG_experimental_wasm_threads}. First we test that the flag is returned
27815 : // correctly if no callback is set. Then we test that the flag is ignored if
27816 : // the callback is set.
27817 :
27818 5 : i::FLAG_experimental_wasm_threads = false;
27819 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
27820 :
27821 5 : i::FLAG_experimental_wasm_threads = true;
27822 5 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
27823 :
27824 5 : isolate->SetWasmThreadsEnabledCallback(MockWasmThreadsEnabledCallback);
27825 5 : wasm_threads_enabled_value = false;
27826 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
27827 :
27828 5 : wasm_threads_enabled_value = true;
27829 5 : i::FLAG_experimental_wasm_threads = false;
27830 10 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
27831 5 : }
27832 :
27833 25880 : TEST(TestGetUnwindState) {
27834 5 : LocalContext env;
27835 5 : v8::Isolate* isolate = env->GetIsolate();
27836 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27837 :
27838 5 : v8::UnwindState unwind_state = isolate->GetUnwindState();
27839 5 : v8::MemoryRange builtins_range = unwind_state.embedded_code_range;
27840 :
27841 : // Check that each off-heap builtin is within the builtins code range.
27842 : if (i::FLAG_embedded_builtins) {
27843 7530 : for (int id = 0; id < i::Builtins::builtin_count; id++) {
27844 : if (!i::Builtins::IsIsolateIndependent(id)) continue;
27845 7525 : i::Code builtin = i_isolate->builtins()->builtin(id);
27846 7525 : i::Address start = builtin->InstructionStart();
27847 7525 : i::Address end = start + builtin->InstructionSize();
27848 :
27849 : i::Address builtins_start =
27850 7525 : reinterpret_cast<i::Address>(builtins_range.start);
27851 7525 : CHECK(start >= builtins_start &&
27852 : end < builtins_start + builtins_range.length_in_bytes);
27853 : }
27854 : } else {
27855 : CHECK_EQ(nullptr, builtins_range.start);
27856 : CHECK_EQ(0, builtins_range.length_in_bytes);
27857 : }
27858 :
27859 5 : v8::JSEntryStub js_entry_stub = unwind_state.js_entry_stub;
27860 :
27861 5 : CHECK_EQ(
27862 : i_isolate->heap()->builtin(i::Builtins::kJSEntry)->InstructionStart(),
27863 5 : reinterpret_cast<i::Address>(js_entry_stub.code.start));
27864 5 : }
27865 :
27866 25880 : TEST(MicrotaskContextShouldBeNativeContext) {
27867 5 : LocalContext env;
27868 5 : v8::Isolate* isolate = env->GetIsolate();
27869 10 : v8::HandleScope scope(isolate);
27870 :
27871 15 : auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
27872 : v8::Isolate* isolate = info.GetIsolate();
27873 5 : v8::HandleScope scope(isolate);
27874 : i::Handle<i::Context> context =
27875 10 : v8::Utils::OpenHandle(*isolate->GetEnteredOrMicrotaskContext());
27876 :
27877 10 : CHECK(context->IsNativeContext());
27878 : info.GetReturnValue().SetUndefined();
27879 10 : };
27880 :
27881 5 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
27882 10 : desc->InstanceTemplate()->SetCallAsFunctionHandler(callback);
27883 5 : Local<v8::Object> obj = desc->GetFunction(env.local())
27884 5 : .ToLocalChecked()
27885 5 : ->NewInstance(env.local())
27886 : .ToLocalChecked();
27887 :
27888 25 : CHECK(env->Global()->Set(env.local(), v8_str("callback"), obj).FromJust());
27889 : CompileRun(
27890 : "with({}){(async ()=>{"
27891 : " await 42;"
27892 : "})().then(callback);}");
27893 :
27894 10 : isolate->RunMicrotasks();
27895 5 : }
27896 :
27897 25880 : TEST(PreviewSetKeysIteratorEntriesWithDeleted) {
27898 5 : LocalContext env;
27899 10 : v8::HandleScope handle_scope(env->GetIsolate());
27900 5 : v8::Local<v8::Context> context = env.local();
27901 :
27902 : {
27903 : // Create set, delete entry, create iterator, preview.
27904 : v8::Local<v8::Object> iterator =
27905 : CompileRun("var set = new Set([1,2,3]); set.delete(1); set.keys()")
27906 : ->ToObject(context)
27907 5 : .ToLocalChecked();
27908 : bool is_key;
27909 : v8::Local<v8::Array> entries =
27910 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
27911 5 : CHECK(!is_key);
27912 5 : CHECK_EQ(2, entries->Length());
27913 15 : CHECK_EQ(2, entries->Get(context, 0)
27914 : .ToLocalChecked()
27915 : ->Int32Value(context)
27916 : .FromJust());
27917 15 : CHECK_EQ(3, entries->Get(context, 1)
27918 : .ToLocalChecked()
27919 : ->Int32Value(context)
27920 : .FromJust());
27921 : }
27922 : {
27923 : // Create set, create iterator, delete entry, preview.
27924 : v8::Local<v8::Object> iterator =
27925 : CompileRun("var set = new Set([1,2,3]); set.keys()")
27926 : ->ToObject(context)
27927 5 : .ToLocalChecked();
27928 : CompileRun("set.delete(1);");
27929 : bool is_key;
27930 : v8::Local<v8::Array> entries =
27931 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
27932 5 : CHECK(!is_key);
27933 5 : CHECK_EQ(2, entries->Length());
27934 15 : CHECK_EQ(2, entries->Get(context, 0)
27935 : .ToLocalChecked()
27936 : ->Int32Value(context)
27937 : .FromJust());
27938 15 : CHECK_EQ(3, entries->Get(context, 1)
27939 : .ToLocalChecked()
27940 : ->Int32Value(context)
27941 : .FromJust());
27942 : }
27943 : {
27944 : // Create set, create iterator, delete entry, iterate, preview.
27945 : v8::Local<v8::Object> iterator =
27946 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
27947 : ->ToObject(context)
27948 5 : .ToLocalChecked();
27949 : CompileRun("set.delete(1); it.next();");
27950 : bool is_key;
27951 : v8::Local<v8::Array> entries =
27952 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
27953 5 : CHECK(!is_key);
27954 5 : CHECK_EQ(1, entries->Length());
27955 15 : CHECK_EQ(3, entries->Get(context, 0)
27956 : .ToLocalChecked()
27957 : ->Int32Value(context)
27958 : .FromJust());
27959 : }
27960 : {
27961 : // Create set, create iterator, delete entry, iterate until empty, preview.
27962 : v8::Local<v8::Object> iterator =
27963 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
27964 : ->ToObject(context)
27965 5 : .ToLocalChecked();
27966 : CompileRun("set.delete(1); it.next(); it.next();");
27967 : bool is_key;
27968 : v8::Local<v8::Array> entries =
27969 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
27970 5 : CHECK(!is_key);
27971 5 : CHECK_EQ(0, entries->Length());
27972 : }
27973 : {
27974 : // Create set, create iterator, delete entry, iterate, trigger rehash,
27975 : // preview.
27976 : v8::Local<v8::Object> iterator =
27977 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
27978 : ->ToObject(context)
27979 5 : .ToLocalChecked();
27980 : CompileRun("set.delete(1); it.next();");
27981 : CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
27982 : bool is_key;
27983 : v8::Local<v8::Array> entries =
27984 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
27985 5 : CHECK(!is_key);
27986 5 : CHECK_EQ(17, entries->Length());
27987 85 : for (uint32_t i = 0; i < 17; i++) {
27988 340 : CHECK_EQ(i + 3, entries->Get(context, i)
27989 : .ToLocalChecked()
27990 : ->Int32Value(context)
27991 : .FromJust());
27992 : }
27993 5 : }
27994 5 : }
27995 :
27996 25880 : TEST(PreviewSetValuesIteratorEntriesWithDeleted) {
27997 5 : LocalContext env;
27998 10 : v8::HandleScope handle_scope(env->GetIsolate());
27999 5 : v8::Local<v8::Context> context = env.local();
28000 :
28001 : {
28002 : // Create set, delete entry, create iterator, preview.
28003 : v8::Local<v8::Object> iterator =
28004 : CompileRun("var set = new Set([1,2,3]); set.delete(1); set.values()")
28005 : ->ToObject(context)
28006 5 : .ToLocalChecked();
28007 : bool is_key;
28008 : v8::Local<v8::Array> entries =
28009 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28010 5 : CHECK(!is_key);
28011 5 : CHECK_EQ(2, entries->Length());
28012 15 : CHECK_EQ(2, entries->Get(context, 0)
28013 : .ToLocalChecked()
28014 : ->Int32Value(context)
28015 : .FromJust());
28016 15 : CHECK_EQ(3, entries->Get(context, 1)
28017 : .ToLocalChecked()
28018 : ->Int32Value(context)
28019 : .FromJust());
28020 : }
28021 : {
28022 : // Create set, create iterator, delete entry, preview.
28023 : v8::Local<v8::Object> iterator =
28024 : CompileRun("var set = new Set([1,2,3]); set.values()")
28025 : ->ToObject(context)
28026 5 : .ToLocalChecked();
28027 : CompileRun("set.delete(1);");
28028 : bool is_key;
28029 : v8::Local<v8::Array> entries =
28030 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28031 5 : CHECK(!is_key);
28032 5 : CHECK_EQ(2, entries->Length());
28033 15 : CHECK_EQ(2, entries->Get(context, 0)
28034 : .ToLocalChecked()
28035 : ->Int32Value(context)
28036 : .FromJust());
28037 15 : CHECK_EQ(3, entries->Get(context, 1)
28038 : .ToLocalChecked()
28039 : ->Int32Value(context)
28040 : .FromJust());
28041 : }
28042 : {
28043 : // Create set, create iterator, delete entry, iterate, preview.
28044 : v8::Local<v8::Object> iterator =
28045 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28046 : ->ToObject(context)
28047 5 : .ToLocalChecked();
28048 : CompileRun("set.delete(1); it.next();");
28049 : bool is_key;
28050 : v8::Local<v8::Array> entries =
28051 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28052 5 : CHECK(!is_key);
28053 5 : CHECK_EQ(1, entries->Length());
28054 15 : CHECK_EQ(3, entries->Get(context, 0)
28055 : .ToLocalChecked()
28056 : ->Int32Value(context)
28057 : .FromJust());
28058 : }
28059 : {
28060 : // Create set, create iterator, delete entry, iterate until empty, preview.
28061 : v8::Local<v8::Object> iterator =
28062 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28063 : ->ToObject(context)
28064 5 : .ToLocalChecked();
28065 : CompileRun("set.delete(1); it.next(); it.next();");
28066 : bool is_key;
28067 : v8::Local<v8::Array> entries =
28068 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28069 5 : CHECK(!is_key);
28070 5 : CHECK_EQ(0, entries->Length());
28071 : }
28072 : {
28073 : // Create set, create iterator, delete entry, iterate, trigger rehash,
28074 : // preview.
28075 : v8::Local<v8::Object> iterator =
28076 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28077 : ->ToObject(context)
28078 5 : .ToLocalChecked();
28079 : CompileRun("set.delete(1); it.next();");
28080 : CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28081 : bool is_key;
28082 : v8::Local<v8::Array> entries =
28083 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28084 5 : CHECK(!is_key);
28085 5 : CHECK_EQ(17, entries->Length());
28086 85 : for (uint32_t i = 0; i < 17; i++) {
28087 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28088 : .ToLocalChecked()
28089 : ->Int32Value(context)
28090 : .FromJust());
28091 : }
28092 5 : }
28093 5 : }
28094 :
28095 25880 : TEST(PreviewMapEntriesIteratorEntries) {
28096 5 : LocalContext env;
28097 10 : v8::HandleScope handle_scope(env->GetIsolate());
28098 5 : v8::Local<v8::Context> context = env.local();
28099 : {
28100 : // Create set, delete entry, create entries iterator, preview.
28101 : v8::Local<v8::Object> iterator =
28102 : CompileRun("var set = new Set([1,2,3]); set.delete(2); set.entries()")
28103 : ->ToObject(context)
28104 5 : .ToLocalChecked();
28105 : bool is_key;
28106 : v8::Local<v8::Array> entries =
28107 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28108 5 : CHECK(is_key);
28109 5 : CHECK_EQ(4, entries->Length());
28110 : uint32_t first = entries->Get(context, 0)
28111 5 : .ToLocalChecked()
28112 : ->Int32Value(context)
28113 10 : .FromJust();
28114 : uint32_t second = entries->Get(context, 2)
28115 5 : .ToLocalChecked()
28116 : ->Int32Value(context)
28117 10 : .FromJust();
28118 5 : CHECK_EQ(1, first);
28119 5 : CHECK_EQ(3, second);
28120 15 : CHECK_EQ(first, entries->Get(context, 1)
28121 : .ToLocalChecked()
28122 : ->Int32Value(context)
28123 : .FromJust());
28124 15 : CHECK_EQ(second, entries->Get(context, 3)
28125 : .ToLocalChecked()
28126 : ->Int32Value(context)
28127 : .FromJust());
28128 5 : }
28129 5 : }
28130 :
28131 25880 : TEST(PreviewMapValuesIteratorEntriesWithDeleted) {
28132 5 : LocalContext env;
28133 10 : v8::HandleScope handle_scope(env->GetIsolate());
28134 5 : v8::Local<v8::Context> context = env.local();
28135 :
28136 : {
28137 : // Create map, delete entry, create iterator, preview.
28138 : v8::Local<v8::Object> iterator = CompileRun(
28139 : "var map = new Map();"
28140 : "var key = {}; map.set(key, 1);"
28141 : "map.set({}, 2); map.set({}, 3);"
28142 : "map.delete(key);"
28143 : "map.values()")
28144 : ->ToObject(context)
28145 5 : .ToLocalChecked();
28146 : bool is_key;
28147 : v8::Local<v8::Array> entries =
28148 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28149 5 : CHECK(!is_key);
28150 5 : CHECK_EQ(2, entries->Length());
28151 15 : CHECK_EQ(2, entries->Get(context, 0)
28152 : .ToLocalChecked()
28153 : ->Int32Value(context)
28154 : .FromJust());
28155 15 : CHECK_EQ(3, entries->Get(context, 1)
28156 : .ToLocalChecked()
28157 : ->Int32Value(context)
28158 : .FromJust());
28159 : }
28160 : {
28161 : // Create map, create iterator, delete entry, preview.
28162 : v8::Local<v8::Object> iterator = CompileRun(
28163 : "var map = new Map();"
28164 : "var key = {}; map.set(key, 1);"
28165 : "map.set({}, 2); map.set({}, 3);"
28166 : "map.values()")
28167 : ->ToObject(context)
28168 5 : .ToLocalChecked();
28169 : CompileRun("map.delete(key);");
28170 : bool is_key;
28171 : v8::Local<v8::Array> entries =
28172 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28173 5 : CHECK(!is_key);
28174 5 : CHECK_EQ(2, entries->Length());
28175 15 : CHECK_EQ(2, entries->Get(context, 0)
28176 : .ToLocalChecked()
28177 : ->Int32Value(context)
28178 : .FromJust());
28179 15 : CHECK_EQ(3, entries->Get(context, 1)
28180 : .ToLocalChecked()
28181 : ->Int32Value(context)
28182 : .FromJust());
28183 : }
28184 : {
28185 : // Create map, create iterator, delete entry, iterate, preview.
28186 : v8::Local<v8::Object> iterator = CompileRun(
28187 : "var map = new Map();"
28188 : "var key = {}; map.set(key, 1);"
28189 : "map.set({}, 2); map.set({}, 3);"
28190 : "var it = map.values(); it")
28191 : ->ToObject(context)
28192 5 : .ToLocalChecked();
28193 : CompileRun("map.delete(key); it.next();");
28194 : bool is_key;
28195 : v8::Local<v8::Array> entries =
28196 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28197 5 : CHECK(!is_key);
28198 5 : CHECK_EQ(1, entries->Length());
28199 15 : CHECK_EQ(3, entries->Get(context, 0)
28200 : .ToLocalChecked()
28201 : ->Int32Value(context)
28202 : .FromJust());
28203 : }
28204 : {
28205 : // Create map, create iterator, delete entry, iterate until empty, preview.
28206 : v8::Local<v8::Object> iterator = CompileRun(
28207 : "var map = new Map();"
28208 : "var key = {}; map.set(key, 1);"
28209 : "map.set({}, 2); map.set({}, 3);"
28210 : "var it = map.values(); it")
28211 : ->ToObject(context)
28212 5 : .ToLocalChecked();
28213 : CompileRun("map.delete(key); it.next(); it.next();");
28214 : bool is_key;
28215 : v8::Local<v8::Array> entries =
28216 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28217 5 : CHECK(!is_key);
28218 5 : CHECK_EQ(0, entries->Length());
28219 : }
28220 : {
28221 : // Create map, create iterator, delete entry, iterate, trigger rehash,
28222 : // preview.
28223 : v8::Local<v8::Object> iterator = CompileRun(
28224 : "var map = new Map();"
28225 : "var key = {}; map.set(key, 1);"
28226 : "map.set({}, 2); map.set({}, 3);"
28227 : "var it = map.values(); it")
28228 : ->ToObject(context)
28229 5 : .ToLocalChecked();
28230 : CompileRun("map.delete(key); it.next();");
28231 : CompileRun("for (var i = 4; i < 20; i++) map.set({}, i);");
28232 : bool is_key;
28233 : v8::Local<v8::Array> entries =
28234 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28235 5 : CHECK(!is_key);
28236 5 : CHECK_EQ(17, entries->Length());
28237 85 : for (uint32_t i = 0; i < 17; i++) {
28238 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28239 : .ToLocalChecked()
28240 : ->Int32Value(context)
28241 : .FromJust());
28242 : }
28243 5 : }
28244 5 : }
28245 :
28246 25880 : TEST(PreviewMapKeysIteratorEntriesWithDeleted) {
28247 5 : LocalContext env;
28248 10 : v8::HandleScope handle_scope(env->GetIsolate());
28249 5 : v8::Local<v8::Context> context = env.local();
28250 :
28251 : {
28252 : // Create map, delete entry, create iterator, preview.
28253 : v8::Local<v8::Object> iterator = CompileRun(
28254 : "var map = new Map();"
28255 : "var key = 1; map.set(key, {});"
28256 : "map.set(2, {}); map.set(3, {});"
28257 : "map.delete(key);"
28258 : "map.keys()")
28259 : ->ToObject(context)
28260 5 : .ToLocalChecked();
28261 : bool is_key;
28262 : v8::Local<v8::Array> entries =
28263 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28264 5 : CHECK(!is_key);
28265 5 : CHECK_EQ(2, entries->Length());
28266 15 : CHECK_EQ(2, entries->Get(context, 0)
28267 : .ToLocalChecked()
28268 : ->Int32Value(context)
28269 : .FromJust());
28270 15 : CHECK_EQ(3, entries->Get(context, 1)
28271 : .ToLocalChecked()
28272 : ->Int32Value(context)
28273 : .FromJust());
28274 : }
28275 : {
28276 : // Create map, create iterator, delete entry, preview.
28277 : v8::Local<v8::Object> iterator = CompileRun(
28278 : "var map = new Map();"
28279 : "var key = 1; map.set(key, {});"
28280 : "map.set(2, {}); map.set(3, {});"
28281 : "map.keys()")
28282 : ->ToObject(context)
28283 5 : .ToLocalChecked();
28284 : CompileRun("map.delete(key);");
28285 : bool is_key;
28286 : v8::Local<v8::Array> entries =
28287 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28288 5 : CHECK(!is_key);
28289 5 : CHECK_EQ(2, entries->Length());
28290 15 : CHECK_EQ(2, entries->Get(context, 0)
28291 : .ToLocalChecked()
28292 : ->Int32Value(context)
28293 : .FromJust());
28294 15 : CHECK_EQ(3, entries->Get(context, 1)
28295 : .ToLocalChecked()
28296 : ->Int32Value(context)
28297 : .FromJust());
28298 : }
28299 : {
28300 : // Create map, create iterator, delete entry, iterate, preview.
28301 : v8::Local<v8::Object> iterator = CompileRun(
28302 : "var map = new Map();"
28303 : "var key = 1; map.set(key, {});"
28304 : "map.set(2, {}); map.set(3, {});"
28305 : "var it = map.keys(); it")
28306 : ->ToObject(context)
28307 5 : .ToLocalChecked();
28308 : CompileRun("map.delete(key); it.next();");
28309 : bool is_key;
28310 : v8::Local<v8::Array> entries =
28311 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28312 5 : CHECK(!is_key);
28313 5 : CHECK_EQ(1, entries->Length());
28314 15 : CHECK_EQ(3, entries->Get(context, 0)
28315 : .ToLocalChecked()
28316 : ->Int32Value(context)
28317 : .FromJust());
28318 : }
28319 : {
28320 : // Create map, create iterator, delete entry, iterate until empty, preview.
28321 : v8::Local<v8::Object> iterator = CompileRun(
28322 : "var map = new Map();"
28323 : "var key = 1; map.set(key, {});"
28324 : "map.set(2, {}); map.set(3, {});"
28325 : "var it = map.keys(); it")
28326 : ->ToObject(context)
28327 5 : .ToLocalChecked();
28328 : CompileRun("map.delete(key); it.next(); it.next();");
28329 : bool is_key;
28330 : v8::Local<v8::Array> entries =
28331 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28332 5 : CHECK(!is_key);
28333 5 : CHECK_EQ(0, entries->Length());
28334 5 : }
28335 5 : }
28336 :
28337 : namespace {
28338 : static v8::Isolate* isolate_1;
28339 : static v8::Isolate* isolate_2;
28340 25875 : v8::Persistent<v8::Context> context_1;
28341 25875 : v8::Persistent<v8::Context> context_2;
28342 :
28343 20 : static void CallIsolate1(const v8::FunctionCallbackInfo<v8::Value>& args) {
28344 20 : v8::Isolate::Scope isolate_scope(isolate_1);
28345 40 : v8::HandleScope handle_scope(isolate_1);
28346 : v8::Local<v8::Context> context =
28347 20 : v8::Local<v8::Context>::New(isolate_1, context_1);
28348 : v8::Context::Scope context_scope(context);
28349 : CompileRun("f1() //# sourceURL=isolate1b");
28350 20 : }
28351 :
28352 20 : static void CallIsolate2(const v8::FunctionCallbackInfo<v8::Value>& args) {
28353 20 : v8::Isolate::Scope isolate_scope(isolate_2);
28354 40 : v8::HandleScope handle_scope(isolate_2);
28355 : v8::Local<v8::Context> context =
28356 20 : v8::Local<v8::Context>::New(isolate_2, context_2);
28357 : v8::Context::Scope context_scope(context);
28358 : reinterpret_cast<i::Isolate*>(isolate_2)->heap()->CollectAllGarbage(
28359 : i::Heap::kNoGCFlags, i::GarbageCollectionReason::kTesting,
28360 20 : v8::kGCCallbackFlagForced);
28361 : CompileRun("f2() //# sourceURL=isolate2b");
28362 20 : }
28363 :
28364 : } // anonymous namespace
28365 :
28366 25880 : UNINITIALIZED_TEST(NestedIsolates) {
28367 : #ifdef VERIFY_HEAP
28368 : i::FLAG_verify_heap = true;
28369 : #endif // VERIFY_HEAP
28370 : // Create two isolates and set up C++ functions via function templates that
28371 : // call into the other isolate. Recurse a few times, trigger GC along the way,
28372 : // and finally capture a stack trace. Check that the stack trace only includes
28373 : // frames from its own isolate.
28374 : v8::Isolate::CreateParams create_params;
28375 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
28376 5 : isolate_1 = v8::Isolate::New(create_params);
28377 5 : isolate_2 = v8::Isolate::New(create_params);
28378 :
28379 : {
28380 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28381 10 : v8::HandleScope handle_scope(isolate_1);
28382 :
28383 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_1);
28384 : v8::Context::Scope context_scope(context);
28385 :
28386 : v8::Local<v8::FunctionTemplate> fun_templ =
28387 5 : v8::FunctionTemplate::New(isolate_1, CallIsolate2);
28388 5 : fun_templ->SetClassName(v8_str(isolate_1, "call_isolate_2"));
28389 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28390 20 : CHECK(context->Global()
28391 : ->Set(context, v8_str(isolate_1, "call_isolate_2"), fun)
28392 : .FromJust());
28393 : CompileRun(
28394 : "let c = 0;"
28395 : "function f1() {"
28396 : " c++;"
28397 : " return call_isolate_2();"
28398 : "} //# sourceURL=isolate1a");
28399 5 : context_1.Reset(isolate_1, context);
28400 : }
28401 :
28402 : {
28403 5 : v8::Isolate::Scope isolate_scope(isolate_2);
28404 10 : v8::HandleScope handle_scope(isolate_2);
28405 :
28406 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_2);
28407 : v8::Context::Scope context_scope(context);
28408 :
28409 : v8::Local<v8::FunctionTemplate> fun_templ =
28410 5 : v8::FunctionTemplate::New(isolate_2, CallIsolate1);
28411 5 : fun_templ->SetClassName(v8_str(isolate_2, "call_isolate_1"));
28412 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28413 :
28414 20 : CHECK(context->Global()
28415 : ->Set(context, v8_str(isolate_2, "call_isolate_1"), fun)
28416 : .FromJust());
28417 : CompileRun(
28418 : "let c = 4;"
28419 : "let result = undefined;"
28420 : "function f2() {"
28421 : " if (c-- > 0) return call_isolate_1();"
28422 : " else result = new Error().stack;"
28423 : "} //# sourceURL=isolate2a");
28424 5 : context_2.Reset(isolate_2, context);
28425 :
28426 : v8::Local<v8::String> result =
28427 : CompileRun("f2(); result //# sourceURL=isolate2c")
28428 : ->ToString(context)
28429 5 : .ToLocalChecked();
28430 : v8::Local<v8::String> expectation = v8_str(isolate_2,
28431 : "Error\n"
28432 : " at f2 (isolate2a:1:104)\n"
28433 : " at isolate2b:1:1\n"
28434 : " at f2 (isolate2a:1:71)\n"
28435 : " at isolate2b:1:1\n"
28436 : " at f2 (isolate2a:1:71)\n"
28437 : " at isolate2b:1:1\n"
28438 : " at f2 (isolate2a:1:71)\n"
28439 : " at isolate2b:1:1\n"
28440 : " at f2 (isolate2a:1:71)\n"
28441 5 : " at isolate2c:1:1");
28442 5 : CHECK(result->StrictEquals(expectation));
28443 : }
28444 :
28445 : {
28446 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28447 10 : v8::HandleScope handle_scope(isolate_1);
28448 : v8::Local<v8::Context> context =
28449 5 : v8::Local<v8::Context>::New(isolate_1, context_1);
28450 : v8::Context::Scope context_scope(context);
28451 5 : ExpectInt32("c", 4);
28452 : }
28453 :
28454 5 : isolate_1->Dispose();
28455 5 : isolate_2->Dispose();
28456 77630 : }
|