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 : #include "test/cctest/wasm/wasm-run-utils.h"
69 : #include "test/common/wasm/wasm-macro-gen.h"
70 :
71 : static const bool kLogThreading = false;
72 :
73 : using ::v8::Array;
74 : using ::v8::Boolean;
75 : using ::v8::BooleanObject;
76 : using ::v8::Context;
77 : using ::v8::Extension;
78 : using ::v8::Function;
79 : using ::v8::FunctionTemplate;
80 : using ::v8::HandleScope;
81 : using ::v8::Local;
82 : using ::v8::Maybe;
83 : using ::v8::Message;
84 : using ::v8::MessageCallback;
85 : using ::v8::Module;
86 : using ::v8::Name;
87 : using ::v8::None;
88 : using ::v8::Object;
89 : using ::v8::ObjectTemplate;
90 : using ::v8::Persistent;
91 : using ::v8::PropertyAttribute;
92 : using ::v8::Script;
93 : using ::v8::StackTrace;
94 : using ::v8::String;
95 : using ::v8::Symbol;
96 : using ::v8::TryCatch;
97 : using ::v8::Undefined;
98 : using ::v8::V8;
99 : using ::v8::Value;
100 :
101 :
102 : #define THREADED_PROFILED_TEST(Name) \
103 : static void Test##Name(); \
104 : TEST(Name##WithProfiler) { \
105 : RunWithProfiler(&Test##Name); \
106 : } \
107 : THREADED_TEST(Name)
108 :
109 30 : void RunWithProfiler(void (*test)()) {
110 30 : LocalContext env;
111 60 : v8::HandleScope scope(env->GetIsolate());
112 30 : v8::Local<v8::String> profile_name = v8_str("my_profile1");
113 30 : v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
114 30 : cpu_profiler->StartProfiling(profile_name);
115 30 : (*test)();
116 30 : reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
117 30 : cpu_profiler->Dispose();
118 30 : }
119 :
120 :
121 : static int signature_callback_count;
122 : static Local<Value> signature_expected_receiver;
123 3900 : static void IncrementingSignatureCallback(
124 : const v8::FunctionCallbackInfo<v8::Value>& args) {
125 3900 : ApiTestFuzzer::Fuzz();
126 3900 : signature_callback_count++;
127 11700 : CHECK(signature_expected_receiver->Equals(
128 : args.GetIsolate()->GetCurrentContext(),
129 : args.Holder())
130 : .FromJust());
131 11700 : CHECK(signature_expected_receiver->Equals(
132 : args.GetIsolate()->GetCurrentContext(),
133 : args.This())
134 : .FromJust());
135 : v8::Local<v8::Array> result =
136 3900 : v8::Array::New(args.GetIsolate(), args.Length());
137 7020 : for (int i = 0; i < args.Length(); i++) {
138 6240 : CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
139 : v8::Integer::New(args.GetIsolate(), i), args[i])
140 : .FromJust());
141 : }
142 : args.GetReturnValue().Set(result);
143 3900 : }
144 :
145 :
146 205 : static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
147 : info.GetReturnValue().Set(42);
148 205 : }
149 :
150 :
151 : // Tests that call v8::V8::Dispose() cannot be threaded.
152 26644 : UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
153 5 : CHECK(v8::V8::Initialize());
154 5 : CHECK(v8::V8::Dispose());
155 5 : }
156 :
157 :
158 : // Tests that call v8::V8::Dispose() cannot be threaded.
159 26644 : UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
160 20 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
161 20 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
162 20 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
163 20 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
164 20 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
165 5 : }
166 :
167 : // Tests that Smi::kZero is set up properly.
168 26644 : UNINITIALIZED_TEST(SmiZero) { CHECK_EQ(i::Smi::kZero, i::Smi::kZero); }
169 :
170 26645 : THREADED_TEST(Handles) {
171 12 : v8::HandleScope scope(CcTest::isolate());
172 : Local<Context> local_env;
173 : {
174 6 : LocalContext env;
175 : local_env = env.local();
176 : }
177 :
178 : // Local context should still be live.
179 6 : CHECK(!local_env.IsEmpty());
180 6 : local_env->Enter();
181 :
182 6 : v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
183 6 : CHECK(!undef.IsEmpty());
184 6 : CHECK(undef->IsUndefined());
185 :
186 : const char* source = "1 + 2 + 3";
187 6 : Local<Script> script = v8_compile(source);
188 6 : CHECK_EQ(6, v8_run_int32value(script));
189 :
190 6 : local_env->Exit();
191 6 : }
192 :
193 :
194 26645 : THREADED_TEST(IsolateOfContext) {
195 12 : v8::HandleScope scope(CcTest::isolate());
196 6 : v8::Local<Context> env = Context::New(CcTest::isolate());
197 :
198 6 : CHECK(!env->GetIsolate()->InContext());
199 6 : CHECK(env->GetIsolate() == CcTest::isolate());
200 6 : env->Enter();
201 6 : CHECK(env->GetIsolate()->InContext());
202 6 : CHECK(env->GetIsolate() == CcTest::isolate());
203 6 : env->Exit();
204 6 : CHECK(!env->GetIsolate()->InContext());
205 6 : CHECK(env->GetIsolate() == CcTest::isolate());
206 6 : }
207 :
208 420 : static void TestSignatureLooped(const char* operation, Local<Value> receiver,
209 : v8::Isolate* isolate) {
210 : i::ScopedVector<char> source(200);
211 : i::SNPrintF(source,
212 : "for (var i = 0; i < 10; i++) {"
213 : " %s"
214 : "}",
215 420 : operation);
216 420 : signature_callback_count = 0;
217 420 : signature_expected_receiver = receiver;
218 : bool expected_to_throw = receiver.IsEmpty();
219 840 : v8::TryCatch try_catch(isolate);
220 : CompileRun(source.start());
221 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
222 420 : if (!expected_to_throw) {
223 300 : CHECK_EQ(10, signature_callback_count);
224 : } else {
225 600 : CHECK(v8_str("TypeError: Illegal invocation")
226 : ->Equals(isolate->GetCurrentContext(),
227 : try_catch.Exception()
228 : ->ToString(isolate->GetCurrentContext())
229 : .ToLocalChecked())
230 : .FromJust());
231 : }
232 420 : }
233 :
234 420 : static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
235 : v8::Isolate* isolate) {
236 : i::ScopedVector<char> source(200);
237 : i::SNPrintF(source,
238 : "function test() {"
239 : " %s"
240 : "}"
241 : "try { test() } catch(e) {}"
242 : "try { test() } catch(e) {}"
243 : "%%OptimizeFunctionOnNextCall(test);"
244 : "test()",
245 420 : operation);
246 420 : signature_callback_count = 0;
247 420 : signature_expected_receiver = receiver;
248 : bool expected_to_throw = receiver.IsEmpty();
249 840 : v8::TryCatch try_catch(isolate);
250 : CompileRun(source.start());
251 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
252 420 : if (!expected_to_throw) {
253 300 : CHECK_EQ(3, signature_callback_count);
254 : } else {
255 600 : CHECK(v8_str("TypeError: Illegal invocation")
256 : ->Equals(isolate->GetCurrentContext(),
257 : try_catch.Exception()
258 : ->ToString(isolate->GetCurrentContext())
259 : .ToLocalChecked())
260 : .FromJust());
261 : }
262 420 : }
263 :
264 : static void TestSignature(const char* operation, Local<Value> receiver,
265 : v8::Isolate* isolate) {
266 420 : TestSignatureLooped(operation, receiver, isolate);
267 420 : TestSignatureOptimized(operation, receiver, isolate);
268 : }
269 :
270 26645 : THREADED_TEST(ReceiverSignature) {
271 6 : i::FLAG_allow_natives_syntax = true;
272 6 : LocalContext env;
273 6 : v8::Isolate* isolate = env->GetIsolate();
274 12 : v8::HandleScope scope(isolate);
275 : // Setup templates.
276 6 : v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
277 6 : v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
278 : v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
279 6 : isolate, IncrementingSignatureCallback, Local<Value>(), sig);
280 : v8::Local<v8::FunctionTemplate> callback =
281 6 : v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
282 6 : v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
283 6 : sub_fun->Inherit(fun);
284 : v8::Local<v8::FunctionTemplate> direct_sub_fun =
285 6 : v8::FunctionTemplate::New(isolate);
286 6 : direct_sub_fun->Inherit(fun);
287 : v8::Local<v8::FunctionTemplate> unrel_fun =
288 6 : v8::FunctionTemplate::New(isolate);
289 : // Install properties.
290 6 : v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
291 12 : fun_proto->Set(v8_str("prop_sig"), callback_sig);
292 12 : fun_proto->Set(v8_str("prop"), callback);
293 12 : fun_proto->SetAccessorProperty(
294 6 : v8_str("accessor_sig"), callback_sig, callback_sig);
295 12 : fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
296 : // Instantiate templates.
297 : Local<Value> fun_instance =
298 18 : fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
299 : Local<Value> sub_fun_instance =
300 18 : sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
301 : // Instance template with properties.
302 : v8::Local<v8::ObjectTemplate> direct_instance_templ =
303 6 : direct_sub_fun->InstanceTemplate();
304 12 : direct_instance_templ->Set(v8_str("prop_sig"), callback_sig);
305 12 : direct_instance_templ->Set(v8_str("prop"), callback);
306 12 : direct_instance_templ->SetAccessorProperty(v8_str("accessor_sig"),
307 6 : callback_sig, callback_sig);
308 12 : direct_instance_templ->SetAccessorProperty(v8_str("accessor"), callback,
309 6 : callback);
310 : Local<Value> direct_instance =
311 6 : direct_instance_templ->NewInstance(env.local()).ToLocalChecked();
312 : // Setup global variables.
313 30 : CHECK(env->Global()
314 : ->Set(env.local(), v8_str("Fun"),
315 : fun->GetFunction(env.local()).ToLocalChecked())
316 : .FromJust());
317 30 : CHECK(env->Global()
318 : ->Set(env.local(), v8_str("UnrelFun"),
319 : unrel_fun->GetFunction(env.local()).ToLocalChecked())
320 : .FromJust());
321 24 : CHECK(env->Global()
322 : ->Set(env.local(), v8_str("fun_instance"), fun_instance)
323 : .FromJust());
324 24 : CHECK(env->Global()
325 : ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
326 : .FromJust());
327 24 : CHECK(env->Global()
328 : ->Set(env.local(), v8_str("direct_instance"), direct_instance)
329 : .FromJust());
330 : CompileRun(
331 : "var accessor_sig_key = 'accessor_sig';"
332 : "var accessor_key = 'accessor';"
333 : "var prop_sig_key = 'prop_sig';"
334 : "var prop_key = 'prop';"
335 : ""
336 : "function copy_props(obj) {"
337 : " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
338 : " var source = Fun.prototype;"
339 : " for (var i in keys) {"
340 : " var key = keys[i];"
341 : " var desc = Object.getOwnPropertyDescriptor(source, key);"
342 : " Object.defineProperty(obj, key, desc);"
343 : " }"
344 : "}"
345 : ""
346 : "var plain = {};"
347 : "copy_props(plain);"
348 : "var unrelated = new UnrelFun();"
349 : "copy_props(unrelated);"
350 : "var inherited = { __proto__: fun_instance };"
351 : "var inherited_direct = { __proto__: direct_instance };");
352 : // Test with and without ICs
353 : const char* test_objects[] = {
354 : "fun_instance", "sub_fun_instance", "direct_instance", "plain",
355 6 : "unrelated", "inherited", "inherited_direct"};
356 : unsigned bad_signature_start_offset = 3;
357 90 : for (unsigned i = 0; i < arraysize(test_objects); i++) {
358 : i::ScopedVector<char> source(200);
359 42 : i::SNPrintF(
360 42 : source, "var test_object = %s; test_object", test_objects[i]);
361 : Local<Value> test_object = CompileRun(source.start());
362 : TestSignature("test_object.prop();", test_object, isolate);
363 : TestSignature("test_object.accessor;", test_object, isolate);
364 : TestSignature("test_object[accessor_key];", test_object, isolate);
365 : TestSignature("test_object.accessor = 1;", test_object, isolate);
366 : TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
367 42 : if (i >= bad_signature_start_offset) test_object = Local<Value>();
368 : TestSignature("test_object.prop_sig();", test_object, isolate);
369 : TestSignature("test_object.accessor_sig;", test_object, isolate);
370 : TestSignature("test_object[accessor_sig_key];", test_object, isolate);
371 : TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
372 : TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
373 : }
374 6 : }
375 :
376 :
377 26645 : THREADED_TEST(HulIgennem) {
378 6 : LocalContext env;
379 6 : v8::Isolate* isolate = env->GetIsolate();
380 12 : v8::HandleScope scope(isolate);
381 : v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
382 6 : Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
383 6 : char* value = i::NewArray<char>(undef_str->Utf8Length(isolate) + 1);
384 6 : undef_str->WriteUtf8(isolate, value);
385 6 : CHECK_EQ(0, strcmp(value, "undefined"));
386 : i::DeleteArray(value);
387 6 : }
388 :
389 :
390 26645 : THREADED_TEST(Access) {
391 6 : LocalContext env;
392 6 : v8::Isolate* isolate = env->GetIsolate();
393 12 : v8::HandleScope scope(isolate);
394 6 : Local<v8::Object> obj = v8::Object::New(isolate);
395 : Local<Value> foo_before =
396 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
397 6 : CHECK(foo_before->IsUndefined());
398 6 : Local<String> bar_str = v8_str("bar");
399 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
400 : Local<Value> foo_after =
401 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
402 6 : CHECK(!foo_after->IsUndefined());
403 6 : CHECK(foo_after->IsString());
404 12 : CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
405 :
406 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).ToChecked());
407 : bool result;
408 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).To(&result));
409 6 : CHECK(result);
410 6 : }
411 :
412 :
413 26645 : THREADED_TEST(AccessElement) {
414 6 : LocalContext env;
415 12 : v8::HandleScope scope(env->GetIsolate());
416 6 : Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
417 6 : Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
418 6 : CHECK(before->IsUndefined());
419 6 : Local<String> bar_str = v8_str("bar");
420 12 : CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
421 6 : Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
422 6 : CHECK(!after->IsUndefined());
423 6 : CHECK(after->IsString());
424 12 : CHECK(bar_str->Equals(env.local(), after).FromJust());
425 :
426 : Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
427 24 : CHECK(v8_str("a")
428 : ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
429 : .FromJust());
430 24 : CHECK(v8_str("b")
431 : ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
432 : .FromJust());
433 6 : }
434 :
435 :
436 26645 : THREADED_TEST(Script) {
437 6 : LocalContext env;
438 12 : v8::HandleScope scope(env->GetIsolate());
439 : const char* source = "1 + 2 + 3";
440 6 : Local<Script> script = v8_compile(source);
441 6 : CHECK_EQ(6, v8_run_int32value(script));
442 6 : }
443 :
444 :
445 : class TestResource: public String::ExternalStringResource {
446 : public:
447 : explicit TestResource(uint16_t* data, int* counter = nullptr,
448 : bool owning_data = true)
449 17941 : : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
450 3082581 : while (data[length_]) ++length_;
451 : }
452 :
453 53817 : ~TestResource() override {
454 17941 : if (owning_data_) i::DeleteArray(data_);
455 17941 : if (counter_ != nullptr) ++*counter_;
456 35876 : }
457 :
458 54425 : const uint16_t* data() const override { return data_; }
459 :
460 71698 : size_t length() const override { return length_; }
461 :
462 : private:
463 : uint16_t* data_;
464 : size_t length_;
465 : int* counter_;
466 : bool owning_data_;
467 : };
468 :
469 :
470 : class TestOneByteResource : public String::ExternalOneByteStringResource {
471 : public:
472 : explicit TestOneByteResource(const char* data, int* counter = nullptr,
473 : size_t offset = 0)
474 : : orig_data_(data),
475 10 : data_(data + offset),
476 69 : length_(strlen(data) - offset),
477 148 : counter_(counter) {}
478 :
479 197 : ~TestOneByteResource() override {
480 69 : i::DeleteArray(orig_data_);
481 69 : if (counter_ != nullptr) ++*counter_;
482 128 : }
483 :
484 194 : const char* data() const override { return data_; }
485 :
486 183 : size_t length() const override { return length_; }
487 :
488 : private:
489 : const char* orig_data_;
490 : const char* data_;
491 : size_t length_;
492 : int* counter_;
493 : };
494 :
495 :
496 26645 : THREADED_TEST(ScriptUsingStringResource) {
497 6 : int dispose_count = 0;
498 : const char* c_source = "1 + 2 * 3";
499 6 : uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
500 : {
501 6 : LocalContext env;
502 12 : v8::HandleScope scope(env->GetIsolate());
503 6 : TestResource* resource = new TestResource(two_byte_source, &dispose_count);
504 : Local<String> source =
505 6 : String::NewExternalTwoByte(env->GetIsolate(), resource)
506 : .ToLocalChecked();
507 6 : Local<Script> script = v8_compile(source);
508 6 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
509 6 : CHECK(value->IsNumber());
510 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
511 6 : CHECK(source->IsExternal());
512 6 : CHECK_EQ(resource,
513 : static_cast<TestResource*>(source->GetExternalStringResource()));
514 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
515 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
516 : source->GetExternalStringResourceBase(&encoding));
517 6 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
518 6 : CcTest::CollectAllGarbage();
519 6 : CHECK_EQ(0, dispose_count);
520 : }
521 6 : CcTest::i_isolate()->compilation_cache()->Clear();
522 6 : CcTest::CollectAllAvailableGarbage();
523 6 : CHECK_EQ(1, dispose_count);
524 6 : }
525 :
526 :
527 26645 : THREADED_TEST(ScriptUsingOneByteStringResource) {
528 6 : int dispose_count = 0;
529 : const char* c_source = "1 + 2 * 3";
530 : {
531 6 : LocalContext env;
532 12 : v8::HandleScope scope(env->GetIsolate());
533 : TestOneByteResource* resource =
534 6 : new TestOneByteResource(i::StrDup(c_source), &dispose_count);
535 : Local<String> source =
536 6 : String::NewExternalOneByte(env->GetIsolate(), resource)
537 : .ToLocalChecked();
538 6 : CHECK(source->IsExternalOneByte());
539 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
540 : source->GetExternalOneByteStringResource());
541 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
542 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
543 : source->GetExternalStringResourceBase(&encoding));
544 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
545 6 : Local<Script> script = v8_compile(source);
546 6 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
547 6 : CHECK(value->IsNumber());
548 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
549 6 : CcTest::CollectAllGarbage();
550 6 : CHECK_EQ(0, dispose_count);
551 : }
552 6 : CcTest::i_isolate()->compilation_cache()->Clear();
553 6 : CcTest::CollectAllAvailableGarbage();
554 6 : CHECK_EQ(1, dispose_count);
555 6 : }
556 :
557 :
558 26645 : THREADED_TEST(ScriptMakingExternalString) {
559 6 : int dispose_count = 0;
560 6 : uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
561 : {
562 6 : LocalContext env;
563 12 : v8::HandleScope scope(env->GetIsolate());
564 : Local<String> source =
565 6 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
566 6 : v8::NewStringType::kNormal)
567 : .ToLocalChecked();
568 : // Trigger GCs so that the newly allocated string moves to old gen.
569 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
570 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
571 6 : CHECK(!source->IsExternal());
572 6 : CHECK(!source->IsExternalOneByte());
573 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
574 6 : CHECK(!source->GetExternalStringResourceBase(&encoding));
575 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
576 6 : bool success = source->MakeExternal(new TestResource(two_byte_source,
577 6 : &dispose_count));
578 6 : CHECK(success);
579 6 : Local<Script> script = v8_compile(source);
580 6 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
581 6 : CHECK(value->IsNumber());
582 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
583 6 : CcTest::CollectAllGarbage();
584 6 : CHECK_EQ(0, dispose_count);
585 : }
586 6 : CcTest::i_isolate()->compilation_cache()->Clear();
587 6 : CcTest::CollectAllGarbage();
588 6 : CHECK_EQ(1, dispose_count);
589 6 : }
590 :
591 :
592 26645 : THREADED_TEST(ScriptMakingExternalOneByteString) {
593 6 : int dispose_count = 0;
594 : const char* c_source = "1 + 2 * 3";
595 : {
596 6 : LocalContext env;
597 12 : v8::HandleScope scope(env->GetIsolate());
598 6 : Local<String> source = v8_str(c_source);
599 : // Trigger GCs so that the newly allocated string moves to old gen.
600 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
601 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
602 6 : bool success = source->MakeExternal(
603 6 : new TestOneByteResource(i::StrDup(c_source), &dispose_count));
604 6 : CHECK(success);
605 6 : Local<Script> script = v8_compile(source);
606 6 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
607 6 : CHECK(value->IsNumber());
608 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
609 6 : CcTest::CollectAllGarbage();
610 6 : CHECK_EQ(0, dispose_count);
611 : }
612 6 : CcTest::i_isolate()->compilation_cache()->Clear();
613 6 : CcTest::CollectAllGarbage();
614 6 : CHECK_EQ(1, dispose_count);
615 6 : }
616 :
617 :
618 26644 : TEST(MakingExternalStringConditions) {
619 5 : LocalContext env;
620 10 : v8::HandleScope scope(env->GetIsolate());
621 :
622 : // Free some space in the new space so that we can check freshness.
623 5 : CcTest::CollectGarbage(i::NEW_SPACE);
624 5 : CcTest::CollectGarbage(i::NEW_SPACE);
625 :
626 5 : uint16_t* two_byte_string = AsciiToTwoByteString("s1");
627 : Local<String> tiny_local_string =
628 5 : String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
629 5 : v8::NewStringType::kNormal)
630 : .ToLocalChecked();
631 : i::DeleteArray(two_byte_string);
632 :
633 5 : two_byte_string = AsciiToTwoByteString("s1234");
634 : Local<String> local_string =
635 5 : String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
636 5 : v8::NewStringType::kNormal)
637 : .ToLocalChecked();
638 : i::DeleteArray(two_byte_string);
639 :
640 : // We should refuse to externalize new space strings.
641 5 : CHECK(!local_string->CanMakeExternal());
642 : // Trigger GCs so that the newly allocated string moves to old gen.
643 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
644 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
645 : // Old space strings should be accepted.
646 5 : CHECK(local_string->CanMakeExternal());
647 :
648 : // Tiny strings are not in-place externalizable when pointer compression is
649 : // enabled.
650 5 : CHECK_EQ(i::kTaggedSize == i::kSystemPointerSize,
651 : tiny_local_string->CanMakeExternal());
652 5 : }
653 :
654 :
655 26644 : TEST(MakingExternalOneByteStringConditions) {
656 5 : LocalContext env;
657 10 : v8::HandleScope scope(env->GetIsolate());
658 :
659 : // Free some space in the new space so that we can check freshness.
660 5 : CcTest::CollectGarbage(i::NEW_SPACE);
661 5 : CcTest::CollectGarbage(i::NEW_SPACE);
662 :
663 5 : Local<String> tiny_local_string = v8_str("s");
664 5 : Local<String> local_string = v8_str("s1234");
665 : // We should refuse to externalize new space strings.
666 5 : CHECK(!local_string->CanMakeExternal());
667 : // Trigger GCs so that the newly allocated string moves to old gen.
668 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
669 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
670 : // Old space strings should be accepted.
671 5 : CHECK(local_string->CanMakeExternal());
672 :
673 : // Tiny strings are not in-place externalizable when pointer compression is
674 : // enabled.
675 5 : CHECK_EQ(i::kTaggedSize == i::kSystemPointerSize,
676 : tiny_local_string->CanMakeExternal());
677 5 : }
678 :
679 :
680 26644 : TEST(MakingExternalUnalignedOneByteString) {
681 5 : LocalContext env;
682 10 : v8::HandleScope scope(env->GetIsolate());
683 :
684 : CompileRun("function cons(a, b) { return a + b; }"
685 : "function slice(a) { return a.substring(1); }");
686 : // Create a cons string that will land in old pointer space.
687 : Local<String> cons = Local<String>::Cast(CompileRun(
688 : "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
689 : // Create a sliced string that will land in old pointer space.
690 : Local<String> slice = Local<String>::Cast(CompileRun(
691 : "slice('abcdefghijklmnopqrstuvwxyz');"));
692 :
693 : // Trigger GCs so that the newly allocated string moves to old gen.
694 5 : i::heap::SimulateFullSpace(CcTest::heap()->old_space());
695 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
696 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
697 :
698 : // Turn into external string with unaligned resource data.
699 : const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
700 5 : bool success = cons->MakeExternal(
701 5 : new TestOneByteResource(i::StrDup(c_cons), nullptr, 1));
702 5 : CHECK(success);
703 : const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
704 5 : success = slice->MakeExternal(
705 5 : new TestOneByteResource(i::StrDup(c_slice), nullptr, 1));
706 5 : CHECK(success);
707 :
708 : // Trigger GCs and force evacuation.
709 5 : CcTest::CollectAllGarbage();
710 5 : CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask,
711 5 : i::GarbageCollectionReason::kTesting);
712 5 : }
713 :
714 26645 : THREADED_TEST(UsingExternalString) {
715 : i::Factory* factory = CcTest::i_isolate()->factory();
716 : {
717 12 : v8::HandleScope scope(CcTest::isolate());
718 6 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
719 : Local<String> string =
720 6 : String::NewExternalTwoByte(CcTest::isolate(),
721 12 : new TestResource(two_byte_string))
722 : .ToLocalChecked();
723 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
724 : // Trigger GCs so that the newly allocated string moves to old gen.
725 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
726 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
727 : i::Handle<i::String> isymbol =
728 6 : factory->InternalizeString(istring);
729 12 : CHECK(isymbol->IsInternalizedString());
730 : }
731 6 : CcTest::CollectAllGarbage();
732 6 : CcTest::CollectAllGarbage();
733 6 : }
734 :
735 :
736 26645 : THREADED_TEST(UsingExternalOneByteString) {
737 : i::Factory* factory = CcTest::i_isolate()->factory();
738 : {
739 12 : v8::HandleScope scope(CcTest::isolate());
740 : const char* one_byte_string = "test string";
741 : Local<String> string =
742 6 : String::NewExternalOneByte(
743 : CcTest::isolate(),
744 12 : new TestOneByteResource(i::StrDup(one_byte_string)))
745 : .ToLocalChecked();
746 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
747 : // Trigger GCs so that the newly allocated string moves to old gen.
748 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
749 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
750 : i::Handle<i::String> isymbol =
751 6 : factory->InternalizeString(istring);
752 12 : CHECK(isymbol->IsInternalizedString());
753 : }
754 6 : CcTest::CollectAllGarbage();
755 6 : CcTest::CollectAllGarbage();
756 6 : }
757 :
758 :
759 12 : class RandomLengthResource : public v8::String::ExternalStringResource {
760 : public:
761 6 : explicit RandomLengthResource(int length) : length_(length) {}
762 6 : const uint16_t* data() const override { return string_; }
763 6 : size_t length() const override { return length_; }
764 :
765 : private:
766 : uint16_t string_[10];
767 : int length_;
768 : };
769 :
770 :
771 22 : class RandomLengthOneByteResource
772 : : public v8::String::ExternalOneByteStringResource {
773 : public:
774 11 : explicit RandomLengthOneByteResource(int length) : length_(length) {}
775 16 : const char* data() const override { return string_; }
776 26 : size_t length() const override { return length_; }
777 :
778 : private:
779 : char string_[10];
780 : int length_;
781 : };
782 :
783 :
784 26645 : THREADED_TEST(NewExternalForVeryLongString) {
785 6 : auto isolate = CcTest::isolate();
786 : {
787 12 : v8::HandleScope scope(isolate);
788 12 : v8::TryCatch try_catch(isolate);
789 : RandomLengthOneByteResource r(1 << 30);
790 : v8::MaybeLocal<v8::String> maybe_str =
791 6 : v8::String::NewExternalOneByte(isolate, &r);
792 6 : CHECK(maybe_str.IsEmpty());
793 6 : CHECK(!try_catch.HasCaught());
794 : }
795 :
796 : {
797 12 : v8::HandleScope scope(isolate);
798 12 : v8::TryCatch try_catch(isolate);
799 : RandomLengthResource r(1 << 30);
800 : v8::MaybeLocal<v8::String> maybe_str =
801 6 : v8::String::NewExternalTwoByte(isolate, &r);
802 6 : CHECK(maybe_str.IsEmpty());
803 6 : CHECK(!try_catch.HasCaught());
804 : }
805 6 : }
806 :
807 26644 : TEST(ScavengeExternalString) {
808 : ManualGCScope manual_gc_scope;
809 5 : i::FLAG_stress_compaction = false;
810 5 : i::FLAG_gc_global = false;
811 5 : int dispose_count = 0;
812 : bool in_young_generation = false;
813 : {
814 10 : v8::HandleScope scope(CcTest::isolate());
815 5 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
816 : Local<String> string =
817 5 : String::NewExternalTwoByte(
818 : CcTest::isolate(),
819 10 : new TestResource(two_byte_string, &dispose_count))
820 : .ToLocalChecked();
821 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
822 5 : CcTest::CollectGarbage(i::NEW_SPACE);
823 : in_young_generation = i::Heap::InYoungGeneration(*istring);
824 10 : CHECK_IMPLIES(!in_young_generation,
825 : CcTest::heap()->old_space()->Contains(*istring));
826 5 : CHECK_EQ(0, dispose_count);
827 : }
828 5 : CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
829 5 : CHECK_EQ(1, dispose_count);
830 5 : }
831 :
832 26644 : TEST(ScavengeExternalOneByteString) {
833 : ManualGCScope manual_gc_scope;
834 5 : i::FLAG_stress_compaction = false;
835 5 : i::FLAG_gc_global = false;
836 5 : int dispose_count = 0;
837 : bool in_young_generation = false;
838 : {
839 10 : v8::HandleScope scope(CcTest::isolate());
840 : const char* one_byte_string = "test string";
841 : Local<String> string =
842 5 : String::NewExternalOneByte(
843 : CcTest::isolate(),
844 10 : new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
845 : .ToLocalChecked();
846 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
847 5 : CcTest::CollectGarbage(i::NEW_SPACE);
848 : in_young_generation = i::Heap::InYoungGeneration(*istring);
849 10 : CHECK_IMPLIES(!in_young_generation,
850 : CcTest::heap()->old_space()->Contains(*istring));
851 5 : CHECK_EQ(0, dispose_count);
852 : }
853 5 : CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
854 5 : CHECK_EQ(1, dispose_count);
855 5 : }
856 :
857 :
858 10 : class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
859 : public:
860 : // Only used by non-threaded tests, so it can use static fields.
861 : static int dispose_calls;
862 : static int dispose_count;
863 :
864 : TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
865 10 : : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
866 :
867 10 : void Dispose() override {
868 10 : ++dispose_calls;
869 10 : if (dispose_) delete this;
870 10 : }
871 : private:
872 : bool dispose_;
873 : };
874 :
875 :
876 : int TestOneByteResourceWithDisposeControl::dispose_count = 0;
877 : int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
878 :
879 :
880 26644 : TEST(ExternalStringWithDisposeHandling) {
881 : const char* c_source = "1 + 2 * 3";
882 :
883 : // Use a stack allocated external string resource allocated object.
884 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
885 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
886 5 : TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
887 : {
888 5 : LocalContext env;
889 10 : v8::HandleScope scope(env->GetIsolate());
890 : Local<String> source =
891 5 : String::NewExternalOneByte(env->GetIsolate(), &res_stack)
892 5 : .ToLocalChecked();
893 5 : Local<Script> script = v8_compile(source);
894 5 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
895 5 : CHECK(value->IsNumber());
896 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
897 5 : CcTest::CollectAllAvailableGarbage();
898 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
899 : }
900 5 : CcTest::i_isolate()->compilation_cache()->Clear();
901 5 : CcTest::CollectAllAvailableGarbage();
902 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
903 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
904 :
905 : // Use a heap allocated external string resource allocated object.
906 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
907 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
908 : TestOneByteResource* res_heap =
909 5 : new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
910 : {
911 5 : LocalContext env;
912 10 : v8::HandleScope scope(env->GetIsolate());
913 : Local<String> source =
914 5 : String::NewExternalOneByte(env->GetIsolate(), res_heap)
915 5 : .ToLocalChecked();
916 5 : Local<Script> script = v8_compile(source);
917 5 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
918 5 : CHECK(value->IsNumber());
919 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
920 5 : CcTest::CollectAllAvailableGarbage();
921 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
922 : }
923 5 : CcTest::i_isolate()->compilation_cache()->Clear();
924 5 : CcTest::CollectAllAvailableGarbage();
925 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
926 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
927 5 : }
928 :
929 :
930 26645 : THREADED_TEST(StringConcat) {
931 : {
932 6 : LocalContext env;
933 6 : v8::Isolate* isolate = env->GetIsolate();
934 12 : v8::HandleScope scope(isolate);
935 : const char* one_byte_string_1 = "function a_times_t";
936 : const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
937 : const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
938 : const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
939 : const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
940 : const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
941 : const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
942 6 : Local<String> left = v8_str(one_byte_string_1);
943 :
944 6 : uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
945 : Local<String> right =
946 6 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
947 6 : v8::NewStringType::kNormal)
948 6 : .ToLocalChecked();
949 : i::DeleteArray(two_byte_source);
950 :
951 6 : Local<String> source = String::Concat(isolate, left, right);
952 6 : right = String::NewExternalOneByte(
953 : env->GetIsolate(),
954 12 : new TestOneByteResource(i::StrDup(one_byte_extern_1)))
955 6 : .ToLocalChecked();
956 6 : source = String::Concat(isolate, source, right);
957 6 : right = String::NewExternalTwoByte(
958 : env->GetIsolate(),
959 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
960 6 : .ToLocalChecked();
961 6 : source = String::Concat(isolate, source, right);
962 6 : right = v8_str(one_byte_string_2);
963 6 : source = String::Concat(isolate, source, right);
964 :
965 6 : two_byte_source = AsciiToTwoByteString(two_byte_string_2);
966 6 : right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
967 6 : v8::NewStringType::kNormal)
968 6 : .ToLocalChecked();
969 : i::DeleteArray(two_byte_source);
970 :
971 6 : source = String::Concat(isolate, source, right);
972 6 : right = String::NewExternalTwoByte(
973 : env->GetIsolate(),
974 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
975 6 : .ToLocalChecked();
976 6 : source = String::Concat(isolate, source, right);
977 6 : Local<Script> script = v8_compile(source);
978 6 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
979 6 : CHECK(value->IsNumber());
980 12 : CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
981 : }
982 6 : CcTest::i_isolate()->compilation_cache()->Clear();
983 6 : CcTest::CollectAllGarbage();
984 6 : CcTest::CollectAllGarbage();
985 6 : }
986 :
987 :
988 26645 : THREADED_TEST(GlobalProperties) {
989 6 : LocalContext env;
990 12 : v8::HandleScope scope(env->GetIsolate());
991 6 : v8::Local<v8::Object> global = env->Global();
992 18 : CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
993 18 : Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
994 12 : CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
995 6 : }
996 :
997 :
998 660 : static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
999 : i::Address callback) {
1000 660 : ApiTestFuzzer::Fuzz();
1001 660 : CheckReturnValue(info, callback);
1002 660 : info.GetReturnValue().Set(v8_str("bad value"));
1003 660 : info.GetReturnValue().Set(v8_num(102));
1004 660 : }
1005 :
1006 :
1007 330 : static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1008 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1009 : }
1010 :
1011 :
1012 330 : static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1013 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1014 : }
1015 :
1016 22 : static void construct_callback(
1017 : const v8::FunctionCallbackInfo<Value>& info) {
1018 22 : ApiTestFuzzer::Fuzz();
1019 22 : CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1020 88 : CHECK(
1021 : info.This()
1022 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
1023 : .FromJust());
1024 88 : CHECK(
1025 : info.This()
1026 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
1027 : .FromJust());
1028 22 : info.GetReturnValue().Set(v8_str("bad value"));
1029 : info.GetReturnValue().Set(info.This());
1030 22 : }
1031 :
1032 :
1033 330 : static void Return239Callback(
1034 : Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1035 330 : ApiTestFuzzer::Fuzz();
1036 330 : CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1037 330 : info.GetReturnValue().Set(v8_str("bad value"));
1038 330 : info.GetReturnValue().Set(v8_num(239));
1039 330 : }
1040 :
1041 :
1042 : template<typename Handler>
1043 11 : static void TestFunctionTemplateInitializer(Handler handler,
1044 : Handler handler_2) {
1045 : // Test constructor calls.
1046 : {
1047 11 : LocalContext env;
1048 11 : v8::Isolate* isolate = env->GetIsolate();
1049 22 : v8::HandleScope scope(isolate);
1050 :
1051 : Local<v8::FunctionTemplate> fun_templ =
1052 11 : v8::FunctionTemplate::New(isolate, handler);
1053 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1054 44 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1055 11 : Local<Script> script = v8_compile("obj()");
1056 671 : for (int i = 0; i < 30; i++) {
1057 330 : CHECK_EQ(102, v8_run_int32value(script));
1058 : }
1059 : }
1060 : // Use SetCallHandler to initialize a function template, should work like
1061 : // the previous one.
1062 : {
1063 11 : LocalContext env;
1064 11 : v8::Isolate* isolate = env->GetIsolate();
1065 22 : v8::HandleScope scope(isolate);
1066 :
1067 11 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1068 11 : fun_templ->SetCallHandler(handler_2);
1069 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1070 44 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1071 11 : Local<Script> script = v8_compile("obj()");
1072 671 : for (int i = 0; i < 30; i++) {
1073 330 : CHECK_EQ(102, v8_run_int32value(script));
1074 : }
1075 : }
1076 11 : }
1077 :
1078 :
1079 : template<typename Constructor, typename Accessor>
1080 11 : static void TestFunctionTemplateAccessor(Constructor constructor,
1081 : Accessor accessor) {
1082 11 : LocalContext env;
1083 22 : v8::HandleScope scope(env->GetIsolate());
1084 :
1085 : Local<v8::FunctionTemplate> fun_templ =
1086 11 : v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1087 11 : fun_templ->SetClassName(v8_str("funky"));
1088 22 : fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1089 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1090 44 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1091 : Local<Value> result =
1092 22 : v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1093 33 : CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1094 : CompileRun("var obj_instance = new obj();");
1095 : Local<Script> script;
1096 11 : script = v8_compile("obj_instance.x");
1097 671 : for (int i = 0; i < 30; i++) {
1098 330 : CHECK_EQ(1, v8_run_int32value(script));
1099 : }
1100 11 : script = v8_compile("obj_instance.m");
1101 671 : for (int i = 0; i < 30; i++) {
1102 330 : CHECK_EQ(239, v8_run_int32value(script));
1103 : }
1104 11 : }
1105 :
1106 :
1107 53294 : THREADED_PROFILED_TEST(FunctionTemplate) {
1108 11 : TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1109 11 : TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1110 11 : }
1111 :
1112 18 : static void FunctionCallbackForProxyTest(
1113 : const v8::FunctionCallbackInfo<Value>& info) {
1114 : info.GetReturnValue().Set(info.This());
1115 18 : }
1116 :
1117 26645 : THREADED_TEST(FunctionTemplateWithProxy) {
1118 6 : LocalContext env;
1119 6 : v8::Isolate* isolate = env->GetIsolate();
1120 12 : v8::HandleScope scope(isolate);
1121 :
1122 : v8::Local<v8::FunctionTemplate> function_template =
1123 6 : v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
1124 : v8::Local<v8::Function> function =
1125 6 : function_template->GetFunction(env.local()).ToLocalChecked();
1126 24 : CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
1127 : v8::Local<v8::Value> proxy =
1128 : CompileRun("var proxy = new Proxy({}, {}); proxy");
1129 6 : CHECK(proxy->IsProxy());
1130 :
1131 : v8::Local<v8::Value> result = CompileRun("f(proxy)");
1132 18 : CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());
1133 :
1134 : result = CompileRun("f.call(proxy)");
1135 12 : CHECK(result->Equals(env.local(), proxy).FromJust());
1136 :
1137 : result = CompileRun("Reflect.apply(f, proxy, [1])");
1138 12 : CHECK(result->Equals(env.local(), proxy).FromJust());
1139 6 : }
1140 :
1141 660 : static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1142 660 : ApiTestFuzzer::Fuzz();
1143 660 : CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1144 660 : info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1145 660 : }
1146 :
1147 :
1148 : template<typename Callback>
1149 11 : static void TestSimpleCallback(Callback callback) {
1150 11 : LocalContext env;
1151 11 : v8::Isolate* isolate = env->GetIsolate();
1152 22 : v8::HandleScope scope(isolate);
1153 :
1154 : v8::Local<v8::ObjectTemplate> object_template =
1155 11 : v8::ObjectTemplate::New(isolate);
1156 22 : object_template->Set(isolate, "callback",
1157 : v8::FunctionTemplate::New(isolate, callback));
1158 : v8::Local<v8::Object> object =
1159 11 : object_template->NewInstance(env.local()).ToLocalChecked();
1160 44 : CHECK((*env)
1161 : ->Global()
1162 : ->Set(env.local(), v8_str("callback_object"), object)
1163 : .FromJust());
1164 : v8::Local<v8::Script> script;
1165 11 : script = v8_compile("callback_object.callback(17)");
1166 671 : for (int i = 0; i < 30; i++) {
1167 330 : CHECK_EQ(51424, v8_run_int32value(script));
1168 : }
1169 11 : script = v8_compile("callback_object.callback(17, 24)");
1170 671 : for (int i = 0; i < 30; i++) {
1171 330 : CHECK_EQ(51425, v8_run_int32value(script));
1172 : }
1173 11 : }
1174 :
1175 :
1176 53294 : THREADED_PROFILED_TEST(SimpleCallback) {
1177 11 : TestSimpleCallback(SimpleCallback);
1178 11 : }
1179 :
1180 :
1181 : template<typename T>
1182 : void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1183 :
1184 : // constant return values
1185 : static int32_t fast_return_value_int32 = 471;
1186 : static uint32_t fast_return_value_uint32 = 571;
1187 : static const double kFastReturnValueDouble = 2.7;
1188 : // variable return values
1189 : static bool fast_return_value_bool = false;
1190 : enum ReturnValueOddball {
1191 : kNullReturnValue,
1192 : kUndefinedReturnValue,
1193 : kEmptyStringReturnValue
1194 : };
1195 : static ReturnValueOddball fast_return_value_void;
1196 : static bool fast_return_value_object_is_empty = false;
1197 :
1198 : // Helper function to avoid compiler error: insufficient contextual information
1199 : // to determine type when applying FUNCTION_ADDR to a template function.
1200 : static i::Address address_of(v8::FunctionCallback callback) {
1201 396 : return FUNCTION_ADDR(callback);
1202 : }
1203 :
1204 : template<>
1205 165 : void FastReturnValueCallback<int32_t>(
1206 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1207 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1208 165 : info.GetReturnValue().Set(fast_return_value_int32);
1209 165 : }
1210 :
1211 : template<>
1212 165 : void FastReturnValueCallback<uint32_t>(
1213 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1214 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1215 165 : info.GetReturnValue().Set(fast_return_value_uint32);
1216 165 : }
1217 :
1218 : template<>
1219 11 : void FastReturnValueCallback<double>(
1220 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1221 11 : CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1222 : info.GetReturnValue().Set(kFastReturnValueDouble);
1223 11 : }
1224 :
1225 : template<>
1226 22 : void FastReturnValueCallback<bool>(
1227 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1228 22 : CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1229 22 : info.GetReturnValue().Set(fast_return_value_bool);
1230 22 : }
1231 :
1232 : template<>
1233 33 : void FastReturnValueCallback<void>(
1234 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1235 33 : CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1236 33 : switch (fast_return_value_void) {
1237 : case kNullReturnValue:
1238 : info.GetReturnValue().SetNull();
1239 11 : break;
1240 : case kUndefinedReturnValue:
1241 : info.GetReturnValue().SetUndefined();
1242 11 : break;
1243 : case kEmptyStringReturnValue:
1244 : info.GetReturnValue().SetEmptyString();
1245 11 : break;
1246 : }
1247 33 : }
1248 :
1249 : template<>
1250 22 : void FastReturnValueCallback<Object>(
1251 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1252 : v8::Local<v8::Object> object;
1253 22 : if (!fast_return_value_object_is_empty) {
1254 11 : object = Object::New(info.GetIsolate());
1255 : }
1256 : info.GetReturnValue().Set(object);
1257 22 : }
1258 :
1259 : template <typename T>
1260 418 : Local<Value> TestFastReturnValues() {
1261 418 : LocalContext env;
1262 418 : v8::Isolate* isolate = env->GetIsolate();
1263 418 : v8::EscapableHandleScope scope(isolate);
1264 : v8::Local<v8::ObjectTemplate> object_template =
1265 418 : v8::ObjectTemplate::New(isolate);
1266 : v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1267 836 : object_template->Set(isolate, "callback",
1268 : v8::FunctionTemplate::New(isolate, callback));
1269 : v8::Local<v8::Object> object =
1270 418 : object_template->NewInstance(env.local()).ToLocalChecked();
1271 1672 : CHECK((*env)
1272 : ->Global()
1273 : ->Set(env.local(), v8_str("callback_object"), object)
1274 : .FromJust());
1275 418 : return scope.Escape(CompileRun("callback_object.callback()"));
1276 : }
1277 :
1278 :
1279 53294 : THREADED_PROFILED_TEST(FastReturnValues) {
1280 11 : LocalContext env;
1281 11 : v8::Isolate* isolate = env->GetIsolate();
1282 22 : v8::HandleScope scope(isolate);
1283 : v8::Local<v8::Value> value;
1284 : // check int32_t and uint32_t
1285 : int32_t int_values[] = {
1286 : 0, 234, -723,
1287 : i::Smi::kMinValue, i::Smi::kMaxValue
1288 11 : };
1289 121 : for (size_t i = 0; i < arraysize(int_values); i++) {
1290 385 : for (int modifier = -1; modifier <= 1; modifier++) {
1291 165 : int int_value = v8::base::AddWithWraparound(int_values[i], modifier);
1292 : // check int32_t
1293 165 : fast_return_value_int32 = int_value;
1294 165 : value = TestFastReturnValues<int32_t>();
1295 165 : CHECK(value->IsInt32());
1296 330 : CHECK_EQ(fast_return_value_int32,
1297 : value->Int32Value(env.local()).FromJust());
1298 : // check uint32_t
1299 165 : fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1300 165 : value = TestFastReturnValues<uint32_t>();
1301 165 : CHECK(value->IsUint32());
1302 330 : CHECK_EQ(fast_return_value_uint32,
1303 : value->Uint32Value(env.local()).FromJust());
1304 : }
1305 : }
1306 : // check double
1307 11 : value = TestFastReturnValues<double>();
1308 11 : CHECK(value->IsNumber());
1309 22 : CHECK_EQ(kFastReturnValueDouble,
1310 : value->ToNumber(env.local()).ToLocalChecked()->Value());
1311 : // check bool values
1312 55 : for (int i = 0; i < 2; i++) {
1313 22 : fast_return_value_bool = i == 0;
1314 22 : value = TestFastReturnValues<bool>();
1315 22 : CHECK(value->IsBoolean());
1316 22 : CHECK_EQ(fast_return_value_bool, value->BooleanValue(isolate));
1317 : }
1318 : // check oddballs
1319 : ReturnValueOddball oddballs[] = {
1320 : kNullReturnValue,
1321 : kUndefinedReturnValue,
1322 : kEmptyStringReturnValue
1323 11 : };
1324 77 : for (size_t i = 0; i < arraysize(oddballs); i++) {
1325 33 : fast_return_value_void = oddballs[i];
1326 33 : value = TestFastReturnValues<void>();
1327 33 : switch (fast_return_value_void) {
1328 : case kNullReturnValue:
1329 11 : CHECK(value->IsNull());
1330 : break;
1331 : case kUndefinedReturnValue:
1332 11 : CHECK(value->IsUndefined());
1333 : break;
1334 : case kEmptyStringReturnValue:
1335 11 : CHECK(value->IsString());
1336 11 : CHECK_EQ(0, v8::String::Cast(*value)->Length());
1337 : break;
1338 : }
1339 : }
1340 : // check handles
1341 11 : fast_return_value_object_is_empty = false;
1342 11 : value = TestFastReturnValues<Object>();
1343 11 : CHECK(value->IsObject());
1344 11 : fast_return_value_object_is_empty = true;
1345 11 : value = TestFastReturnValues<Object>();
1346 11 : CHECK(value->IsUndefined());
1347 11 : }
1348 :
1349 :
1350 26645 : THREADED_TEST(FunctionTemplateSetLength) {
1351 6 : LocalContext env;
1352 6 : v8::Isolate* isolate = env->GetIsolate();
1353 12 : v8::HandleScope scope(isolate);
1354 : {
1355 : Local<v8::FunctionTemplate> fun_templ =
1356 : v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1357 6 : Local<v8::Signature>(), 23);
1358 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1359 24 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1360 6 : Local<Script> script = v8_compile("obj.length");
1361 6 : CHECK_EQ(23, v8_run_int32value(script));
1362 : }
1363 : {
1364 : Local<v8::FunctionTemplate> fun_templ =
1365 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1366 6 : fun_templ->SetLength(22);
1367 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1368 24 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1369 6 : Local<Script> script = v8_compile("obj.length");
1370 6 : CHECK_EQ(22, v8_run_int32value(script));
1371 : }
1372 : {
1373 : // Without setting length it defaults to 0.
1374 : Local<v8::FunctionTemplate> fun_templ =
1375 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1376 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1377 24 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1378 6 : Local<Script> script = v8_compile("obj.length");
1379 6 : CHECK_EQ(0, v8_run_int32value(script));
1380 : }
1381 6 : }
1382 :
1383 :
1384 : static void* expected_ptr;
1385 8424 : static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1386 8424 : void* ptr = v8::External::Cast(*args.Data())->Value();
1387 8424 : CHECK_EQ(expected_ptr, ptr);
1388 : args.GetReturnValue().Set(true);
1389 8424 : }
1390 :
1391 :
1392 648 : static void TestExternalPointerWrapping() {
1393 648 : LocalContext env;
1394 648 : v8::Isolate* isolate = env->GetIsolate();
1395 1296 : v8::HandleScope scope(isolate);
1396 :
1397 648 : v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1398 :
1399 648 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
1400 3240 : CHECK(obj->Set(env.local(), v8_str("func"),
1401 : v8::FunctionTemplate::New(isolate, callback, data)
1402 : ->GetFunction(env.local())
1403 : .ToLocalChecked())
1404 : .FromJust());
1405 2592 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1406 :
1407 648 : CHECK(CompileRun("function foo() {\n"
1408 : " for (var i = 0; i < 13; i++) obj.func();\n"
1409 : "}\n"
1410 : "foo(), true")
1411 : ->BooleanValue(isolate));
1412 648 : }
1413 :
1414 :
1415 26645 : THREADED_TEST(ExternalWrap) {
1416 : // Check heap allocated object.
1417 6 : int* ptr = new int;
1418 6 : expected_ptr = ptr;
1419 6 : TestExternalPointerWrapping();
1420 6 : delete ptr;
1421 :
1422 : // Check stack allocated object.
1423 : int foo;
1424 6 : expected_ptr = &foo;
1425 6 : TestExternalPointerWrapping();
1426 :
1427 : // Check not aligned addresses.
1428 : const int n = 100;
1429 6 : char* s = new char[n];
1430 1206 : for (int i = 0; i < n; i++) {
1431 600 : expected_ptr = s + i;
1432 600 : TestExternalPointerWrapping();
1433 : }
1434 :
1435 6 : delete[] s;
1436 :
1437 : // Check several invalid addresses.
1438 6 : expected_ptr = reinterpret_cast<void*>(1);
1439 6 : TestExternalPointerWrapping();
1440 :
1441 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF);
1442 6 : TestExternalPointerWrapping();
1443 :
1444 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF + 1);
1445 6 : TestExternalPointerWrapping();
1446 :
1447 : #if defined(V8_HOST_ARCH_X64)
1448 : // Check a value with a leading 1 bit in x64 Smi encoding.
1449 6 : expected_ptr = reinterpret_cast<void*>(0x400000000);
1450 6 : TestExternalPointerWrapping();
1451 :
1452 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF);
1453 6 : TestExternalPointerWrapping();
1454 :
1455 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF + 1);
1456 6 : TestExternalPointerWrapping();
1457 : #endif
1458 6 : }
1459 :
1460 :
1461 26645 : THREADED_TEST(FindInstanceInPrototypeChain) {
1462 6 : LocalContext env;
1463 6 : v8::Isolate* isolate = env->GetIsolate();
1464 12 : v8::HandleScope scope(isolate);
1465 :
1466 6 : Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1467 6 : Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1468 6 : Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1469 6 : derived->Inherit(base);
1470 :
1471 : Local<v8::Function> base_function =
1472 6 : base->GetFunction(env.local()).ToLocalChecked();
1473 : Local<v8::Function> derived_function =
1474 6 : derived->GetFunction(env.local()).ToLocalChecked();
1475 : Local<v8::Function> other_function =
1476 6 : other->GetFunction(env.local()).ToLocalChecked();
1477 :
1478 : Local<v8::Object> base_instance =
1479 : base_function->NewInstance(env.local()).ToLocalChecked();
1480 : Local<v8::Object> derived_instance =
1481 : derived_function->NewInstance(env.local()).ToLocalChecked();
1482 : Local<v8::Object> derived_instance2 =
1483 : derived_function->NewInstance(env.local()).ToLocalChecked();
1484 : Local<v8::Object> other_instance =
1485 : other_function->NewInstance(env.local()).ToLocalChecked();
1486 18 : CHECK(
1487 : derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1488 : .FromJust());
1489 18 : CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1490 : .FromJust());
1491 :
1492 : // base_instance is only an instance of base.
1493 18 : CHECK(base_instance->Equals(env.local(),
1494 : base_instance->FindInstanceInPrototypeChain(base))
1495 : .FromJust());
1496 12 : CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1497 12 : CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1498 :
1499 : // derived_instance is an instance of base and derived.
1500 18 : CHECK(derived_instance->Equals(env.local(),
1501 : derived_instance->FindInstanceInPrototypeChain(
1502 : base))
1503 : .FromJust());
1504 18 : CHECK(derived_instance->Equals(env.local(),
1505 : derived_instance->FindInstanceInPrototypeChain(
1506 : derived))
1507 : .FromJust());
1508 12 : CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1509 :
1510 : // other_instance is an instance of other and its immediate
1511 : // prototype derived_instance2 is an instance of base and derived.
1512 : // Note, derived_instance is an instance of base and derived too,
1513 : // but it comes after derived_instance2 in the prototype chain of
1514 : // other_instance.
1515 18 : CHECK(derived_instance2->Equals(
1516 : env.local(),
1517 : other_instance->FindInstanceInPrototypeChain(base))
1518 : .FromJust());
1519 18 : CHECK(derived_instance2->Equals(env.local(),
1520 : other_instance->FindInstanceInPrototypeChain(
1521 : derived))
1522 : .FromJust());
1523 18 : CHECK(other_instance->Equals(
1524 : env.local(),
1525 : other_instance->FindInstanceInPrototypeChain(other))
1526 : .FromJust());
1527 6 : }
1528 :
1529 :
1530 26645 : THREADED_TEST(TinyInteger) {
1531 6 : LocalContext env;
1532 6 : v8::Isolate* isolate = env->GetIsolate();
1533 12 : v8::HandleScope scope(isolate);
1534 :
1535 : int32_t value = 239;
1536 6 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1537 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1538 6 : }
1539 :
1540 :
1541 26645 : THREADED_TEST(BigSmiInteger) {
1542 6 : LocalContext env;
1543 12 : v8::HandleScope scope(env->GetIsolate());
1544 6 : v8::Isolate* isolate = CcTest::isolate();
1545 :
1546 : int32_t value = i::Smi::kMaxValue;
1547 : // We cannot add one to a Smi::kMaxValue without wrapping.
1548 : if (i::SmiValuesAre31Bits()) {
1549 : CHECK(i::Smi::IsValid(value));
1550 : CHECK(!i::Smi::IsValid(value + 1));
1551 :
1552 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1553 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1554 : }
1555 6 : }
1556 :
1557 :
1558 26645 : THREADED_TEST(BigInteger) {
1559 6 : LocalContext env;
1560 12 : v8::HandleScope scope(env->GetIsolate());
1561 6 : v8::Isolate* isolate = CcTest::isolate();
1562 :
1563 : // We cannot add one to a Smi::kMaxValue without wrapping.
1564 : if (i::SmiValuesAre31Bits()) {
1565 : // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1566 : // The code will not be run in that case, due to the "if" guard.
1567 : int32_t value =
1568 : static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1569 : CHECK_GT(value, i::Smi::kMaxValue);
1570 : CHECK(!i::Smi::IsValid(value));
1571 :
1572 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1573 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1574 : }
1575 6 : }
1576 :
1577 :
1578 26645 : THREADED_TEST(TinyUnsignedInteger) {
1579 6 : LocalContext env;
1580 12 : v8::HandleScope scope(env->GetIsolate());
1581 6 : v8::Isolate* isolate = CcTest::isolate();
1582 :
1583 : uint32_t value = 239;
1584 :
1585 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1586 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1587 6 : }
1588 :
1589 :
1590 26645 : THREADED_TEST(BigUnsignedSmiInteger) {
1591 6 : LocalContext env;
1592 12 : v8::HandleScope scope(env->GetIsolate());
1593 6 : v8::Isolate* isolate = CcTest::isolate();
1594 :
1595 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1596 : CHECK(i::Smi::IsValid(value));
1597 : CHECK(!i::Smi::IsValid(value + 1));
1598 :
1599 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1600 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1601 6 : }
1602 :
1603 :
1604 26645 : THREADED_TEST(BigUnsignedInteger) {
1605 6 : LocalContext env;
1606 12 : v8::HandleScope scope(env->GetIsolate());
1607 6 : v8::Isolate* isolate = CcTest::isolate();
1608 :
1609 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1610 : CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1611 : CHECK(!i::Smi::IsValid(value));
1612 :
1613 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1614 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1615 6 : }
1616 :
1617 :
1618 26645 : THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1619 6 : LocalContext env;
1620 12 : v8::HandleScope scope(env->GetIsolate());
1621 6 : v8::Isolate* isolate = CcTest::isolate();
1622 :
1623 : uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1624 : uint32_t value = INT32_MAX_AS_UINT + 1;
1625 : CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1626 :
1627 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1628 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1629 6 : }
1630 :
1631 :
1632 26645 : THREADED_TEST(IsNativeError) {
1633 6 : LocalContext env;
1634 12 : v8::HandleScope scope(env->GetIsolate());
1635 : v8::Local<Value> syntax_error = CompileRun(
1636 : "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1637 6 : CHECK(syntax_error->IsNativeError());
1638 : v8::Local<Value> not_error = CompileRun("{a:42}");
1639 6 : CHECK(!not_error->IsNativeError());
1640 : v8::Local<Value> not_object = CompileRun("42");
1641 6 : CHECK(!not_object->IsNativeError());
1642 6 : }
1643 :
1644 :
1645 26645 : THREADED_TEST(IsGeneratorFunctionOrObject) {
1646 6 : LocalContext env;
1647 12 : v8::HandleScope scope(env->GetIsolate());
1648 :
1649 : CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1650 : v8::Local<Value> gen = CompileRun("gen");
1651 : v8::Local<Value> genObj = CompileRun("gen()");
1652 : v8::Local<Value> object = CompileRun("{a:42}");
1653 : v8::Local<Value> func = CompileRun("func");
1654 :
1655 6 : CHECK(gen->IsGeneratorFunction());
1656 6 : CHECK(gen->IsFunction());
1657 6 : CHECK(!gen->IsGeneratorObject());
1658 :
1659 6 : CHECK(!genObj->IsGeneratorFunction());
1660 6 : CHECK(!genObj->IsFunction());
1661 6 : CHECK(genObj->IsGeneratorObject());
1662 :
1663 6 : CHECK(!object->IsGeneratorFunction());
1664 6 : CHECK(!object->IsFunction());
1665 6 : CHECK(!object->IsGeneratorObject());
1666 :
1667 6 : CHECK(!func->IsGeneratorFunction());
1668 6 : CHECK(func->IsFunction());
1669 6 : CHECK(!func->IsGeneratorObject());
1670 6 : }
1671 :
1672 26645 : THREADED_TEST(IsAsyncFunction) {
1673 6 : LocalContext env;
1674 6 : v8::Isolate* isolate = env->GetIsolate();
1675 12 : v8::HandleScope scope(isolate);
1676 :
1677 : CompileRun("async function foo() {}");
1678 : v8::Local<Value> foo = CompileRun("foo");
1679 :
1680 6 : CHECK(foo->IsAsyncFunction());
1681 6 : CHECK(foo->IsFunction());
1682 6 : CHECK(!foo->IsGeneratorFunction());
1683 6 : CHECK(!foo->IsGeneratorObject());
1684 :
1685 : CompileRun("function bar() {}");
1686 : v8::Local<Value> bar = CompileRun("bar");
1687 :
1688 6 : CHECK(!bar->IsAsyncFunction());
1689 6 : CHECK(bar->IsFunction());
1690 6 : }
1691 :
1692 26645 : THREADED_TEST(ArgumentsObject) {
1693 6 : LocalContext env;
1694 12 : v8::HandleScope scope(env->GetIsolate());
1695 : v8::Local<Value> arguments_object =
1696 : CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1697 6 : CHECK(arguments_object->IsArgumentsObject());
1698 : v8::Local<Value> array = CompileRun("[1,2,3]");
1699 6 : CHECK(!array->IsArgumentsObject());
1700 : v8::Local<Value> object = CompileRun("{a:42}");
1701 6 : CHECK(!object->IsArgumentsObject());
1702 6 : }
1703 :
1704 :
1705 26645 : THREADED_TEST(IsMapOrSet) {
1706 6 : LocalContext env;
1707 12 : v8::HandleScope scope(env->GetIsolate());
1708 : v8::Local<Value> map = CompileRun("new Map()");
1709 : v8::Local<Value> set = CompileRun("new Set()");
1710 : v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1711 : v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1712 6 : CHECK(map->IsMap());
1713 6 : CHECK(set->IsSet());
1714 6 : CHECK(weak_map->IsWeakMap());
1715 6 : CHECK(weak_set->IsWeakSet());
1716 :
1717 6 : CHECK(!map->IsSet());
1718 6 : CHECK(!map->IsWeakMap());
1719 6 : CHECK(!map->IsWeakSet());
1720 :
1721 6 : CHECK(!set->IsMap());
1722 6 : CHECK(!set->IsWeakMap());
1723 6 : CHECK(!set->IsWeakSet());
1724 :
1725 6 : CHECK(!weak_map->IsMap());
1726 6 : CHECK(!weak_map->IsSet());
1727 6 : CHECK(!weak_map->IsWeakSet());
1728 :
1729 6 : CHECK(!weak_set->IsMap());
1730 6 : CHECK(!weak_set->IsSet());
1731 6 : CHECK(!weak_set->IsWeakMap());
1732 :
1733 : v8::Local<Value> object = CompileRun("{a:42}");
1734 6 : CHECK(!object->IsMap());
1735 6 : CHECK(!object->IsSet());
1736 6 : CHECK(!object->IsWeakMap());
1737 6 : CHECK(!object->IsWeakSet());
1738 6 : }
1739 :
1740 :
1741 26645 : THREADED_TEST(StringObject) {
1742 6 : LocalContext env;
1743 12 : v8::HandleScope scope(env->GetIsolate());
1744 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1745 6 : CHECK(boxed_string->IsStringObject());
1746 : v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1747 6 : CHECK(!unboxed_string->IsStringObject());
1748 : v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1749 6 : CHECK(!boxed_not_string->IsStringObject());
1750 : v8::Local<Value> not_object = CompileRun("0");
1751 6 : CHECK(!not_object->IsStringObject());
1752 : v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1753 6 : CHECK(!as_boxed.IsEmpty());
1754 6 : Local<v8::String> the_string = as_boxed->ValueOf();
1755 6 : CHECK(!the_string.IsEmpty());
1756 6 : ExpectObject("\"test\"", the_string);
1757 : v8::Local<v8::Value> new_boxed_string =
1758 6 : v8::StringObject::New(CcTest::isolate(), the_string);
1759 6 : CHECK(new_boxed_string->IsStringObject());
1760 : as_boxed = new_boxed_string.As<v8::StringObject>();
1761 6 : the_string = as_boxed->ValueOf();
1762 6 : CHECK(!the_string.IsEmpty());
1763 6 : ExpectObject("\"test\"", the_string);
1764 6 : }
1765 :
1766 :
1767 26644 : TEST(StringObjectDelete) {
1768 5 : LocalContext context;
1769 10 : v8::HandleScope scope(context->GetIsolate());
1770 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1771 5 : CHECK(boxed_string->IsStringObject());
1772 : v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1773 10 : CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1774 15 : CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1775 5 : }
1776 :
1777 :
1778 26645 : THREADED_TEST(NumberObject) {
1779 6 : LocalContext env;
1780 12 : v8::HandleScope scope(env->GetIsolate());
1781 : v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1782 6 : CHECK(boxed_number->IsNumberObject());
1783 : v8::Local<Value> unboxed_number = CompileRun("42");
1784 6 : CHECK(!unboxed_number->IsNumberObject());
1785 : v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1786 6 : CHECK(!boxed_not_number->IsNumberObject());
1787 : v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1788 6 : CHECK(!as_boxed.IsEmpty());
1789 6 : double the_number = as_boxed->ValueOf();
1790 6 : CHECK_EQ(42.0, the_number);
1791 : v8::Local<v8::Value> new_boxed_number =
1792 6 : v8::NumberObject::New(env->GetIsolate(), 43);
1793 6 : CHECK(new_boxed_number->IsNumberObject());
1794 : as_boxed = new_boxed_number.As<v8::NumberObject>();
1795 6 : the_number = as_boxed->ValueOf();
1796 6 : CHECK_EQ(43.0, the_number);
1797 6 : }
1798 :
1799 26645 : THREADED_TEST(BigIntObject) {
1800 6 : LocalContext env;
1801 6 : v8::Isolate* isolate = env->GetIsolate();
1802 12 : v8::HandleScope scope(isolate);
1803 6 : v8::Local<v8::Context> context(env.local());
1804 : v8::Local<Value> boxed_bigint = CompileRun("new Object(42n)");
1805 6 : CHECK(!boxed_bigint->IsBigInt());
1806 6 : CHECK(boxed_bigint->IsBigIntObject());
1807 : v8::Local<Value> unboxed_bigint = CompileRun("42n");
1808 6 : CHECK(unboxed_bigint->IsBigInt());
1809 6 : CHECK(!unboxed_bigint->IsBigIntObject());
1810 : v8::Local<v8::BigIntObject> as_boxed = boxed_bigint.As<v8::BigIntObject>();
1811 6 : CHECK(!as_boxed.IsEmpty());
1812 6 : v8::Local<v8::BigInt> unpacked = as_boxed->ValueOf();
1813 6 : CHECK(!unpacked.IsEmpty());
1814 6 : v8::Local<v8::Value> new_boxed_bigint = v8::BigIntObject::New(isolate, 43);
1815 6 : CHECK(new_boxed_bigint->IsBigIntObject());
1816 6 : v8::Local<v8::Value> new_unboxed_bigint = v8::BigInt::New(isolate, 44);
1817 6 : CHECK(new_unboxed_bigint->IsBigInt());
1818 :
1819 : // Test functionality inherited from v8::Value.
1820 6 : CHECK(unboxed_bigint->BooleanValue(isolate));
1821 : v8::Local<v8::String> string =
1822 6 : unboxed_bigint->ToString(context).ToLocalChecked();
1823 6 : CHECK_EQ(0, strcmp("42", *v8::String::Utf8Value(isolate, string)));
1824 :
1825 : // IntegerValue throws.
1826 12 : CHECK(unboxed_bigint->IntegerValue(context).IsNothing());
1827 6 : }
1828 :
1829 26645 : THREADED_TEST(BooleanObject) {
1830 6 : LocalContext env;
1831 12 : v8::HandleScope scope(env->GetIsolate());
1832 : v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1833 6 : CHECK(boxed_boolean->IsBooleanObject());
1834 : v8::Local<Value> unboxed_boolean = CompileRun("true");
1835 6 : CHECK(!unboxed_boolean->IsBooleanObject());
1836 : v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1837 6 : CHECK(!boxed_not_boolean->IsBooleanObject());
1838 : v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1839 6 : CHECK(!as_boxed.IsEmpty());
1840 6 : bool the_boolean = as_boxed->ValueOf();
1841 6 : CHECK(the_boolean);
1842 : v8::Local<v8::Value> boxed_true =
1843 6 : v8::BooleanObject::New(env->GetIsolate(), true);
1844 : v8::Local<v8::Value> boxed_false =
1845 6 : v8::BooleanObject::New(env->GetIsolate(), false);
1846 6 : CHECK(boxed_true->IsBooleanObject());
1847 6 : CHECK(boxed_false->IsBooleanObject());
1848 : as_boxed = boxed_true.As<v8::BooleanObject>();
1849 6 : CHECK(as_boxed->ValueOf());
1850 : as_boxed = boxed_false.As<v8::BooleanObject>();
1851 6 : CHECK(!as_boxed->ValueOf());
1852 6 : }
1853 :
1854 :
1855 26645 : THREADED_TEST(PrimitiveAndWrappedBooleans) {
1856 6 : LocalContext env;
1857 6 : v8::Isolate* isolate = env->GetIsolate();
1858 12 : v8::HandleScope scope(isolate);
1859 :
1860 : Local<Value> primitive_false = Boolean::New(isolate, false);
1861 6 : CHECK(primitive_false->IsBoolean());
1862 6 : CHECK(!primitive_false->IsBooleanObject());
1863 6 : CHECK(!primitive_false->BooleanValue(isolate));
1864 6 : CHECK(!primitive_false->IsTrue());
1865 6 : CHECK(primitive_false->IsFalse());
1866 :
1867 6 : Local<Value> false_value = BooleanObject::New(isolate, false);
1868 6 : CHECK(!false_value->IsBoolean());
1869 6 : CHECK(false_value->IsBooleanObject());
1870 6 : CHECK(false_value->BooleanValue(isolate));
1871 6 : CHECK(!false_value->IsTrue());
1872 6 : CHECK(!false_value->IsFalse());
1873 :
1874 : Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1875 6 : CHECK(!false_boolean_object->IsBoolean());
1876 6 : CHECK(false_boolean_object->IsBooleanObject());
1877 6 : CHECK(false_boolean_object->BooleanValue(isolate));
1878 6 : CHECK(!false_boolean_object->ValueOf());
1879 6 : CHECK(!false_boolean_object->IsTrue());
1880 6 : CHECK(!false_boolean_object->IsFalse());
1881 :
1882 : Local<Value> primitive_true = Boolean::New(isolate, true);
1883 6 : CHECK(primitive_true->IsBoolean());
1884 6 : CHECK(!primitive_true->IsBooleanObject());
1885 6 : CHECK(primitive_true->BooleanValue(isolate));
1886 6 : CHECK(primitive_true->IsTrue());
1887 6 : CHECK(!primitive_true->IsFalse());
1888 :
1889 6 : Local<Value> true_value = BooleanObject::New(isolate, true);
1890 6 : CHECK(!true_value->IsBoolean());
1891 6 : CHECK(true_value->IsBooleanObject());
1892 6 : CHECK(true_value->BooleanValue(isolate));
1893 6 : CHECK(!true_value->IsTrue());
1894 6 : CHECK(!true_value->IsFalse());
1895 :
1896 : Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1897 6 : CHECK(!true_boolean_object->IsBoolean());
1898 6 : CHECK(true_boolean_object->IsBooleanObject());
1899 6 : CHECK(true_boolean_object->BooleanValue(isolate));
1900 6 : CHECK(true_boolean_object->ValueOf());
1901 6 : CHECK(!true_boolean_object->IsTrue());
1902 6 : CHECK(!true_boolean_object->IsFalse());
1903 6 : }
1904 :
1905 :
1906 26645 : THREADED_TEST(Number) {
1907 6 : LocalContext env;
1908 12 : v8::HandleScope scope(env->GetIsolate());
1909 : double PI = 3.1415926;
1910 6 : Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1911 12 : CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1912 6 : }
1913 :
1914 :
1915 26645 : THREADED_TEST(ToNumber) {
1916 6 : LocalContext env;
1917 6 : v8::Isolate* isolate = CcTest::isolate();
1918 12 : v8::HandleScope scope(isolate);
1919 6 : Local<String> str = v8_str("3.1415926");
1920 12 : CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1921 : v8::Local<v8::Boolean> t = v8::True(isolate);
1922 12 : CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1923 : v8::Local<v8::Boolean> f = v8::False(isolate);
1924 12 : CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1925 6 : }
1926 :
1927 :
1928 26645 : THREADED_TEST(Date) {
1929 6 : LocalContext env;
1930 12 : v8::HandleScope scope(env->GetIsolate());
1931 : double PI = 3.1415926;
1932 6 : Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1933 12 : CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1934 24 : CHECK(date.As<v8::Date>()
1935 : ->Set(env.local(), v8_str("property"),
1936 : v8::Integer::New(env->GetIsolate(), 42))
1937 : .FromJust());
1938 24 : CHECK_EQ(42, date.As<v8::Date>()
1939 : ->Get(env.local(), v8_str("property"))
1940 : .ToLocalChecked()
1941 : ->Int32Value(env.local())
1942 : .FromJust());
1943 6 : }
1944 :
1945 :
1946 26645 : THREADED_TEST(Boolean) {
1947 6 : LocalContext env;
1948 6 : v8::Isolate* isolate = env->GetIsolate();
1949 12 : v8::HandleScope scope(isolate);
1950 : v8::Local<v8::Boolean> t = v8::True(isolate);
1951 6 : CHECK(t->Value());
1952 : v8::Local<v8::Boolean> f = v8::False(isolate);
1953 6 : CHECK(!f->Value());
1954 : v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1955 6 : CHECK(!u->BooleanValue(isolate));
1956 : v8::Local<v8::Primitive> n = v8::Null(isolate);
1957 6 : CHECK(!n->BooleanValue(isolate));
1958 6 : v8::Local<String> str1 = v8_str("");
1959 6 : CHECK(!str1->BooleanValue(isolate));
1960 6 : v8::Local<String> str2 = v8_str("x");
1961 6 : CHECK(str2->BooleanValue(isolate));
1962 12 : CHECK(!v8::Number::New(isolate, 0)->BooleanValue(isolate));
1963 12 : CHECK(v8::Number::New(isolate, -1)->BooleanValue(isolate));
1964 12 : CHECK(v8::Number::New(isolate, 1)->BooleanValue(isolate));
1965 12 : CHECK(v8::Number::New(isolate, 42)->BooleanValue(isolate));
1966 12 : CHECK(!v8_compile("NaN")
1967 : ->Run(env.local())
1968 : .ToLocalChecked()
1969 : ->BooleanValue(isolate));
1970 6 : }
1971 :
1972 :
1973 6 : static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1974 6 : ApiTestFuzzer::Fuzz();
1975 6 : args.GetReturnValue().Set(v8_num(13.4));
1976 6 : }
1977 :
1978 :
1979 6 : static void GetM(Local<String> name,
1980 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1981 6 : ApiTestFuzzer::Fuzz();
1982 6 : info.GetReturnValue().Set(v8_num(876));
1983 6 : }
1984 :
1985 :
1986 26645 : THREADED_TEST(GlobalPrototype) {
1987 6 : v8::Isolate* isolate = CcTest::isolate();
1988 12 : v8::HandleScope scope(isolate);
1989 : v8::Local<v8::FunctionTemplate> func_templ =
1990 6 : v8::FunctionTemplate::New(isolate);
1991 12 : func_templ->PrototypeTemplate()->Set(
1992 : isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1993 6 : v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1994 6 : templ->Set(isolate, "x", v8_num(200));
1995 6 : templ->SetAccessor(v8_str("m"), GetM);
1996 6 : LocalContext env(nullptr, templ);
1997 : v8::Local<Script> script(v8_compile("dummy()"));
1998 6 : v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1999 12 : CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
2000 6 : CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
2001 6 : CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
2002 6 : }
2003 :
2004 :
2005 26645 : THREADED_TEST(ObjectTemplate) {
2006 6 : LocalContext env;
2007 6 : v8::Isolate* isolate = CcTest::isolate();
2008 12 : v8::HandleScope scope(isolate);
2009 : Local<v8::FunctionTemplate> acc =
2010 6 : v8::FunctionTemplate::New(isolate, Returns42);
2011 30 : CHECK(env->Global()
2012 : ->Set(env.local(), v8_str("acc"),
2013 : acc->GetFunction(env.local()).ToLocalChecked())
2014 : .FromJust());
2015 :
2016 6 : Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
2017 6 : v8::Local<v8::String> class_name = v8_str("the_class_name");
2018 6 : fun->SetClassName(class_name);
2019 6 : Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
2020 6 : templ1->Set(isolate, "x", v8_num(10));
2021 6 : templ1->Set(isolate, "y", v8_num(13));
2022 12 : templ1->Set(v8_str("foo"), acc);
2023 : Local<v8::Object> instance1 =
2024 6 : templ1->NewInstance(env.local()).ToLocalChecked();
2025 12 : CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
2026 24 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
2027 6 : CHECK(CompileRun("(p.x == 10)")->BooleanValue(isolate));
2028 6 : CHECK(CompileRun("(p.y == 13)")->BooleanValue(isolate));
2029 6 : CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(isolate));
2030 6 : CHECK(CompileRun("(p.foo == acc)")->BooleanValue(isolate));
2031 : // Ensure that foo become a data field.
2032 : CompileRun("p.foo = function() {}");
2033 6 : Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
2034 12 : fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
2035 6 : Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
2036 6 : templ2->Set(isolate, "a", v8_num(12));
2037 : templ2->Set(isolate, "b", templ1);
2038 12 : templ2->Set(v8_str("bar"), acc);
2039 12 : templ2->SetAccessorProperty(v8_str("acc"), acc);
2040 : Local<v8::Object> instance2 =
2041 6 : templ2->NewInstance(env.local()).ToLocalChecked();
2042 24 : CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
2043 6 : CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(isolate));
2044 6 : CHECK(CompileRun("(q.a == 12)")->BooleanValue(isolate));
2045 6 : CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(isolate));
2046 6 : CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(isolate));
2047 6 : CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(isolate));
2048 6 : CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(isolate));
2049 6 : CHECK(CompileRun("(q.b !== p)")->BooleanValue(isolate));
2050 6 : CHECK(CompileRun("(q.acc == 42)")->BooleanValue(isolate));
2051 6 : CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(isolate));
2052 6 : CHECK(CompileRun("(q.bar == acc)")->BooleanValue(isolate));
2053 :
2054 6 : instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
2055 24 : CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
2056 6 : CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(isolate));
2057 6 : CHECK(CompileRun("(q2.a == 12)")->BooleanValue(isolate));
2058 6 : CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(isolate));
2059 6 : CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(isolate));
2060 6 : CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(isolate));
2061 6 : CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(isolate));
2062 6 : CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(isolate));
2063 6 : CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(isolate));
2064 6 : CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(isolate));
2065 :
2066 6 : CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(isolate));
2067 6 : CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")->BooleanValue(isolate));
2068 6 : CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
2069 : "(desc1.get === acc)")
2070 : ->BooleanValue(isolate));
2071 6 : CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
2072 : "(desc2.get === acc)")
2073 : ->BooleanValue(isolate));
2074 6 : }
2075 :
2076 26645 : THREADED_TEST(IntegerValue) {
2077 6 : LocalContext env;
2078 6 : v8::Isolate* isolate = CcTest::isolate();
2079 12 : v8::HandleScope scope(isolate);
2080 :
2081 12 : CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
2082 6 : }
2083 :
2084 126 : static void GetNirk(Local<String> name,
2085 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2086 126 : ApiTestFuzzer::Fuzz();
2087 126 : info.GetReturnValue().Set(v8_num(900));
2088 126 : }
2089 :
2090 126 : static void GetRino(Local<String> name,
2091 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2092 126 : ApiTestFuzzer::Fuzz();
2093 126 : info.GetReturnValue().Set(v8_num(560));
2094 126 : }
2095 :
2096 : enum ObjectInstantiationMode {
2097 : // Create object using ObjectTemplate::NewInstance.
2098 : ObjectTemplate_NewInstance,
2099 : // Create object using FunctionTemplate::NewInstance on constructor.
2100 : Constructor_GetFunction_NewInstance,
2101 : // Create object using new operator on constructor.
2102 : Constructor_GetFunction_New
2103 : };
2104 :
2105 : // Test object instance creation using a function template with an instance
2106 : // template inherited from another function template with accessors and data
2107 : // properties in prototype template.
2108 18 : static void TestObjectTemplateInheritedWithPrototype(
2109 : ObjectInstantiationMode mode) {
2110 18 : LocalContext env;
2111 18 : v8::Isolate* isolate = CcTest::isolate();
2112 36 : v8::HandleScope scope(isolate);
2113 :
2114 18 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2115 18 : fun_A->SetClassName(v8_str("A"));
2116 18 : v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
2117 18 : prototype_templ->Set(isolate, "a", v8_num(113));
2118 18 : prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2119 18 : prototype_templ->Set(isolate, "b", v8_num(153));
2120 :
2121 18 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2122 18 : v8::Local<v8::String> class_name = v8_str("B");
2123 18 : fun_B->SetClassName(class_name);
2124 18 : fun_B->Inherit(fun_A);
2125 18 : prototype_templ = fun_B->PrototypeTemplate();
2126 18 : prototype_templ->Set(isolate, "c", v8_num(713));
2127 18 : prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
2128 18 : prototype_templ->Set(isolate, "d", v8_num(753));
2129 :
2130 18 : Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
2131 18 : templ->Set(isolate, "x", v8_num(10));
2132 18 : templ->Set(isolate, "y", v8_num(13));
2133 :
2134 : // Perform several iterations to trigger creation from cached boilerplate.
2135 126 : for (int i = 0; i < 3; i++) {
2136 : Local<v8::Object> instance;
2137 54 : switch (mode) {
2138 : case ObjectTemplate_NewInstance:
2139 18 : instance = templ->NewInstance(env.local()).ToLocalChecked();
2140 : break;
2141 :
2142 : case Constructor_GetFunction_NewInstance: {
2143 : Local<v8::Function> function_B =
2144 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2145 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2146 : break;
2147 : }
2148 : case Constructor_GetFunction_New: {
2149 : Local<v8::Function> function_B =
2150 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2151 18 : if (i == 0) {
2152 18 : CHECK(env->Global()
2153 : ->Set(env.local(), class_name, function_B)
2154 : .FromJust());
2155 : }
2156 : instance =
2157 18 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2158 : break;
2159 : }
2160 : default:
2161 0 : UNREACHABLE();
2162 : }
2163 :
2164 108 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2165 216 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2166 :
2167 108 : CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2168 108 : CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2169 :
2170 108 : CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2171 108 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2172 108 : CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2173 108 : CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2174 108 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2175 108 : CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2176 : }
2177 18 : }
2178 :
2179 26645 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2180 6 : TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2181 6 : }
2182 :
2183 26645 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2184 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2185 6 : }
2186 :
2187 26645 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2188 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2189 6 : }
2190 :
2191 : // Test object instance creation using a function template without an instance
2192 : // template inherited from another function template.
2193 12 : static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2194 : ObjectInstantiationMode mode) {
2195 12 : LocalContext env;
2196 12 : v8::Isolate* isolate = CcTest::isolate();
2197 24 : v8::HandleScope scope(isolate);
2198 :
2199 12 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2200 12 : fun_A->SetClassName(v8_str("A"));
2201 :
2202 12 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2203 12 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2204 12 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2205 :
2206 12 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2207 12 : v8::Local<v8::String> class_name = v8_str("B");
2208 12 : fun_B->SetClassName(class_name);
2209 12 : fun_B->Inherit(fun_A);
2210 :
2211 : // Perform several iterations to trigger creation from cached boilerplate.
2212 84 : for (int i = 0; i < 3; i++) {
2213 : Local<v8::Object> instance;
2214 36 : switch (mode) {
2215 : case Constructor_GetFunction_NewInstance: {
2216 : Local<v8::Function> function_B =
2217 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2218 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2219 : break;
2220 : }
2221 : case Constructor_GetFunction_New: {
2222 : Local<v8::Function> function_B =
2223 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2224 18 : if (i == 0) {
2225 18 : CHECK(env->Global()
2226 : ->Set(env.local(), class_name, function_B)
2227 : .FromJust());
2228 : }
2229 : instance =
2230 18 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2231 : break;
2232 : }
2233 : default:
2234 0 : UNREACHABLE();
2235 : }
2236 :
2237 72 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2238 144 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2239 :
2240 72 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2241 72 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2242 : }
2243 12 : }
2244 :
2245 26645 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2246 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2247 6 : Constructor_GetFunction_NewInstance);
2248 6 : }
2249 :
2250 26645 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2251 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2252 6 : Constructor_GetFunction_New);
2253 6 : }
2254 :
2255 26645 : THREADED_TEST(TestObjectTemplateClassInheritance) {
2256 6 : LocalContext env;
2257 6 : v8::Isolate* isolate = CcTest::isolate();
2258 12 : v8::HandleScope scope(isolate);
2259 :
2260 6 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2261 6 : fun_A->SetClassName(v8_str("A"));
2262 :
2263 6 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2264 6 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2265 6 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2266 :
2267 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2268 6 : v8::Local<v8::String> class_name = v8_str("B");
2269 6 : fun_B->SetClassName(class_name);
2270 6 : fun_B->Inherit(fun_A);
2271 :
2272 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2273 : v8::Local<v8::Object> b_proto;
2274 : v8::Local<v8::Object> c_proto;
2275 : // Perform several iterations to make sure the cache doesn't break
2276 : // subclassing.
2277 42 : for (int i = 0; i < 3; i++) {
2278 : Local<v8::Function> function_B =
2279 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2280 18 : if (i == 0) {
2281 18 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2282 : CompileRun("class C extends B {}");
2283 : b_proto =
2284 6 : CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2285 : c_proto =
2286 6 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2287 18 : CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2288 : }
2289 : Local<v8::Object> instance =
2290 18 : CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2291 54 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2292 :
2293 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2294 72 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2295 :
2296 36 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2297 36 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2298 : }
2299 6 : }
2300 :
2301 276 : static void NamedPropertyGetterWhichReturns42(
2302 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2303 276 : info.GetReturnValue().Set(v8_num(42));
2304 276 : }
2305 :
2306 26645 : THREADED_TEST(TestObjectTemplateReflectConstruct) {
2307 6 : LocalContext env;
2308 6 : v8::Isolate* isolate = CcTest::isolate();
2309 12 : v8::HandleScope scope(isolate);
2310 :
2311 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2312 12 : fun_B->InstanceTemplate()->SetHandler(
2313 6 : v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2314 6 : v8::Local<v8::String> class_name = v8_str("B");
2315 6 : fun_B->SetClassName(class_name);
2316 :
2317 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2318 : v8::Local<v8::Object> b_proto;
2319 : v8::Local<v8::Object> c_proto;
2320 : // Perform several iterations to make sure the cache doesn't break
2321 : // subclassing.
2322 42 : for (int i = 0; i < 3; i++) {
2323 : Local<v8::Function> function_B =
2324 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2325 18 : if (i == 0) {
2326 18 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2327 : CompileRun("function C() {}");
2328 : c_proto =
2329 6 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2330 : }
2331 : Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2332 18 : ->ToObject(env.local())
2333 : .ToLocalChecked();
2334 54 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2335 :
2336 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2337 72 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2338 :
2339 36 : CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2340 36 : CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2341 : }
2342 6 : }
2343 :
2344 12 : static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2345 12 : ApiTestFuzzer::Fuzz();
2346 12 : args.GetReturnValue().Set(v8_num(17.2));
2347 12 : }
2348 :
2349 :
2350 30 : static void GetKnurd(Local<String> property,
2351 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2352 30 : ApiTestFuzzer::Fuzz();
2353 30 : info.GetReturnValue().Set(v8_num(15.2));
2354 30 : }
2355 :
2356 :
2357 26645 : THREADED_TEST(DescriptorInheritance) {
2358 6 : v8::Isolate* isolate = CcTest::isolate();
2359 12 : v8::HandleScope scope(isolate);
2360 6 : v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2361 12 : super->PrototypeTemplate()->Set(isolate, "flabby",
2362 : v8::FunctionTemplate::New(isolate,
2363 : GetFlabby));
2364 12 : super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2365 :
2366 12 : super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2367 :
2368 6 : v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2369 6 : base1->Inherit(super);
2370 12 : base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2371 :
2372 6 : v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2373 6 : base2->Inherit(super);
2374 12 : base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2375 :
2376 6 : LocalContext env;
2377 :
2378 30 : CHECK(env->Global()
2379 : ->Set(env.local(), v8_str("s"),
2380 : super->GetFunction(env.local()).ToLocalChecked())
2381 : .FromJust());
2382 30 : CHECK(env->Global()
2383 : ->Set(env.local(), v8_str("base1"),
2384 : base1->GetFunction(env.local()).ToLocalChecked())
2385 : .FromJust());
2386 30 : CHECK(env->Global()
2387 : ->Set(env.local(), v8_str("base2"),
2388 : base2->GetFunction(env.local()).ToLocalChecked())
2389 : .FromJust());
2390 :
2391 : // Checks right __proto__ chain.
2392 6 : CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2393 : ->BooleanValue(isolate));
2394 6 : CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2395 : ->BooleanValue(isolate));
2396 :
2397 12 : CHECK(v8_compile("s.prototype.PI == 3.14")
2398 : ->Run(env.local())
2399 : .ToLocalChecked()
2400 : ->BooleanValue(isolate));
2401 :
2402 : // Instance accessor should not be visible on function object or its prototype
2403 6 : CHECK(CompileRun("s.knurd == undefined")->BooleanValue(isolate));
2404 6 : CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue(isolate));
2405 6 : CHECK(
2406 : CompileRun("base1.prototype.knurd == undefined")->BooleanValue(isolate));
2407 :
2408 30 : CHECK(env->Global()
2409 : ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2410 : .ToLocalChecked()
2411 : ->NewInstance(env.local())
2412 : .ToLocalChecked())
2413 : .FromJust());
2414 12 : CHECK_EQ(17.2,
2415 : CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2416 6 : CHECK(CompileRun("'flabby' in obj")->BooleanValue(isolate));
2417 12 : CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2418 6 : CHECK(CompileRun("'knurd' in obj")->BooleanValue(isolate));
2419 12 : CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2420 :
2421 30 : CHECK(env->Global()
2422 : ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2423 : .ToLocalChecked()
2424 : ->NewInstance(env.local())
2425 : .ToLocalChecked())
2426 : .FromJust());
2427 12 : CHECK_EQ(17.2,
2428 : CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2429 6 : CHECK(CompileRun("'flabby' in obj2")->BooleanValue(isolate));
2430 12 : CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2431 6 : CHECK(CompileRun("'knurd' in obj2")->BooleanValue(isolate));
2432 12 : CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2433 :
2434 : // base1 and base2 cannot cross reference to each's prototype
2435 6 : CHECK(CompileRun("obj.v2")->IsUndefined());
2436 6 : CHECK(CompileRun("obj2.v1")->IsUndefined());
2437 6 : }
2438 :
2439 26645 : THREADED_TEST(DescriptorInheritance2) {
2440 6 : LocalContext env;
2441 6 : v8::Isolate* isolate = CcTest::isolate();
2442 12 : v8::HandleScope scope(isolate);
2443 6 : v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2444 6 : fun_A->SetClassName(v8_str("A"));
2445 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2446 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2447 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2448 :
2449 6 : v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2450 6 : fun_B->SetClassName(v8_str("B"));
2451 6 : fun_B->Inherit(fun_A);
2452 :
2453 6 : v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2454 6 : fun_C->SetClassName(v8_str("C"));
2455 6 : fun_C->Inherit(fun_B);
2456 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2457 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2458 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2459 :
2460 6 : v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2461 6 : fun_D->SetClassName(v8_str("D"));
2462 6 : fun_D->Inherit(fun_C);
2463 :
2464 6 : v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2465 6 : fun_E->SetClassName(v8_str("E"));
2466 6 : fun_E->Inherit(fun_D);
2467 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2468 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2469 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2470 :
2471 6 : v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2472 6 : fun_F->SetClassName(v8_str("F"));
2473 6 : fun_F->Inherit(fun_E);
2474 6 : v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2475 : const int kDataPropertiesNumber = 100;
2476 1206 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2477 600 : v8::Local<v8::Value> val = v8_num(i);
2478 600 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2479 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2480 :
2481 600 : templ->Set(name, val);
2482 600 : templ->Set(val_str, val);
2483 : }
2484 :
2485 30 : CHECK(env->Global()
2486 : ->Set(env.local(), v8_str("F"),
2487 : fun_F->GetFunction(env.local()).ToLocalChecked())
2488 : .FromJust());
2489 :
2490 : v8::Local<v8::Script> script = v8_compile("o = new F()");
2491 :
2492 1206 : for (int i = 0; i < 100; i++) {
2493 1200 : v8::HandleScope scope(isolate);
2494 600 : script->Run(env.local()).ToLocalChecked();
2495 : }
2496 6 : v8::Local<v8::Object> object = script->Run(env.local())
2497 : .ToLocalChecked()
2498 6 : ->ToObject(env.local())
2499 : .ToLocalChecked();
2500 :
2501 12 : CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2502 12 : CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2503 12 : CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2504 :
2505 12 : CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2506 12 : CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2507 12 : CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2508 :
2509 12 : CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2510 12 : CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2511 12 : CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2512 :
2513 1206 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2514 600 : v8::Local<v8::Value> val = v8_num(i);
2515 1200 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2516 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2517 :
2518 1800 : CHECK_EQ(i, object->Get(env.local(), name)
2519 : .ToLocalChecked()
2520 : ->IntegerValue(env.local())
2521 : .FromJust());
2522 1800 : CHECK_EQ(i, object->Get(env.local(), val)
2523 : .ToLocalChecked()
2524 : ->IntegerValue(env.local())
2525 : .FromJust());
2526 : }
2527 6 : }
2528 :
2529 :
2530 : // Helper functions for Interceptor/Accessor interaction tests
2531 :
2532 36 : void SimpleAccessorGetter(Local<String> name,
2533 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2534 : Local<Object> self = Local<Object>::Cast(info.This());
2535 : info.GetReturnValue().Set(
2536 36 : self->Get(info.GetIsolate()->GetCurrentContext(),
2537 144 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
2538 : .ToLocalChecked());
2539 36 : }
2540 :
2541 6 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2542 : const v8::PropertyCallbackInfo<void>& info) {
2543 : Local<Object> self = Local<Object>::Cast(info.This());
2544 24 : CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2545 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name),
2546 : value)
2547 : .FromJust());
2548 6 : }
2549 :
2550 36 : void SymbolAccessorGetter(Local<Name> name,
2551 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2552 36 : CHECK(name->IsSymbol());
2553 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2554 72 : if (sym->Name()->IsUndefined())
2555 : return;
2556 36 : SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2557 : }
2558 :
2559 6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2560 : const v8::PropertyCallbackInfo<void>& info) {
2561 6 : CHECK(name->IsSymbol());
2562 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2563 12 : if (sym->Name()->IsUndefined())
2564 : return;
2565 6 : SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2566 : }
2567 :
2568 5 : void SymbolAccessorGetterReturnsDefault(
2569 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2570 5 : CHECK(name->IsSymbol());
2571 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2572 10 : if (sym->Name()->IsUndefined()) return;
2573 : info.GetReturnValue().Set(info.Data());
2574 : }
2575 :
2576 5 : static void ThrowingSymbolAccessorGetter(
2577 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2578 10 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2579 5 : }
2580 :
2581 :
2582 26645 : THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2583 6 : v8::Isolate* isolate = CcTest::isolate();
2584 12 : v8::HandleScope scope(isolate);
2585 6 : LocalContext env;
2586 : v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2587 : i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2588 6 : CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
2589 : CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2590 6 : CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
2591 : // But we should still have an AccessorInfo.
2592 12 : i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2593 : i::LookupIterator it(CcTest::i_isolate(), a, name,
2594 6 : i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2595 6 : CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2596 12 : CHECK(it.GetAccessors()->IsAccessorInfo());
2597 6 : }
2598 :
2599 :
2600 26645 : THREADED_TEST(UndefinedIsNotEnumerable) {
2601 6 : LocalContext env;
2602 12 : v8::HandleScope scope(env->GetIsolate());
2603 : v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2604 6 : CHECK(result->IsFalse());
2605 6 : }
2606 :
2607 :
2608 : v8::Local<Script> call_recursively_script;
2609 : static const int kTargetRecursionDepth = 100; // near maximum
2610 :
2611 606 : static void CallScriptRecursivelyCall(
2612 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2613 606 : ApiTestFuzzer::Fuzz();
2614 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2615 : int depth = args.This()
2616 1818 : ->Get(context, v8_str("depth"))
2617 : .ToLocalChecked()
2618 1212 : ->Int32Value(context)
2619 : .FromJust();
2620 612 : if (depth == kTargetRecursionDepth) return;
2621 3000 : CHECK(args.This()
2622 : ->Set(context, v8_str("depth"),
2623 : v8::Integer::New(args.GetIsolate(), depth + 1))
2624 : .FromJust());
2625 : args.GetReturnValue().Set(
2626 600 : call_recursively_script->Run(context).ToLocalChecked());
2627 : }
2628 :
2629 :
2630 606 : static void CallFunctionRecursivelyCall(
2631 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2632 606 : ApiTestFuzzer::Fuzz();
2633 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2634 : int depth = args.This()
2635 1818 : ->Get(context, v8_str("depth"))
2636 : .ToLocalChecked()
2637 1212 : ->Int32Value(context)
2638 : .FromJust();
2639 606 : if (depth == kTargetRecursionDepth) {
2640 : printf("[depth = %d]\n", depth);
2641 6 : return;
2642 : }
2643 3000 : CHECK(args.This()
2644 : ->Set(context, v8_str("depth"),
2645 : v8::Integer::New(args.GetIsolate(), depth + 1))
2646 : .FromJust());
2647 : v8::Local<Value> function =
2648 : args.This()
2649 1800 : ->Get(context, v8_str("callFunctionRecursively"))
2650 : .ToLocalChecked();
2651 : args.GetReturnValue().Set(function.As<Function>()
2652 1200 : ->Call(context, args.This(), 0, nullptr)
2653 : .ToLocalChecked());
2654 : }
2655 :
2656 :
2657 26645 : THREADED_TEST(DeepCrossLanguageRecursion) {
2658 6 : v8::Isolate* isolate = CcTest::isolate();
2659 12 : v8::HandleScope scope(isolate);
2660 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2661 18 : global->Set(v8_str("callScriptRecursively"),
2662 6 : v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2663 18 : global->Set(v8_str("callFunctionRecursively"),
2664 6 : v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2665 6 : LocalContext env(nullptr, global);
2666 :
2667 30 : CHECK(env->Global()
2668 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2669 : .FromJust());
2670 6 : call_recursively_script = v8_compile("callScriptRecursively()");
2671 6 : call_recursively_script->Run(env.local()).ToLocalChecked();
2672 6 : call_recursively_script = v8::Local<Script>();
2673 :
2674 30 : CHECK(env->Global()
2675 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2676 : .FromJust());
2677 : CompileRun("callFunctionRecursively()");
2678 6 : }
2679 :
2680 :
2681 24 : static void ThrowingPropertyHandlerGet(
2682 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2683 : // Since this interceptor is used on "with" objects, the runtime will look up
2684 : // @@unscopables. Punt.
2685 24 : if (key->IsSymbol()) return;
2686 12 : ApiTestFuzzer::Fuzz();
2687 24 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2688 : }
2689 :
2690 :
2691 0 : static void ThrowingPropertyHandlerSet(
2692 : Local<Name> key, Local<Value>,
2693 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2694 0 : info.GetIsolate()->ThrowException(key);
2695 : info.GetReturnValue().SetUndefined(); // not the same as empty handle
2696 0 : }
2697 :
2698 :
2699 26645 : THREADED_TEST(CallbackExceptionRegression) {
2700 6 : v8::Isolate* isolate = CcTest::isolate();
2701 12 : v8::HandleScope scope(isolate);
2702 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2703 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2704 6 : ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2705 6 : LocalContext env;
2706 30 : CHECK(env->Global()
2707 : ->Set(env.local(), v8_str("obj"),
2708 : obj->NewInstance(env.local()).ToLocalChecked())
2709 : .FromJust());
2710 : v8::Local<Value> otto =
2711 6 : CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2712 18 : CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2713 : v8::Local<Value> netto =
2714 6 : CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2715 18 : CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2716 6 : }
2717 :
2718 :
2719 26645 : THREADED_TEST(FunctionPrototype) {
2720 6 : v8::Isolate* isolate = CcTest::isolate();
2721 12 : v8::HandleScope scope(isolate);
2722 6 : Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2723 24 : Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2724 6 : LocalContext env;
2725 30 : CHECK(env->Global()
2726 : ->Set(env.local(), v8_str("Foo"),
2727 : Foo->GetFunction(env.local()).ToLocalChecked())
2728 : .FromJust());
2729 6 : Local<Script> script = v8_compile("Foo.prototype.plak");
2730 6 : CHECK_EQ(v8_run_int32value(script), 321);
2731 6 : }
2732 :
2733 26645 : THREADED_TEST(InternalFields) {
2734 6 : LocalContext env;
2735 6 : v8::Isolate* isolate = env->GetIsolate();
2736 12 : v8::HandleScope scope(isolate);
2737 :
2738 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2739 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2740 6 : instance_templ->SetInternalFieldCount(1);
2741 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2742 : .ToLocalChecked()
2743 : ->NewInstance(env.local())
2744 : .ToLocalChecked();
2745 6 : CHECK_EQ(1, obj->InternalFieldCount());
2746 6 : CHECK(obj->GetInternalField(0)->IsUndefined());
2747 6 : obj->SetInternalField(0, v8_num(17));
2748 12 : CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2749 6 : }
2750 :
2751 26644 : TEST(InternalFieldsSubclassing) {
2752 5 : LocalContext env;
2753 5 : v8::Isolate* isolate = env->GetIsolate();
2754 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2755 10 : v8::HandleScope scope(isolate);
2756 60 : for (int nof_embedder_fields = 0;
2757 65 : nof_embedder_fields < i::JSObject::kMaxEmbedderFields;
2758 : nof_embedder_fields++) {
2759 60 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2760 60 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2761 60 : instance_templ->SetInternalFieldCount(nof_embedder_fields);
2762 : Local<Function> constructor =
2763 60 : templ->GetFunction(env.local()).ToLocalChecked();
2764 : // Check that instances have the correct NOF properties.
2765 : Local<v8::Object> obj =
2766 : constructor->NewInstance(env.local()).ToLocalChecked();
2767 :
2768 : i::Handle<i::JSObject> i_obj =
2769 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
2770 60 : CHECK_EQ(nof_embedder_fields, obj->InternalFieldCount());
2771 60 : CHECK_EQ(0, i_obj->map()->GetInObjectProperties());
2772 : // Check writing and reading internal fields.
2773 720 : for (int j = 0; j < nof_embedder_fields; j++) {
2774 330 : CHECK(obj->GetInternalField(j)->IsUndefined());
2775 330 : int value = 17 + j;
2776 330 : obj->SetInternalField(j, v8_num(value));
2777 : }
2778 720 : for (int j = 0; j < nof_embedder_fields; j++) {
2779 330 : int value = 17 + j;
2780 660 : CHECK_EQ(value,
2781 : obj->GetInternalField(j)->Int32Value(env.local()).FromJust());
2782 : }
2783 240 : CHECK(env->Global()
2784 : ->Set(env.local(), v8_str("BaseClass"), constructor)
2785 : .FromJust());
2786 : // Create various levels of subclasses to stress instance size calculation.
2787 : const int kMaxNofProperties =
2788 : i::JSObject::kMaxInObjectProperties -
2789 60 : nof_embedder_fields * i::kEmbedderDataSlotSizeInTaggedSlots;
2790 : // Select only a few values to speed up the test.
2791 : int sizes[] = {0,
2792 : 1,
2793 : 2,
2794 : 3,
2795 : 4,
2796 : 5,
2797 : 6,
2798 60 : kMaxNofProperties / 4,
2799 60 : kMaxNofProperties / 2,
2800 60 : kMaxNofProperties - 2,
2801 60 : kMaxNofProperties - 1,
2802 60 : kMaxNofProperties + 1,
2803 60 : kMaxNofProperties + 2,
2804 60 : kMaxNofProperties * 2,
2805 480 : kMaxNofProperties * 2};
2806 1860 : for (size_t i = 0; i < arraysize(sizes); i++) {
2807 900 : int nof_properties = sizes[i];
2808 : bool in_object_only = nof_properties <= kMaxNofProperties;
2809 1800 : std::ostringstream src;
2810 : // Assembler source string for a subclass with {nof_properties}
2811 : // in-object properties.
2812 : src << "(function() {\n"
2813 : << " class SubClass extends BaseClass {\n"
2814 : << " constructor() {\n"
2815 900 : << " super();\n";
2816 : // Set {nof_properties} instance properties in the constructor.
2817 262170 : for (int j = 0; j < nof_properties; j++) {
2818 261270 : src << " this.property" << j << " = " << j << ";\n";
2819 : }
2820 : src << " }\n"
2821 : << " };\n"
2822 : << " let instance;\n"
2823 : << " for (let i = 0; i < 3; i++) {\n"
2824 : << " instance = new SubClass();\n"
2825 : << " }"
2826 : << " return instance;\n"
2827 900 : << "})();";
2828 900 : Local<v8::Object> value = CompileRun(src.str().c_str()).As<v8::Object>();
2829 :
2830 : i::Handle<i::JSObject> i_value =
2831 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*value));
2832 : #ifdef VERIFY_HEAP
2833 : i_value->HeapObjectVerify(i_isolate);
2834 : i_value->map()->HeapObjectVerify(i_isolate);
2835 : i_value->map()->FindRootMap(i_isolate)->HeapObjectVerify(i_isolate);
2836 : #endif
2837 900 : CHECK_EQ(nof_embedder_fields, value->InternalFieldCount());
2838 900 : if (in_object_only) {
2839 660 : CHECK_LE(nof_properties, i_value->map()->GetInObjectProperties());
2840 : } else {
2841 240 : CHECK_LE(i_value->map()->GetInObjectProperties(), kMaxNofProperties);
2842 : }
2843 :
2844 : // Make Sure we get the precise property count.
2845 1800 : i_value->map()->FindRootMap(i_isolate)->CompleteInobjectSlackTracking(
2846 900 : i_isolate);
2847 : // TODO(cbruni): fix accounting to make this condition true.
2848 : // CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
2849 900 : if (in_object_only) {
2850 660 : CHECK_EQ(nof_properties, i_value->map()->GetInObjectProperties());
2851 : } else {
2852 240 : CHECK_LE(i_value->map()->GetInObjectProperties(), kMaxNofProperties);
2853 : }
2854 : }
2855 : }
2856 5 : }
2857 :
2858 26645 : THREADED_TEST(InternalFieldsOfRegularObjects) {
2859 6 : LocalContext env;
2860 6 : v8::Isolate* isolate = env->GetIsolate();
2861 12 : v8::HandleScope scope(isolate);
2862 :
2863 6 : const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"};
2864 42 : for (size_t i = 0; i < arraysize(sources); ++i) {
2865 : i::ScopedVector<char> source(128);
2866 18 : i::SNPrintF(source, "(function() { return %s })()", sources[i]);
2867 : v8::Local<v8::Object> obj = CompileRun(source.start()).As<v8::Object>();
2868 18 : CHECK_EQ(0, obj->InternalFieldCount());
2869 : }
2870 6 : }
2871 :
2872 26645 : THREADED_TEST(GlobalObjectInternalFields) {
2873 6 : v8::Isolate* isolate = CcTest::isolate();
2874 12 : v8::HandleScope scope(isolate);
2875 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2876 6 : global_template->SetInternalFieldCount(1);
2877 6 : LocalContext env(nullptr, global_template);
2878 6 : v8::Local<v8::Object> global_proxy = env->Global();
2879 6 : v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2880 6 : CHECK_EQ(1, global->InternalFieldCount());
2881 6 : CHECK(global->GetInternalField(0)->IsUndefined());
2882 6 : global->SetInternalField(0, v8_num(17));
2883 12 : CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2884 6 : }
2885 :
2886 :
2887 26645 : THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2888 6 : LocalContext env;
2889 12 : v8::HandleScope scope(CcTest::isolate());
2890 :
2891 6 : v8::Local<v8::Object> global = env->Global();
2892 18 : CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2893 12 : CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2894 6 : }
2895 :
2896 24 : static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2897 : void* value) {
2898 24 : CHECK(HAS_SMI_TAG(reinterpret_cast<i::Address>(value)));
2899 24 : obj->SetAlignedPointerInInternalField(0, value);
2900 24 : CcTest::CollectAllGarbage();
2901 24 : CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2902 24 : }
2903 :
2904 26645 : THREADED_TEST(InternalFieldsAlignedPointers) {
2905 6 : LocalContext env;
2906 6 : v8::Isolate* isolate = env->GetIsolate();
2907 12 : v8::HandleScope scope(isolate);
2908 :
2909 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2910 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2911 6 : instance_templ->SetInternalFieldCount(1);
2912 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2913 : .ToLocalChecked()
2914 : ->NewInstance(env.local())
2915 : .ToLocalChecked();
2916 6 : CHECK_EQ(1, obj->InternalFieldCount());
2917 :
2918 6 : CheckAlignedPointerInInternalField(obj, nullptr);
2919 :
2920 6 : int* heap_allocated = new int[100];
2921 6 : CheckAlignedPointerInInternalField(obj, heap_allocated);
2922 6 : delete[] heap_allocated;
2923 :
2924 : int stack_allocated[100];
2925 6 : CheckAlignedPointerInInternalField(obj, stack_allocated);
2926 :
2927 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2928 6 : CheckAlignedPointerInInternalField(obj, huge);
2929 :
2930 : v8::Global<v8::Object> persistent(isolate, obj);
2931 6 : CHECK_EQ(1, Object::InternalFieldCount(persistent));
2932 6 : CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2933 6 : }
2934 :
2935 26645 : THREADED_TEST(SetAlignedPointerInInternalFields) {
2936 6 : LocalContext env;
2937 6 : v8::Isolate* isolate = env->GetIsolate();
2938 12 : v8::HandleScope scope(isolate);
2939 :
2940 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2941 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2942 6 : instance_templ->SetInternalFieldCount(2);
2943 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2944 : .ToLocalChecked()
2945 : ->NewInstance(env.local())
2946 : .ToLocalChecked();
2947 6 : CHECK_EQ(2, obj->InternalFieldCount());
2948 :
2949 6 : int* heap_allocated_1 = new int[100];
2950 6 : int* heap_allocated_2 = new int[100];
2951 6 : int indices[] = {0, 1};
2952 6 : void* values[] = {heap_allocated_1, heap_allocated_2};
2953 :
2954 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2955 6 : CcTest::CollectAllGarbage();
2956 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0));
2957 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1));
2958 :
2959 6 : indices[0] = 1;
2960 6 : indices[1] = 0;
2961 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2962 6 : CcTest::CollectAllGarbage();
2963 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0));
2964 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1));
2965 :
2966 6 : delete[] heap_allocated_1;
2967 6 : delete[] heap_allocated_2;
2968 6 : }
2969 :
2970 24 : static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2971 : void* value) {
2972 24 : CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2973 24 : (*env)->SetAlignedPointerInEmbedderData(index, value);
2974 24 : CcTest::CollectAllGarbage();
2975 24 : CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2976 24 : }
2977 :
2978 :
2979 : static void* AlignedTestPointer(int i) {
2980 1200 : return reinterpret_cast<void*>(i * 1234);
2981 : }
2982 :
2983 :
2984 26645 : THREADED_TEST(EmbedderDataAlignedPointers) {
2985 6 : LocalContext env;
2986 12 : v8::HandleScope scope(env->GetIsolate());
2987 :
2988 6 : CheckAlignedPointerInEmbedderData(&env, 0, nullptr);
2989 6 : CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields());
2990 :
2991 6 : int* heap_allocated = new int[100];
2992 6 : CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2993 6 : CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields());
2994 6 : delete[] heap_allocated;
2995 :
2996 : int stack_allocated[100];
2997 6 : CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2998 6 : CHECK_EQ(3, (*env)->GetNumberOfEmbedderDataFields());
2999 :
3000 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
3001 6 : CheckAlignedPointerInEmbedderData(&env, 3, huge);
3002 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3003 :
3004 : // Test growing of the embedder data's backing store.
3005 1206 : for (int i = 0; i < 100; i++) {
3006 600 : env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
3007 : }
3008 6 : CcTest::CollectAllGarbage();
3009 1206 : for (int i = 0; i < 100; i++) {
3010 600 : CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
3011 : }
3012 6 : }
3013 :
3014 30 : static void CheckEmbedderData(LocalContext* env, int index,
3015 : v8::Local<Value> data) {
3016 30 : (*env)->SetEmbedderData(index, data);
3017 30 : CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
3018 30 : }
3019 :
3020 :
3021 26645 : THREADED_TEST(EmbedderData) {
3022 6 : LocalContext env;
3023 6 : v8::Isolate* isolate = env->GetIsolate();
3024 12 : v8::HandleScope scope(isolate);
3025 :
3026 6 : CHECK_EQ(0, (*env)->GetNumberOfEmbedderDataFields());
3027 12 : CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
3028 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3029 12 : CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
3030 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3031 12 : CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
3032 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3033 6 : CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
3034 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3035 6 : CheckEmbedderData(&env, 211, v8::Boolean::New(isolate, true));
3036 6 : CHECK_EQ(212, (*env)->GetNumberOfEmbedderDataFields());
3037 6 : }
3038 :
3039 :
3040 26645 : THREADED_TEST(IdentityHash) {
3041 6 : LocalContext env;
3042 6 : v8::Isolate* isolate = env->GetIsolate();
3043 12 : v8::HandleScope scope(isolate);
3044 :
3045 : // Ensure that the test starts with an fresh heap to test whether the hash
3046 : // code is based on the address.
3047 6 : CcTest::CollectAllGarbage();
3048 6 : Local<v8::Object> obj = v8::Object::New(isolate);
3049 6 : int hash = obj->GetIdentityHash();
3050 6 : int hash1 = obj->GetIdentityHash();
3051 6 : CHECK_EQ(hash, hash1);
3052 12 : int hash2 = v8::Object::New(isolate)->GetIdentityHash();
3053 : // Since the identity hash is essentially a random number two consecutive
3054 : // objects should not be assigned the same hash code. If the test below fails
3055 : // the random number generator should be evaluated.
3056 6 : CHECK_NE(hash, hash2);
3057 6 : CcTest::CollectAllGarbage();
3058 12 : int hash3 = v8::Object::New(isolate)->GetIdentityHash();
3059 : // Make sure that the identity hash is not based on the initial address of
3060 : // the object alone. If the test below fails the random number generator
3061 : // should be evaluated.
3062 6 : CHECK_NE(hash, hash3);
3063 6 : int hash4 = obj->GetIdentityHash();
3064 6 : CHECK_EQ(hash, hash4);
3065 :
3066 : // Check identity hashes behaviour in the presence of JS accessors.
3067 : // Put a getter for 'v8::IdentityHash' on the Object's prototype:
3068 : {
3069 : CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
3070 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3071 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3072 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3073 : }
3074 : {
3075 : CompileRun(
3076 : "function cnst() { return 42; };\n"
3077 : "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3078 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3079 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3080 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3081 : }
3082 6 : }
3083 :
3084 :
3085 12 : void GlobalProxyIdentityHash(bool set_in_js) {
3086 12 : LocalContext env;
3087 12 : v8::Isolate* isolate = env->GetIsolate();
3088 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3089 24 : v8::HandleScope scope(isolate);
3090 12 : Local<Object> global_proxy = env->Global();
3091 : i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
3092 48 : CHECK(env->Global()
3093 : ->Set(env.local(), v8_str("global"), global_proxy)
3094 : .FromJust());
3095 : int32_t hash1;
3096 12 : if (set_in_js) {
3097 : CompileRun("var m = new Set(); m.add(global);");
3098 6 : i::Object original_hash = i_global_proxy->GetHash();
3099 6 : CHECK(original_hash->IsSmi());
3100 : hash1 = i::Smi::ToInt(original_hash);
3101 : } else {
3102 12 : hash1 = i_global_proxy->GetOrCreateHash(i_isolate)->value();
3103 : }
3104 : // Hash should be retained after being detached.
3105 12 : env->DetachGlobal();
3106 12 : int hash2 = global_proxy->GetIdentityHash();
3107 12 : CHECK_EQ(hash1, hash2);
3108 : {
3109 : // Re-attach global proxy to a new context, hash should stay the same.
3110 12 : LocalContext env2(nullptr, Local<ObjectTemplate>(), global_proxy);
3111 12 : int hash3 = global_proxy->GetIdentityHash();
3112 12 : CHECK_EQ(hash1, hash3);
3113 : }
3114 12 : }
3115 :
3116 :
3117 26645 : THREADED_TEST(GlobalProxyIdentityHash) {
3118 6 : GlobalProxyIdentityHash(true);
3119 6 : GlobalProxyIdentityHash(false);
3120 6 : }
3121 :
3122 :
3123 26644 : TEST(SymbolIdentityHash) {
3124 5 : LocalContext env;
3125 5 : v8::Isolate* isolate = env->GetIsolate();
3126 10 : v8::HandleScope scope(isolate);
3127 :
3128 : {
3129 5 : Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3130 5 : int hash = symbol->GetIdentityHash();
3131 5 : int hash1 = symbol->GetIdentityHash();
3132 5 : CHECK_EQ(hash, hash1);
3133 5 : CcTest::CollectAllGarbage();
3134 5 : int hash3 = symbol->GetIdentityHash();
3135 5 : CHECK_EQ(hash, hash3);
3136 : }
3137 :
3138 : {
3139 : v8::Local<v8::Symbol> js_symbol =
3140 : CompileRun("Symbol('foo')").As<v8::Symbol>();
3141 5 : int hash = js_symbol->GetIdentityHash();
3142 5 : int hash1 = js_symbol->GetIdentityHash();
3143 5 : CHECK_EQ(hash, hash1);
3144 5 : CcTest::CollectAllGarbage();
3145 5 : int hash3 = js_symbol->GetIdentityHash();
3146 5 : CHECK_EQ(hash, hash3);
3147 : }
3148 5 : }
3149 :
3150 :
3151 26644 : TEST(StringIdentityHash) {
3152 5 : LocalContext env;
3153 5 : v8::Isolate* isolate = env->GetIsolate();
3154 10 : v8::HandleScope scope(isolate);
3155 :
3156 5 : Local<v8::String> str = v8_str("str1");
3157 5 : int hash = str->GetIdentityHash();
3158 5 : int hash1 = str->GetIdentityHash();
3159 5 : CHECK_EQ(hash, hash1);
3160 5 : CcTest::CollectAllGarbage();
3161 5 : int hash3 = str->GetIdentityHash();
3162 5 : CHECK_EQ(hash, hash3);
3163 :
3164 5 : Local<v8::String> str2 = v8_str("str1");
3165 5 : int hash4 = str2->GetIdentityHash();
3166 5 : CHECK_EQ(hash, hash4);
3167 5 : }
3168 :
3169 :
3170 26645 : THREADED_TEST(SymbolProperties) {
3171 6 : LocalContext env;
3172 6 : v8::Isolate* isolate = env->GetIsolate();
3173 12 : v8::HandleScope scope(isolate);
3174 :
3175 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3176 6 : v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3177 6 : v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
3178 6 : v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
3179 6 : v8::Local<v8::Symbol> sym4 = v8::Symbol::New(isolate, v8_str("native"));
3180 :
3181 6 : CcTest::CollectAllGarbage();
3182 :
3183 : // Check basic symbol functionality.
3184 6 : CHECK(sym1->IsSymbol());
3185 6 : CHECK(sym2->IsSymbol());
3186 6 : CHECK(!obj->IsSymbol());
3187 :
3188 12 : CHECK(sym1->Equals(env.local(), sym1).FromJust());
3189 12 : CHECK(sym2->Equals(env.local(), sym2).FromJust());
3190 12 : CHECK(!sym1->Equals(env.local(), sym2).FromJust());
3191 12 : CHECK(!sym2->Equals(env.local(), sym1).FromJust());
3192 6 : CHECK(sym1->StrictEquals(sym1));
3193 6 : CHECK(sym2->StrictEquals(sym2));
3194 6 : CHECK(!sym1->StrictEquals(sym2));
3195 6 : CHECK(!sym2->StrictEquals(sym1));
3196 :
3197 24 : CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
3198 :
3199 : v8::Local<v8::Value> sym_val = sym2;
3200 6 : CHECK(sym_val->IsSymbol());
3201 12 : CHECK(sym_val->Equals(env.local(), sym2).FromJust());
3202 6 : CHECK(sym_val->StrictEquals(sym2));
3203 12 : CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
3204 :
3205 6 : v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3206 6 : CHECK(sym_obj->IsSymbolObject());
3207 6 : CHECK(!sym2->IsSymbolObject());
3208 6 : CHECK(!obj->IsSymbolObject());
3209 12 : CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
3210 6 : CHECK(!sym_obj->StrictEquals(sym2));
3211 12 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3212 : ->Equals(env.local(), sym_obj)
3213 : .FromJust());
3214 18 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3215 : ->ValueOf()
3216 : ->Equals(env.local(), sym2)
3217 : .FromJust());
3218 :
3219 : // Make sure delete of a non-existent symbol property works.
3220 12 : CHECK(obj->Delete(env.local(), sym1).FromJust());
3221 12 : CHECK(!obj->Has(env.local(), sym1).FromJust());
3222 :
3223 18 : CHECK(
3224 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
3225 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3226 18 : CHECK_EQ(1503, obj->Get(env.local(), sym1)
3227 : .ToLocalChecked()
3228 : ->Int32Value(env.local())
3229 : .FromJust());
3230 18 : CHECK(
3231 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
3232 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3233 18 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3234 : .ToLocalChecked()
3235 : ->Int32Value(env.local())
3236 : .FromJust());
3237 12 : CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
3238 :
3239 12 : CHECK_EQ(0u,
3240 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3241 : unsigned num_props =
3242 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3243 24 : CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
3244 : .FromJust());
3245 12 : CHECK_EQ(1u,
3246 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3247 12 : CHECK_EQ(num_props + 1,
3248 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3249 :
3250 6 : CcTest::CollectAllGarbage();
3251 :
3252 12 : CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
3253 : SymbolAccessorSetter)
3254 : .FromJust());
3255 12 : CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
3256 18 : CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
3257 24 : CHECK(obj->Get(env.local(), sym3)
3258 : .ToLocalChecked()
3259 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3260 : .FromJust());
3261 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3262 : .ToLocalChecked()
3263 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3264 : .FromJust());
3265 :
3266 12 : CHECK(obj->SetNativeDataProperty(env.local(), sym4, SymbolAccessorGetter)
3267 : .FromJust());
3268 12 : CHECK(obj->Get(env.local(), sym4).ToLocalChecked()->IsUndefined());
3269 24 : CHECK(obj->Set(env.local(), v8_str("accessor_native"),
3270 : v8::Integer::New(isolate, 123))
3271 : .FromJust());
3272 18 : CHECK_EQ(123, obj->Get(env.local(), sym4)
3273 : .ToLocalChecked()
3274 : ->Int32Value(env.local())
3275 : .FromJust());
3276 18 : CHECK(obj->Set(env.local(), sym4, v8::Integer::New(isolate, 314)).FromJust());
3277 24 : CHECK(obj->Get(env.local(), sym4)
3278 : .ToLocalChecked()
3279 : ->Equals(env.local(), v8::Integer::New(isolate, 314))
3280 : .FromJust());
3281 18 : CHECK(obj->Delete(env.local(), v8_str("accessor_native")).FromJust());
3282 :
3283 : // Add another property and delete it afterwards to force the object in
3284 : // slow case.
3285 18 : CHECK(
3286 : obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
3287 18 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3288 : .ToLocalChecked()
3289 : ->Int32Value(env.local())
3290 : .FromJust());
3291 18 : CHECK_EQ(2008, obj->Get(env.local(), sym2)
3292 : .ToLocalChecked()
3293 : ->Int32Value(env.local())
3294 : .FromJust());
3295 18 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3296 : .ToLocalChecked()
3297 : ->Int32Value(env.local())
3298 : .FromJust());
3299 12 : CHECK_EQ(2u,
3300 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3301 :
3302 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3303 12 : CHECK(obj->Has(env.local(), sym2).FromJust());
3304 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3305 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3306 12 : CHECK(obj->Delete(env.local(), sym2).FromJust());
3307 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3308 12 : CHECK(!obj->Has(env.local(), sym2).FromJust());
3309 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3310 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3311 18 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3312 : .ToLocalChecked()
3313 : ->Int32Value(env.local())
3314 : .FromJust());
3315 24 : CHECK(obj->Get(env.local(), sym3)
3316 : .ToLocalChecked()
3317 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3318 : .FromJust());
3319 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3320 : .ToLocalChecked()
3321 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3322 : .FromJust());
3323 12 : CHECK_EQ(2u,
3324 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3325 :
3326 : // Symbol properties are inherited.
3327 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3328 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3329 12 : CHECK(child->Has(env.local(), sym1).FromJust());
3330 18 : CHECK_EQ(2002, child->Get(env.local(), sym1)
3331 : .ToLocalChecked()
3332 : ->Int32Value(env.local())
3333 : .FromJust());
3334 24 : CHECK(obj->Get(env.local(), sym3)
3335 : .ToLocalChecked()
3336 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3337 : .FromJust());
3338 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3339 : .ToLocalChecked()
3340 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3341 : .FromJust());
3342 12 : CHECK_EQ(0u,
3343 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3344 6 : }
3345 :
3346 :
3347 26645 : THREADED_TEST(SymbolTemplateProperties) {
3348 6 : LocalContext env;
3349 6 : v8::Isolate* isolate = env->GetIsolate();
3350 12 : v8::HandleScope scope(isolate);
3351 6 : v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3352 6 : v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3353 6 : CHECK(!name.IsEmpty());
3354 18 : foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3355 : v8::Local<v8::Object> new_instance =
3356 18 : foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3357 6 : CHECK(!new_instance.IsEmpty());
3358 12 : CHECK(new_instance->Has(env.local(), name).FromJust());
3359 6 : }
3360 :
3361 :
3362 26645 : THREADED_TEST(PrivatePropertiesOnProxies) {
3363 6 : LocalContext env;
3364 6 : v8::Isolate* isolate = env->GetIsolate();
3365 12 : v8::HandleScope scope(isolate);
3366 :
3367 6 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3368 6 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3369 :
3370 : v8::Local<v8::Proxy> proxy =
3371 6 : v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3372 :
3373 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3374 : v8::Local<v8::Private> priv2 =
3375 6 : v8::Private::New(isolate, v8_str("my-private"));
3376 :
3377 6 : CcTest::CollectAllGarbage();
3378 :
3379 24 : CHECK(priv2->Name()
3380 : ->Equals(env.local(),
3381 : v8::String::NewFromUtf8(isolate, "my-private",
3382 : v8::NewStringType::kNormal)
3383 : .ToLocalChecked())
3384 : .FromJust());
3385 :
3386 : // Make sure delete of a non-existent private symbol property works.
3387 12 : proxy->DeletePrivate(env.local(), priv1).FromJust();
3388 12 : CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3389 :
3390 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3391 : .FromJust());
3392 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3393 18 : CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3394 : .ToLocalChecked()
3395 : ->Int32Value(env.local())
3396 : .FromJust());
3397 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3398 : .FromJust());
3399 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3400 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3401 : .ToLocalChecked()
3402 : ->Int32Value(env.local())
3403 : .FromJust());
3404 :
3405 12 : CHECK_EQ(0u,
3406 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3407 : unsigned num_props =
3408 12 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3409 24 : CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3410 : isolate, "bla", v8::NewStringType::kNormal)
3411 : .ToLocalChecked(),
3412 : v8::Integer::New(isolate, 20))
3413 : .FromJust());
3414 12 : CHECK_EQ(1u,
3415 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3416 12 : CHECK_EQ(num_props + 1,
3417 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3418 :
3419 6 : CcTest::CollectAllGarbage();
3420 :
3421 : // Add another property and delete it afterwards to force the object in
3422 : // slow case.
3423 18 : CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3424 : .FromJust());
3425 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3426 : .ToLocalChecked()
3427 : ->Int32Value(env.local())
3428 : .FromJust());
3429 18 : CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3430 : .ToLocalChecked()
3431 : ->Int32Value(env.local())
3432 : .FromJust());
3433 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3434 : .ToLocalChecked()
3435 : ->Int32Value(env.local())
3436 : .FromJust());
3437 12 : CHECK_EQ(1u,
3438 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3439 :
3440 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3441 12 : CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3442 12 : CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3443 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3444 12 : CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3445 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3446 : .ToLocalChecked()
3447 : ->Int32Value(env.local())
3448 : .FromJust());
3449 12 : CHECK_EQ(1u,
3450 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3451 :
3452 : // Private properties are not inherited (for the time being).
3453 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3454 12 : CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3455 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3456 12 : CHECK_EQ(0u,
3457 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3458 6 : }
3459 :
3460 :
3461 26645 : THREADED_TEST(PrivateProperties) {
3462 6 : LocalContext env;
3463 6 : v8::Isolate* isolate = env->GetIsolate();
3464 12 : v8::HandleScope scope(isolate);
3465 :
3466 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3467 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3468 : v8::Local<v8::Private> priv2 =
3469 6 : v8::Private::New(isolate, v8_str("my-private"));
3470 :
3471 6 : CcTest::CollectAllGarbage();
3472 :
3473 24 : CHECK(priv2->Name()
3474 : ->Equals(env.local(),
3475 : v8::String::NewFromUtf8(isolate, "my-private",
3476 : v8::NewStringType::kNormal)
3477 : .ToLocalChecked())
3478 : .FromJust());
3479 :
3480 : // Make sure delete of a non-existent private symbol property works.
3481 12 : obj->DeletePrivate(env.local(), priv1).FromJust();
3482 12 : CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3483 :
3484 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3485 : .FromJust());
3486 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3487 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3488 : .ToLocalChecked()
3489 : ->Int32Value(env.local())
3490 : .FromJust());
3491 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3492 : .FromJust());
3493 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3494 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3495 : .ToLocalChecked()
3496 : ->Int32Value(env.local())
3497 : .FromJust());
3498 :
3499 12 : CHECK_EQ(0u,
3500 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3501 : unsigned num_props =
3502 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3503 24 : CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3504 : isolate, "bla", v8::NewStringType::kNormal)
3505 : .ToLocalChecked(),
3506 : v8::Integer::New(isolate, 20))
3507 : .FromJust());
3508 12 : CHECK_EQ(1u,
3509 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3510 12 : CHECK_EQ(num_props + 1,
3511 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3512 :
3513 6 : CcTest::CollectAllGarbage();
3514 :
3515 : // Add another property and delete it afterwards to force the object in
3516 : // slow case.
3517 18 : CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3518 : .FromJust());
3519 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3520 : .ToLocalChecked()
3521 : ->Int32Value(env.local())
3522 : .FromJust());
3523 18 : CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3524 : .ToLocalChecked()
3525 : ->Int32Value(env.local())
3526 : .FromJust());
3527 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3528 : .ToLocalChecked()
3529 : ->Int32Value(env.local())
3530 : .FromJust());
3531 12 : CHECK_EQ(1u,
3532 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3533 :
3534 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3535 12 : CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3536 12 : CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3537 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3538 12 : CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3539 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3540 : .ToLocalChecked()
3541 : ->Int32Value(env.local())
3542 : .FromJust());
3543 12 : CHECK_EQ(1u,
3544 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3545 :
3546 : // Private properties are not inherited (for the time being).
3547 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3548 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3549 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3550 12 : CHECK_EQ(0u,
3551 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3552 6 : }
3553 :
3554 :
3555 26645 : THREADED_TEST(GlobalSymbols) {
3556 6 : LocalContext env;
3557 6 : v8::Isolate* isolate = env->GetIsolate();
3558 12 : v8::HandleScope scope(isolate);
3559 :
3560 6 : v8::Local<String> name = v8_str("my-symbol");
3561 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3562 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3563 6 : CHECK(glob2->SameValue(glob));
3564 :
3565 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3566 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3567 6 : CHECK(glob_api2->SameValue(glob_api));
3568 6 : CHECK(!glob_api->SameValue(glob));
3569 :
3570 6 : v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3571 6 : CHECK(!sym->SameValue(glob));
3572 :
3573 : CompileRun("var sym2 = Symbol.for('my-symbol')");
3574 : v8::Local<Value> sym2 =
3575 24 : env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3576 6 : CHECK(sym2->SameValue(glob));
3577 6 : CHECK(!sym2->SameValue(glob_api));
3578 6 : }
3579 :
3580 26645 : THREADED_TEST(GlobalSymbolsNoContext) {
3581 6 : v8::Isolate* isolate = CcTest::isolate();
3582 12 : v8::HandleScope scope(isolate);
3583 :
3584 6 : v8::Local<String> name = v8_str("my-symbol");
3585 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3586 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3587 6 : CHECK(glob2->SameValue(glob));
3588 :
3589 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3590 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3591 6 : CHECK(glob_api2->SameValue(glob_api));
3592 6 : CHECK(!glob_api->SameValue(glob));
3593 6 : }
3594 :
3595 60 : static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3596 : const char* name) {
3597 60 : LocalContext env;
3598 60 : v8::Isolate* isolate = env->GetIsolate();
3599 120 : v8::HandleScope scope(isolate);
3600 :
3601 60 : v8::Local<v8::Symbol> symbol = getter(isolate);
3602 120 : std::string script = std::string("var sym = ") + name;
3603 : CompileRun(script.c_str());
3604 : v8::Local<Value> value =
3605 240 : env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3606 :
3607 60 : CHECK(!value.IsEmpty());
3608 60 : CHECK(!symbol.IsEmpty());
3609 60 : CHECK(value->SameValue(symbol));
3610 60 : }
3611 :
3612 :
3613 26645 : THREADED_TEST(WellKnownSymbols) {
3614 6 : CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3615 6 : CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3616 6 : CheckWellKnownSymbol(v8::Symbol::GetHasInstance, "Symbol.hasInstance");
3617 : CheckWellKnownSymbol(v8::Symbol::GetIsConcatSpreadable,
3618 6 : "Symbol.isConcatSpreadable");
3619 6 : CheckWellKnownSymbol(v8::Symbol::GetMatch, "Symbol.match");
3620 6 : CheckWellKnownSymbol(v8::Symbol::GetReplace, "Symbol.replace");
3621 6 : CheckWellKnownSymbol(v8::Symbol::GetSearch, "Symbol.search");
3622 6 : CheckWellKnownSymbol(v8::Symbol::GetSplit, "Symbol.split");
3623 6 : CheckWellKnownSymbol(v8::Symbol::GetToPrimitive, "Symbol.toPrimitive");
3624 6 : CheckWellKnownSymbol(v8::Symbol::GetToStringTag, "Symbol.toStringTag");
3625 6 : }
3626 :
3627 :
3628 26645 : THREADED_TEST(GlobalPrivates) {
3629 6 : i::FLAG_allow_natives_syntax = true;
3630 6 : LocalContext env;
3631 6 : v8::Isolate* isolate = env->GetIsolate();
3632 12 : v8::HandleScope scope(isolate);
3633 :
3634 6 : v8::Local<String> name = v8_str("my-private");
3635 6 : v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3636 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3637 18 : CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3638 : .FromJust());
3639 :
3640 6 : v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3641 12 : CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3642 :
3643 6 : v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3644 12 : CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3645 :
3646 : CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3647 : v8::Local<Value> intern =
3648 24 : env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3649 12 : CHECK(!obj->Has(env.local(), intern).FromJust());
3650 6 : }
3651 :
3652 :
3653 : class ScopedArrayBufferContents {
3654 : public:
3655 : explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3656 36 : : contents_(contents) {}
3657 36 : ~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
3658 : void* Data() const { return contents_.Data(); }
3659 : size_t ByteLength() const { return contents_.ByteLength(); }
3660 :
3661 : void* AllocationBase() const { return contents_.AllocationBase(); }
3662 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3663 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3664 : return contents_.AllocationMode();
3665 : }
3666 :
3667 : private:
3668 : const v8::ArrayBuffer::Contents contents_;
3669 : };
3670 :
3671 : template <typename T>
3672 282 : static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3673 282 : CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3674 1410 : for (int i = 0; i < value->InternalFieldCount(); i++) {
3675 1692 : CHECK_EQ(0, value->GetInternalField(i)
3676 : ->Int32Value(CcTest::isolate()->GetCurrentContext())
3677 : .FromJust());
3678 : }
3679 282 : }
3680 :
3681 :
3682 26645 : THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3683 6 : LocalContext env;
3684 6 : v8::Isolate* isolate = env->GetIsolate();
3685 12 : v8::HandleScope handle_scope(isolate);
3686 :
3687 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3688 6 : CheckInternalFieldsAreZero(ab);
3689 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3690 6 : CHECK(!ab->IsExternal());
3691 6 : CcTest::CollectAllGarbage();
3692 :
3693 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3694 6 : CHECK(ab->IsExternal());
3695 :
3696 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3697 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3698 6 : CHECK_NOT_NULL(data);
3699 24 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3700 :
3701 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3702 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3703 :
3704 : result = CompileRun(
3705 : "var u8 = new Uint8Array(ab);"
3706 : "u8[0] = 0xFF;"
3707 : "u8[1] = 0xAA;"
3708 : "u8.length");
3709 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3710 12 : CHECK_EQ(0xFF, data[0]);
3711 12 : CHECK_EQ(0xAA, data[1]);
3712 6 : data[0] = 0xCC;
3713 6 : data[1] = 0x11;
3714 : result = CompileRun("u8[0] + u8[1]");
3715 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3716 6 : }
3717 :
3718 :
3719 26645 : THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3720 6 : LocalContext env;
3721 6 : v8::Isolate* isolate = env->GetIsolate();
3722 12 : v8::HandleScope handle_scope(isolate);
3723 :
3724 :
3725 : v8::Local<v8::Value> result = CompileRun(
3726 : "var ab1 = new ArrayBuffer(2);"
3727 : "var u8_a = new Uint8Array(ab1);"
3728 : "u8_a[0] = 0xAA;"
3729 : "u8_a[1] = 0xFF; u8_a.buffer");
3730 : Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3731 6 : CheckInternalFieldsAreZero(ab1);
3732 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3733 6 : CHECK(!ab1->IsExternal());
3734 12 : ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3735 6 : CHECK(ab1->IsExternal());
3736 :
3737 : result = CompileRun("ab1.byteLength");
3738 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3739 : result = CompileRun("u8_a[0]");
3740 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3741 : result = CompileRun("u8_a[1]");
3742 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3743 : result = CompileRun(
3744 : "var u8_b = new Uint8Array(ab1);"
3745 : "u8_b[0] = 0xBB;"
3746 : "u8_a[0]");
3747 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3748 : result = CompileRun("u8_b[1]");
3749 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3750 :
3751 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3752 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3753 12 : CHECK_EQ(0xBB, ab1_data[0]);
3754 12 : CHECK_EQ(0xFF, ab1_data[1]);
3755 6 : ab1_data[0] = 0xCC;
3756 6 : ab1_data[1] = 0x11;
3757 : result = CompileRun("u8_a[0] + u8_a[1]");
3758 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3759 6 : }
3760 :
3761 :
3762 26645 : THREADED_TEST(ArrayBuffer_External) {
3763 6 : LocalContext env;
3764 6 : v8::Isolate* isolate = env->GetIsolate();
3765 12 : v8::HandleScope handle_scope(isolate);
3766 :
3767 : i::ScopedVector<uint8_t> my_data(100);
3768 : memset(my_data.start(), 0, 100);
3769 : Local<v8::ArrayBuffer> ab3 =
3770 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3771 6 : CheckInternalFieldsAreZero(ab3);
3772 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3773 6 : CHECK(ab3->IsExternal());
3774 :
3775 24 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3776 :
3777 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3778 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3779 :
3780 : result = CompileRun(
3781 : "var u8_b = new Uint8Array(ab3);"
3782 : "u8_b[0] = 0xBB;"
3783 : "u8_b[1] = 0xCC;"
3784 : "u8_b.length");
3785 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3786 12 : CHECK_EQ(0xBB, my_data[0]);
3787 12 : CHECK_EQ(0xCC, my_data[1]);
3788 6 : my_data[0] = 0xCC;
3789 6 : my_data[1] = 0x11;
3790 : result = CompileRun("u8_b[0] + u8_b[1]");
3791 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3792 6 : }
3793 :
3794 26645 : THREADED_TEST(ArrayBuffer_DisableDetach) {
3795 6 : LocalContext env;
3796 6 : v8::Isolate* isolate = env->GetIsolate();
3797 12 : v8::HandleScope handle_scope(isolate);
3798 :
3799 : i::ScopedVector<uint8_t> my_data(100);
3800 : memset(my_data.start(), 0, 100);
3801 : Local<v8::ArrayBuffer> ab =
3802 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3803 6 : CHECK(ab->IsDetachable());
3804 :
3805 : i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3806 : buf->set_is_detachable(false);
3807 :
3808 6 : CHECK(!ab->IsDetachable());
3809 6 : }
3810 :
3811 12 : static void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
3812 12 : CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3813 12 : CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3814 12 : }
3815 :
3816 108 : static void CheckIsDetached(v8::Local<v8::TypedArray> ta) {
3817 108 : CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3818 108 : CHECK_EQ(0, static_cast<int>(ta->Length()));
3819 108 : CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3820 108 : }
3821 :
3822 54 : static void CheckIsTypedArrayVarDetached(const char* name) {
3823 : i::ScopedVector<char> source(1024);
3824 : i::SNPrintF(source,
3825 : "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3826 54 : name, name, name);
3827 54 : CHECK(CompileRun(source.start())->IsTrue());
3828 : v8::Local<v8::TypedArray> ta =
3829 54 : v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3830 54 : CheckIsDetached(ta);
3831 54 : }
3832 :
3833 : template <typename TypedArray, int kElementSize>
3834 54 : static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3835 : int byteOffset, int length) {
3836 54 : v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3837 54 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3838 54 : CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3839 54 : CHECK_EQ(length, static_cast<int>(ta->Length()));
3840 54 : CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3841 54 : return ta;
3842 : }
3843 :
3844 26645 : THREADED_TEST(ArrayBuffer_DetachingApi) {
3845 6 : LocalContext env;
3846 6 : v8::Isolate* isolate = env->GetIsolate();
3847 12 : v8::HandleScope handle_scope(isolate);
3848 :
3849 6 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3850 :
3851 : v8::Local<v8::Uint8Array> u8a =
3852 6 : CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3853 : v8::Local<v8::Uint8ClampedArray> u8c =
3854 6 : CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3855 : v8::Local<v8::Int8Array> i8a =
3856 6 : CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3857 :
3858 : v8::Local<v8::Uint16Array> u16a =
3859 6 : CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3860 : v8::Local<v8::Int16Array> i16a =
3861 6 : CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3862 :
3863 : v8::Local<v8::Uint32Array> u32a =
3864 6 : CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3865 : v8::Local<v8::Int32Array> i32a =
3866 6 : CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3867 :
3868 : v8::Local<v8::Float32Array> f32a =
3869 6 : CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3870 : v8::Local<v8::Float64Array> f64a =
3871 6 : CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3872 :
3873 6 : v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3874 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3875 6 : CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3876 6 : CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3877 :
3878 12 : ScopedArrayBufferContents contents(buffer->Externalize());
3879 6 : buffer->Detach();
3880 6 : CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3881 6 : CheckIsDetached(u8a);
3882 6 : CheckIsDetached(u8c);
3883 6 : CheckIsDetached(i8a);
3884 6 : CheckIsDetached(u16a);
3885 6 : CheckIsDetached(i16a);
3886 6 : CheckIsDetached(u32a);
3887 6 : CheckIsDetached(i32a);
3888 6 : CheckIsDetached(f32a);
3889 6 : CheckIsDetached(f64a);
3890 6 : CheckDataViewIsDetached(dv);
3891 6 : }
3892 :
3893 26645 : THREADED_TEST(ArrayBuffer_DetachingScript) {
3894 6 : LocalContext env;
3895 6 : v8::Isolate* isolate = env->GetIsolate();
3896 12 : v8::HandleScope handle_scope(isolate);
3897 :
3898 : CompileRun(
3899 : "var ab = new ArrayBuffer(1024);"
3900 : "var u8a = new Uint8Array(ab, 1, 1023);"
3901 : "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3902 : "var i8a = new Int8Array(ab, 1, 1023);"
3903 : "var u16a = new Uint16Array(ab, 2, 511);"
3904 : "var i16a = new Int16Array(ab, 2, 511);"
3905 : "var u32a = new Uint32Array(ab, 4, 255);"
3906 : "var i32a = new Int32Array(ab, 4, 255);"
3907 : "var f32a = new Float32Array(ab, 4, 255);"
3908 : "var f64a = new Float64Array(ab, 8, 127);"
3909 : "var dv = new DataView(ab, 1, 1023);");
3910 :
3911 : v8::Local<v8::ArrayBuffer> ab =
3912 : Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3913 :
3914 6 : v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3915 :
3916 12 : ScopedArrayBufferContents contents(ab->Externalize());
3917 6 : ab->Detach();
3918 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3919 6 : CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3920 :
3921 6 : CheckIsTypedArrayVarDetached("u8a");
3922 6 : CheckIsTypedArrayVarDetached("u8c");
3923 6 : CheckIsTypedArrayVarDetached("i8a");
3924 6 : CheckIsTypedArrayVarDetached("u16a");
3925 6 : CheckIsTypedArrayVarDetached("i16a");
3926 6 : CheckIsTypedArrayVarDetached("u32a");
3927 6 : CheckIsTypedArrayVarDetached("i32a");
3928 6 : CheckIsTypedArrayVarDetached("f32a");
3929 6 : CheckIsTypedArrayVarDetached("f64a");
3930 :
3931 6 : CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3932 6 : CheckDataViewIsDetached(dv);
3933 6 : }
3934 :
3935 26645 : THREADED_TEST(ArrayBuffer_AllocationInformation) {
3936 6 : LocalContext env;
3937 6 : v8::Isolate* isolate = env->GetIsolate();
3938 12 : v8::HandleScope handle_scope(isolate);
3939 :
3940 : const size_t ab_size = 1024;
3941 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
3942 12 : ScopedArrayBufferContents contents(ab->Externalize());
3943 :
3944 : // Array buffers should have normal allocation mode.
3945 6 : CHECK_EQ(contents.AllocationMode(),
3946 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
3947 : // The allocation must contain the buffer (normally they will be equal, but
3948 : // this is not required by the contract).
3949 6 : CHECK_NOT_NULL(contents.AllocationBase());
3950 : const uintptr_t alloc =
3951 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
3952 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
3953 6 : CHECK_LE(alloc, data);
3954 6 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
3955 6 : }
3956 :
3957 26645 : THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
3958 6 : LocalContext env;
3959 6 : v8::Isolate* isolate = env->GetIsolate();
3960 12 : v8::HandleScope handle_scope(isolate);
3961 :
3962 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 0);
3963 6 : CheckInternalFieldsAreZero(ab);
3964 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3965 6 : CHECK(!ab->IsExternal());
3966 :
3967 : // Externalize the buffer (taking ownership of the backing store memory).
3968 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3969 :
3970 6 : Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0);
3971 : // Calling Buffer() will materialize the ArrayBuffer (transitioning it from
3972 : // on-heap to off-heap if need be). This should not affect whether it is
3973 : // marked as is_external or not.
3974 6 : USE(u8a->Buffer());
3975 :
3976 6 : CHECK(ab->IsExternal());
3977 6 : }
3978 :
3979 : class ScopedSharedArrayBufferContents {
3980 : public:
3981 : explicit ScopedSharedArrayBufferContents(
3982 : const v8::SharedArrayBuffer::Contents& contents)
3983 18 : : contents_(contents) {}
3984 18 : ~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
3985 : void* Data() const { return contents_.Data(); }
3986 : size_t ByteLength() const { return contents_.ByteLength(); }
3987 :
3988 : void* AllocationBase() const { return contents_.AllocationBase(); }
3989 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3990 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3991 : return contents_.AllocationMode();
3992 : }
3993 :
3994 : private:
3995 : const v8::SharedArrayBuffer::Contents contents_;
3996 : };
3997 :
3998 :
3999 26645 : THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
4000 6 : i::FLAG_harmony_sharedarraybuffer = true;
4001 6 : LocalContext env;
4002 6 : v8::Isolate* isolate = env->GetIsolate();
4003 12 : v8::HandleScope handle_scope(isolate);
4004 :
4005 6 : Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
4006 6 : CheckInternalFieldsAreZero(ab);
4007 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
4008 6 : CHECK(!ab->IsExternal());
4009 6 : CcTest::CollectAllGarbage();
4010 :
4011 12 : ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
4012 6 : CHECK(ab->IsExternal());
4013 :
4014 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
4015 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
4016 6 : CHECK_NOT_NULL(data);
4017 24 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
4018 :
4019 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
4020 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4021 :
4022 : result = CompileRun(
4023 : "var u8 = new Uint8Array(ab);"
4024 : "u8[0] = 0xFF;"
4025 : "u8[1] = 0xAA;"
4026 : "u8.length");
4027 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4028 12 : CHECK_EQ(0xFF, data[0]);
4029 12 : CHECK_EQ(0xAA, data[1]);
4030 6 : data[0] = 0xCC;
4031 6 : data[1] = 0x11;
4032 : result = CompileRun("u8[0] + u8[1]");
4033 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4034 6 : }
4035 :
4036 :
4037 26645 : THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
4038 6 : i::FLAG_harmony_sharedarraybuffer = true;
4039 6 : LocalContext env;
4040 6 : v8::Isolate* isolate = env->GetIsolate();
4041 12 : v8::HandleScope handle_scope(isolate);
4042 :
4043 :
4044 : v8::Local<v8::Value> result = CompileRun(
4045 : "var ab1 = new SharedArrayBuffer(2);"
4046 : "var u8_a = new Uint8Array(ab1);"
4047 : "u8_a[0] = 0xAA;"
4048 : "u8_a[1] = 0xFF; u8_a.buffer");
4049 : Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
4050 6 : CheckInternalFieldsAreZero(ab1);
4051 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
4052 6 : CHECK(!ab1->IsExternal());
4053 12 : ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
4054 6 : CHECK(ab1->IsExternal());
4055 :
4056 : result = CompileRun("ab1.byteLength");
4057 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
4058 : result = CompileRun("u8_a[0]");
4059 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
4060 : result = CompileRun("u8_a[1]");
4061 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4062 : result = CompileRun(
4063 : "var u8_b = new Uint8Array(ab1);"
4064 : "u8_b[0] = 0xBB;"
4065 : "u8_a[0]");
4066 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
4067 : result = CompileRun("u8_b[1]");
4068 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4069 :
4070 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
4071 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
4072 12 : CHECK_EQ(0xBB, ab1_data[0]);
4073 12 : CHECK_EQ(0xFF, ab1_data[1]);
4074 6 : ab1_data[0] = 0xCC;
4075 6 : ab1_data[1] = 0x11;
4076 : result = CompileRun("u8_a[0] + u8_a[1]");
4077 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4078 6 : }
4079 :
4080 :
4081 26645 : THREADED_TEST(SharedArrayBuffer_External) {
4082 6 : i::FLAG_harmony_sharedarraybuffer = true;
4083 6 : LocalContext env;
4084 6 : v8::Isolate* isolate = env->GetIsolate();
4085 12 : v8::HandleScope handle_scope(isolate);
4086 :
4087 : i::ScopedVector<uint8_t> my_data(100);
4088 : memset(my_data.start(), 0, 100);
4089 : Local<v8::SharedArrayBuffer> ab3 =
4090 6 : v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
4091 6 : CheckInternalFieldsAreZero(ab3);
4092 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
4093 6 : CHECK(ab3->IsExternal());
4094 :
4095 24 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
4096 :
4097 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
4098 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4099 :
4100 : result = CompileRun(
4101 : "var u8_b = new Uint8Array(ab3);"
4102 : "u8_b[0] = 0xBB;"
4103 : "u8_b[1] = 0xCC;"
4104 : "u8_b.length");
4105 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4106 12 : CHECK_EQ(0xBB, my_data[0]);
4107 12 : CHECK_EQ(0xCC, my_data[1]);
4108 6 : my_data[0] = 0xCC;
4109 6 : my_data[1] = 0x11;
4110 : result = CompileRun("u8_b[0] + u8_b[1]");
4111 12 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4112 6 : }
4113 :
4114 :
4115 26645 : THREADED_TEST(HiddenProperties) {
4116 6 : LocalContext env;
4117 6 : v8::Isolate* isolate = env->GetIsolate();
4118 12 : v8::HandleScope scope(isolate);
4119 :
4120 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4121 : v8::Local<v8::Private> key =
4122 6 : v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
4123 6 : v8::Local<v8::String> empty = v8_str("");
4124 6 : v8::Local<v8::String> prop_name = v8_str("prop_name");
4125 :
4126 6 : CcTest::CollectAllGarbage();
4127 :
4128 : // Make sure delete of a non-existent hidden value works
4129 12 : obj->DeletePrivate(env.local(), key).FromJust();
4130 :
4131 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
4132 : .FromJust());
4133 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
4134 : .ToLocalChecked()
4135 : ->Int32Value(env.local())
4136 : .FromJust());
4137 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4138 : .FromJust());
4139 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4140 : .ToLocalChecked()
4141 : ->Int32Value(env.local())
4142 : .FromJust());
4143 :
4144 6 : CcTest::CollectAllGarbage();
4145 :
4146 : // Make sure we do not find the hidden property.
4147 12 : CHECK(!obj->Has(env.local(), empty).FromJust());
4148 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4149 : .ToLocalChecked()
4150 : ->Int32Value(env.local())
4151 : .FromJust());
4152 12 : CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
4153 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4154 : .ToLocalChecked()
4155 : ->Int32Value(env.local())
4156 : .FromJust());
4157 18 : CHECK(
4158 : obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
4159 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4160 : .ToLocalChecked()
4161 : ->Int32Value(env.local())
4162 : .FromJust());
4163 18 : CHECK_EQ(2003, obj->Get(env.local(), empty)
4164 : .ToLocalChecked()
4165 : ->Int32Value(env.local())
4166 : .FromJust());
4167 :
4168 6 : CcTest::CollectAllGarbage();
4169 :
4170 : // Add another property and delete it afterwards to force the object in
4171 : // slow case.
4172 18 : CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
4173 : .FromJust());
4174 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4175 : .ToLocalChecked()
4176 : ->Int32Value(env.local())
4177 : .FromJust());
4178 18 : CHECK_EQ(2008, obj->Get(env.local(), prop_name)
4179 : .ToLocalChecked()
4180 : ->Int32Value(env.local())
4181 : .FromJust());
4182 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4183 : .ToLocalChecked()
4184 : ->Int32Value(env.local())
4185 : .FromJust());
4186 12 : CHECK(obj->Delete(env.local(), prop_name).FromJust());
4187 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4188 : .ToLocalChecked()
4189 : ->Int32Value(env.local())
4190 : .FromJust());
4191 :
4192 6 : CcTest::CollectAllGarbage();
4193 :
4194 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4195 : .FromJust());
4196 12 : CHECK(obj->DeletePrivate(env.local(), key).FromJust());
4197 12 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4198 6 : }
4199 :
4200 :
4201 26645 : THREADED_TEST(Regress97784) {
4202 : // Regression test for crbug.com/97784
4203 : // Messing with the Object.prototype should not have effect on
4204 : // hidden properties.
4205 6 : LocalContext env;
4206 12 : v8::HandleScope scope(env->GetIsolate());
4207 :
4208 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4209 : v8::Local<v8::Private> key =
4210 12 : v8::Private::New(env->GetIsolate(), v8_str("hidden"));
4211 :
4212 : CompileRun(
4213 : "set_called = false;"
4214 : "Object.defineProperty("
4215 : " Object.prototype,"
4216 : " 'hidden',"
4217 : " {get: function() { return 45; },"
4218 : " set: function() { set_called = true; }})");
4219 :
4220 12 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4221 : // Make sure that the getter and setter from Object.prototype is not invoked.
4222 : // If it did we would have full access to the hidden properties in
4223 : // the accessor.
4224 18 : CHECK(
4225 : obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
4226 : .FromJust());
4227 : ExpectFalse("set_called");
4228 18 : CHECK_EQ(42, obj->GetPrivate(env.local(), key)
4229 : .ToLocalChecked()
4230 : ->Int32Value(env.local())
4231 : .FromJust());
4232 6 : }
4233 :
4234 :
4235 26645 : THREADED_TEST(External) {
4236 12 : v8::HandleScope scope(CcTest::isolate());
4237 6 : int x = 3;
4238 6 : Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
4239 6 : LocalContext env;
4240 24 : CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
4241 : Local<Value> reext_obj = CompileRun("this.ext");
4242 : v8::Local<v8::External> reext = reext_obj.As<v8::External>();
4243 6 : int* ptr = static_cast<int*>(reext->Value());
4244 6 : CHECK_EQ(3, x);
4245 6 : *ptr = 10;
4246 6 : CHECK_EQ(x, 10);
4247 :
4248 : {
4249 : i::Handle<i::Object> obj = v8::Utils::OpenHandle(*ext);
4250 12 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4251 6 : CHECK(ext->IsExternal());
4252 6 : CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty());
4253 12 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4254 6 : CHECK(ext->IsExternal());
4255 : }
4256 :
4257 : // Make sure unaligned pointers are wrapped properly.
4258 6 : char* data = i::StrDup("0123456789");
4259 6 : Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
4260 6 : Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
4261 6 : Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
4262 6 : Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
4263 :
4264 6 : char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
4265 6 : CHECK_EQ('0', *char_ptr);
4266 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
4267 6 : CHECK_EQ('1', *char_ptr);
4268 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
4269 6 : CHECK_EQ('2', *char_ptr);
4270 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
4271 6 : CHECK_EQ('3', *char_ptr);
4272 : i::DeleteArray(data);
4273 6 : }
4274 :
4275 :
4276 26645 : THREADED_TEST(GlobalHandle) {
4277 6 : v8::Isolate* isolate = CcTest::isolate();
4278 : v8::Persistent<String> global;
4279 : {
4280 12 : v8::HandleScope scope(isolate);
4281 12 : global.Reset(isolate, v8_str("str"));
4282 : }
4283 : {
4284 12 : v8::HandleScope scope(isolate);
4285 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4286 : }
4287 : global.Reset();
4288 : {
4289 12 : v8::HandleScope scope(isolate);
4290 12 : global.Reset(isolate, v8_str("str"));
4291 : }
4292 : {
4293 12 : v8::HandleScope scope(isolate);
4294 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4295 : }
4296 : global.Reset();
4297 6 : }
4298 :
4299 :
4300 26645 : THREADED_TEST(ResettingGlobalHandle) {
4301 6 : v8::Isolate* isolate = CcTest::isolate();
4302 : v8::Persistent<String> global;
4303 : {
4304 12 : v8::HandleScope scope(isolate);
4305 12 : global.Reset(isolate, v8_str("str"));
4306 : }
4307 : v8::internal::GlobalHandles* global_handles =
4308 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4309 : size_t initial_handle_count = global_handles->handles_count();
4310 : {
4311 12 : v8::HandleScope scope(isolate);
4312 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4313 : }
4314 : {
4315 12 : v8::HandleScope scope(isolate);
4316 12 : global.Reset(isolate, v8_str("longer"));
4317 : }
4318 6 : CHECK_EQ(global_handles->handles_count(), initial_handle_count);
4319 : {
4320 12 : v8::HandleScope scope(isolate);
4321 6 : CHECK_EQ(6, v8::Local<String>::New(isolate, global)->Length());
4322 : }
4323 : global.Reset();
4324 6 : CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4325 6 : }
4326 :
4327 :
4328 26645 : THREADED_TEST(ResettingGlobalHandleToEmpty) {
4329 6 : v8::Isolate* isolate = CcTest::isolate();
4330 : v8::Persistent<String> global;
4331 : {
4332 12 : v8::HandleScope scope(isolate);
4333 12 : global.Reset(isolate, v8_str("str"));
4334 : }
4335 : v8::internal::GlobalHandles* global_handles =
4336 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4337 : size_t initial_handle_count = global_handles->handles_count();
4338 : {
4339 12 : v8::HandleScope scope(isolate);
4340 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4341 : }
4342 : {
4343 12 : v8::HandleScope scope(isolate);
4344 : Local<String> empty;
4345 : global.Reset(isolate, empty);
4346 : }
4347 6 : CHECK(global.IsEmpty());
4348 6 : CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4349 6 : }
4350 :
4351 :
4352 : template <class T>
4353 : static v8::Global<T> PassUnique(v8::Global<T> unique) {
4354 : return unique.Pass();
4355 : }
4356 :
4357 :
4358 : template <class T>
4359 6 : static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
4360 : const v8::Persistent<T>& global) {
4361 : v8::Global<String> unique(isolate, global);
4362 6 : return unique.Pass();
4363 : }
4364 :
4365 :
4366 26645 : THREADED_TEST(Global) {
4367 6 : v8::Isolate* isolate = CcTest::isolate();
4368 : v8::Persistent<String> global;
4369 : {
4370 12 : v8::HandleScope scope(isolate);
4371 12 : global.Reset(isolate, v8_str("str"));
4372 : }
4373 : v8::internal::GlobalHandles* global_handles =
4374 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4375 : size_t initial_handle_count = global_handles->handles_count();
4376 : {
4377 : v8::Global<String> unique(isolate, global);
4378 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4379 : // Test assignment via Pass
4380 : {
4381 : v8::Global<String> copy = unique.Pass();
4382 6 : CHECK(unique.IsEmpty());
4383 6 : CHECK(copy == global);
4384 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4385 6 : unique = copy.Pass();
4386 : }
4387 : // Test ctor via Pass
4388 : {
4389 : v8::Global<String> copy(unique.Pass());
4390 6 : CHECK(unique.IsEmpty());
4391 6 : CHECK(copy == global);
4392 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4393 6 : unique = copy.Pass();
4394 : }
4395 : // Test pass through function call
4396 : {
4397 6 : v8::Global<String> copy = PassUnique(unique.Pass());
4398 6 : CHECK(unique.IsEmpty());
4399 6 : CHECK(copy == global);
4400 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4401 6 : unique = copy.Pass();
4402 : }
4403 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4404 : }
4405 : // Test pass from function call
4406 : {
4407 6 : v8::Global<String> unique = ReturnUnique(isolate, global);
4408 6 : CHECK(unique == global);
4409 6 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4410 : }
4411 6 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4412 : global.Reset();
4413 6 : }
4414 :
4415 :
4416 : namespace {
4417 :
4418 : class TwoPassCallbackData;
4419 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4420 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4421 :
4422 :
4423 : class TwoPassCallbackData {
4424 : public:
4425 215 : TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4426 : : first_pass_called_(false),
4427 : second_pass_called_(false),
4428 : trigger_gc_(false),
4429 430 : instance_counter_(instance_counter) {
4430 430 : HandleScope scope(isolate);
4431 : i::ScopedVector<char> buffer(40);
4432 215 : i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4433 : auto string =
4434 215 : v8::String::NewFromUtf8(isolate, buffer.start(),
4435 : v8::NewStringType::kNormal).ToLocalChecked();
4436 : cell_.Reset(isolate, string);
4437 215 : (*instance_counter_)++;
4438 215 : }
4439 :
4440 430 : ~TwoPassCallbackData() {
4441 215 : CHECK(first_pass_called_);
4442 215 : CHECK(second_pass_called_);
4443 215 : CHECK(cell_.IsEmpty());
4444 215 : (*instance_counter_)--;
4445 215 : }
4446 :
4447 215 : void FirstPass() {
4448 215 : CHECK(!first_pass_called_);
4449 215 : CHECK(!second_pass_called_);
4450 215 : CHECK(!cell_.IsEmpty());
4451 : cell_.Reset();
4452 215 : first_pass_called_ = true;
4453 215 : }
4454 :
4455 215 : void SecondPass() {
4456 215 : CHECK(first_pass_called_);
4457 215 : CHECK(!second_pass_called_);
4458 215 : CHECK(cell_.IsEmpty());
4459 215 : second_pass_called_ = true;
4460 215 : delete this;
4461 215 : }
4462 :
4463 : void SetWeak() {
4464 : cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4465 : }
4466 :
4467 15 : void MarkTriggerGc() { trigger_gc_ = true; }
4468 : bool trigger_gc() { return trigger_gc_; }
4469 :
4470 : int* instance_counter() { return instance_counter_; }
4471 :
4472 : private:
4473 : bool first_pass_called_;
4474 : bool second_pass_called_;
4475 : bool trigger_gc_;
4476 : v8::Global<v8::String> cell_;
4477 : int* instance_counter_;
4478 : };
4479 :
4480 :
4481 215 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4482 215 : ApiTestFuzzer::Fuzz();
4483 : bool trigger_gc = data.GetParameter()->trigger_gc();
4484 : int* instance_counter = data.GetParameter()->instance_counter();
4485 215 : data.GetParameter()->SecondPass();
4486 215 : if (!trigger_gc) return;
4487 15 : auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4488 : data_2->SetWeak();
4489 15 : CcTest::CollectAllGarbage();
4490 : }
4491 :
4492 :
4493 215 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4494 215 : data.GetParameter()->FirstPass();
4495 : data.SetSecondPassCallback(SecondPassCallback);
4496 215 : }
4497 :
4498 : } // namespace
4499 :
4500 :
4501 26644 : TEST(TwoPassPhantomCallbacks) {
4502 5 : auto isolate = CcTest::isolate();
4503 : const size_t kLength = 20;
4504 5 : int instance_counter = 0;
4505 205 : for (size_t i = 0; i < kLength; ++i) {
4506 100 : auto data = new TwoPassCallbackData(isolate, &instance_counter);
4507 : data->SetWeak();
4508 : }
4509 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4510 5 : CcTest::CollectAllGarbage();
4511 5 : EmptyMessageQueues(isolate);
4512 5 : CHECK_EQ(0, instance_counter);
4513 5 : }
4514 :
4515 :
4516 26644 : TEST(TwoPassPhantomCallbacksNestedGc) {
4517 5 : auto isolate = CcTest::isolate();
4518 : const size_t kLength = 20;
4519 : TwoPassCallbackData* array[kLength];
4520 5 : int instance_counter = 0;
4521 205 : for (size_t i = 0; i < kLength; ++i) {
4522 100 : array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4523 : array[i]->SetWeak();
4524 : }
4525 5 : array[5]->MarkTriggerGc();
4526 5 : array[10]->MarkTriggerGc();
4527 5 : array[15]->MarkTriggerGc();
4528 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4529 5 : CcTest::CollectAllGarbage();
4530 5 : EmptyMessageQueues(isolate);
4531 5 : CHECK_EQ(0, instance_counter);
4532 5 : }
4533 :
4534 :
4535 : namespace {
4536 :
4537 30 : void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4538 :
4539 :
4540 20 : Local<v8::Object> NewObjectForIntKey(
4541 : v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4542 : int key) {
4543 : auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4544 20 : auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4545 20 : obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4546 20 : return obj;
4547 : }
4548 :
4549 :
4550 : template <typename K, typename V>
4551 : class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4552 : public:
4553 : typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4554 : static const v8::PersistentContainerCallbackType kCallbackType =
4555 : v8::kWeakWithInternalFields;
4556 : struct WeakCallbackDataType {
4557 : MapType* map;
4558 : K key;
4559 : };
4560 : static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4561 : Local<V> value) {
4562 25 : WeakCallbackDataType* data = new WeakCallbackDataType;
4563 25 : data->map = map;
4564 25 : data->key = key;
4565 : return data;
4566 : }
4567 : static MapType* MapFromWeakCallbackInfo(
4568 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4569 5 : return data.GetParameter()->map;
4570 : }
4571 : static K KeyFromWeakCallbackInfo(
4572 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4573 10 : return data.GetParameter()->key;
4574 : }
4575 25 : static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
4576 5 : static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4577 5 : CHECK_EQ(IntKeyToVoidPointer(key),
4578 : v8::Object::GetAlignedPointerFromInternalField(value, 0));
4579 5 : }
4580 : static void OnWeakCallback(
4581 : const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
4582 5 : static void DisposeWeak(
4583 : const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4584 : K key = KeyFromWeakCallbackInfo(info);
4585 5 : CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4586 : DisposeCallbackData(info.GetParameter());
4587 5 : }
4588 : };
4589 :
4590 :
4591 : template <typename Map>
4592 10 : void TestGlobalValueMap() {
4593 10 : LocalContext env;
4594 10 : v8::Isolate* isolate = env->GetIsolate();
4595 : v8::Global<ObjectTemplate> templ;
4596 : {
4597 20 : HandleScope scope(isolate);
4598 10 : auto t = ObjectTemplate::New(isolate);
4599 10 : t->SetInternalFieldCount(1);
4600 : templ.Reset(isolate, t);
4601 : }
4602 : Map map(isolate);
4603 : v8::internal::GlobalHandles* global_handles =
4604 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4605 : size_t initial_handle_count = global_handles->handles_count();
4606 : CHECK_EQ(0, static_cast<int>(map.Size()));
4607 : {
4608 20 : HandleScope scope(isolate);
4609 10 : Local<v8::Object> obj = map.Get(7);
4610 10 : CHECK(obj.IsEmpty());
4611 10 : Local<v8::Object> expected = v8::Object::New(isolate);
4612 20 : map.Set(7, expected);
4613 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4614 10 : obj = map.Get(7);
4615 20 : CHECK(expected->Equals(env.local(), obj).FromJust());
4616 : {
4617 : typename Map::PersistentValueReference ref = map.GetReference(7);
4618 20 : CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4619 : }
4620 10 : v8::Global<v8::Object> removed = map.Remove(7);
4621 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4622 10 : CHECK(expected == removed);
4623 20 : removed = map.Remove(7);
4624 10 : CHECK(removed.IsEmpty());
4625 20 : map.Set(8, expected);
4626 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4627 20 : map.Set(8, expected);
4628 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4629 : {
4630 : typename Map::PersistentValueReference ref;
4631 10 : Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4632 30 : removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4633 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4634 10 : CHECK(expected == removed);
4635 20 : CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4636 : }
4637 : }
4638 10 : CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4639 : if (map.IsWeak()) {
4640 5 : CcTest::PreciseCollectAllGarbage();
4641 : } else {
4642 5 : map.Clear();
4643 : }
4644 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4645 10 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4646 : {
4647 20 : HandleScope scope(isolate);
4648 10 : Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4649 20 : map.Set(9, value);
4650 10 : map.Clear();
4651 : }
4652 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4653 10 : CHECK_EQ(initial_handle_count, global_handles->handles_count());
4654 10 : }
4655 :
4656 : } // namespace
4657 :
4658 :
4659 26644 : TEST(GlobalValueMap) {
4660 : // Default case, w/o weak callbacks:
4661 5 : TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4662 :
4663 : // Custom traits with weak callbacks:
4664 : typedef v8::GlobalValueMap<int, v8::Object,
4665 : PhantomStdMapTraits<int, v8::Object>> WeakMap;
4666 5 : TestGlobalValueMap<WeakMap>();
4667 5 : }
4668 :
4669 :
4670 26644 : TEST(PersistentValueVector) {
4671 5 : LocalContext env;
4672 5 : v8::Isolate* isolate = env->GetIsolate();
4673 : v8::internal::GlobalHandles* global_handles =
4674 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4675 : size_t handle_count = global_handles->handles_count();
4676 10 : HandleScope scope(isolate);
4677 :
4678 5 : v8::PersistentValueVector<v8::Object> vector(isolate);
4679 :
4680 5 : Local<v8::Object> obj1 = v8::Object::New(isolate);
4681 5 : Local<v8::Object> obj2 = v8::Object::New(isolate);
4682 5 : v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4683 :
4684 5 : CHECK(vector.IsEmpty());
4685 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4686 :
4687 : vector.ReserveCapacity(3);
4688 5 : CHECK(vector.IsEmpty());
4689 :
4690 5 : vector.Append(obj1);
4691 5 : vector.Append(obj2);
4692 5 : vector.Append(obj1);
4693 5 : vector.Append(obj3.Pass());
4694 5 : vector.Append(obj1);
4695 :
4696 5 : CHECK(!vector.IsEmpty());
4697 5 : CHECK_EQ(5, static_cast<int>(vector.Size()));
4698 5 : CHECK(obj3.IsEmpty());
4699 15 : CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4700 15 : CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4701 15 : CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4702 15 : CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4703 :
4704 5 : CHECK_EQ(5 + handle_count, global_handles->handles_count());
4705 :
4706 5 : vector.Clear();
4707 5 : CHECK(vector.IsEmpty());
4708 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4709 5 : CHECK_EQ(handle_count, global_handles->handles_count());
4710 5 : }
4711 :
4712 :
4713 26645 : THREADED_TEST(GlobalHandleUpcast) {
4714 6 : v8::Isolate* isolate = CcTest::isolate();
4715 12 : v8::HandleScope scope(isolate);
4716 6 : v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4717 : v8::Persistent<String> global_string(isolate, local);
4718 : v8::Persistent<Value>& global_value =
4719 : v8::Persistent<Value>::Cast(global_string);
4720 6 : CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4721 6 : CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4722 : global_string.Reset();
4723 6 : }
4724 :
4725 :
4726 26645 : THREADED_TEST(HandleEquality) {
4727 6 : v8::Isolate* isolate = CcTest::isolate();
4728 : v8::Persistent<String> global1;
4729 : v8::Persistent<String> global2;
4730 : {
4731 12 : v8::HandleScope scope(isolate);
4732 12 : global1.Reset(isolate, v8_str("str"));
4733 12 : global2.Reset(isolate, v8_str("str2"));
4734 : }
4735 6 : CHECK(global1 == global1);
4736 6 : CHECK(!(global1 != global1));
4737 : {
4738 12 : v8::HandleScope scope(isolate);
4739 : Local<String> local1 = Local<String>::New(isolate, global1);
4740 : Local<String> local2 = Local<String>::New(isolate, global2);
4741 :
4742 6 : CHECK(global1 == local1);
4743 6 : CHECK(!(global1 != local1));
4744 6 : CHECK(local1 == global1);
4745 6 : CHECK(!(local1 != global1));
4746 :
4747 6 : CHECK(!(global1 == local2));
4748 6 : CHECK(global1 != local2);
4749 6 : CHECK(!(local2 == global1));
4750 6 : CHECK(local2 != global1);
4751 :
4752 6 : CHECK(!(local1 == local2));
4753 6 : CHECK(local1 != local2);
4754 :
4755 : Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4756 6 : CHECK(local1 == anotherLocal1);
4757 6 : CHECK(!(local1 != anotherLocal1));
4758 : }
4759 : global1.Reset();
4760 : global2.Reset();
4761 6 : }
4762 :
4763 :
4764 26645 : THREADED_TEST(LocalHandle) {
4765 12 : v8::HandleScope scope(CcTest::isolate());
4766 : v8::Local<String> local =
4767 6 : v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4768 6 : CHECK_EQ(3, local->Length());
4769 6 : }
4770 :
4771 :
4772 : class WeakCallCounter {
4773 : public:
4774 5 : explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
4775 : int id() { return id_; }
4776 10 : void increment() { number_of_weak_calls_++; }
4777 : int NumberOfWeakCalls() { return number_of_weak_calls_; }
4778 :
4779 : private:
4780 : int id_;
4781 : int number_of_weak_calls_;
4782 : };
4783 :
4784 :
4785 : template <typename T>
4786 10 : struct WeakCallCounterAndPersistent {
4787 : explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4788 10 : : counter(counter) {}
4789 : WeakCallCounter* counter;
4790 : v8::Persistent<T> handle;
4791 : };
4792 :
4793 :
4794 : template <typename T>
4795 10 : static void WeakPointerCallback(
4796 : const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4797 10 : CHECK_EQ(1234, data.GetParameter()->counter->id());
4798 : data.GetParameter()->counter->increment();
4799 : data.GetParameter()->handle.Reset();
4800 10 : }
4801 :
4802 26645 : THREADED_TEST(ScriptException) {
4803 6 : LocalContext env;
4804 12 : v8::HandleScope scope(env->GetIsolate());
4805 : Local<Script> script = v8_compile("throw 'panama!';");
4806 12 : v8::TryCatch try_catch(env->GetIsolate());
4807 6 : v8::MaybeLocal<Value> result = script->Run(env.local());
4808 6 : CHECK(result.IsEmpty());
4809 6 : CHECK(try_catch.HasCaught());
4810 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
4811 6 : CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4812 6 : }
4813 :
4814 :
4815 26644 : TEST(TryCatchCustomException) {
4816 5 : LocalContext env;
4817 5 : v8::Isolate* isolate = env->GetIsolate();
4818 10 : v8::HandleScope scope(isolate);
4819 10 : v8::TryCatch try_catch(isolate);
4820 : CompileRun(
4821 : "function CustomError() { this.a = 'b'; }"
4822 : "(function f() { throw new CustomError(); })();");
4823 5 : CHECK(try_catch.HasCaught());
4824 35 : CHECK(try_catch.Exception()
4825 : ->ToObject(env.local())
4826 : .ToLocalChecked()
4827 : ->Get(env.local(), v8_str("a"))
4828 : .ToLocalChecked()
4829 : ->Equals(env.local(), v8_str("b"))
4830 : .FromJust());
4831 5 : }
4832 :
4833 :
4834 : bool message_received;
4835 :
4836 :
4837 6 : static void check_message_0(v8::Local<v8::Message> message,
4838 : v8::Local<Value> data) {
4839 18 : CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4840 : .FromJust());
4841 18 : CHECK_EQ(6.75, message->GetScriptOrigin()
4842 : .ResourceName()
4843 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4844 : .FromJust());
4845 6 : CHECK(!message->IsSharedCrossOrigin());
4846 6 : message_received = true;
4847 6 : }
4848 :
4849 :
4850 26645 : THREADED_TEST(MessageHandler0) {
4851 6 : message_received = false;
4852 12 : v8::HandleScope scope(CcTest::isolate());
4853 6 : CHECK(!message_received);
4854 6 : LocalContext context;
4855 6 : CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4856 : v8::Local<v8::Script> script =
4857 6 : CompileWithOrigin("throw 'error'", "6.75", false);
4858 12 : CHECK(script->Run(context.local()).IsEmpty());
4859 6 : CHECK(message_received);
4860 : // clear out the message listener
4861 6 : CcTest::isolate()->RemoveMessageListeners(check_message_0);
4862 6 : }
4863 :
4864 :
4865 5 : static void check_message_1(v8::Local<v8::Message> message,
4866 : v8::Local<Value> data) {
4867 5 : CHECK(data->IsNumber());
4868 10 : CHECK_EQ(1337,
4869 : data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4870 5 : CHECK(!message->IsSharedCrossOrigin());
4871 5 : message_received = true;
4872 5 : }
4873 :
4874 :
4875 26644 : TEST(MessageHandler1) {
4876 5 : message_received = false;
4877 10 : v8::HandleScope scope(CcTest::isolate());
4878 5 : CHECK(!message_received);
4879 5 : CcTest::isolate()->AddMessageListener(check_message_1);
4880 5 : LocalContext context;
4881 : CompileRun("throw 1337;");
4882 5 : CHECK(message_received);
4883 : // clear out the message listener
4884 5 : CcTest::isolate()->RemoveMessageListeners(check_message_1);
4885 5 : }
4886 :
4887 :
4888 5 : static void check_message_2(v8::Local<v8::Message> message,
4889 : v8::Local<Value> data) {
4890 5 : LocalContext context;
4891 5 : CHECK(data->IsObject());
4892 : v8::Local<v8::Value> hidden_property =
4893 : v8::Object::Cast(*data)
4894 5 : ->GetPrivate(
4895 : context.local(),
4896 5 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4897 5 : .ToLocalChecked();
4898 15 : CHECK(v8_str("hidden value")
4899 : ->Equals(context.local(), hidden_property)
4900 : .FromJust());
4901 5 : CHECK(!message->IsSharedCrossOrigin());
4902 5 : message_received = true;
4903 5 : }
4904 :
4905 :
4906 26644 : TEST(MessageHandler2) {
4907 5 : message_received = false;
4908 10 : v8::HandleScope scope(CcTest::isolate());
4909 5 : CHECK(!message_received);
4910 5 : CcTest::isolate()->AddMessageListener(check_message_2);
4911 5 : LocalContext context;
4912 5 : v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4913 : v8::Object::Cast(*error)
4914 10 : ->SetPrivate(context.local(),
4915 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4916 15 : v8_str("hidden value"))
4917 : .FromJust();
4918 20 : CHECK(context->Global()
4919 : ->Set(context.local(), v8_str("error"), error)
4920 : .FromJust());
4921 : CompileRun("throw error;");
4922 5 : CHECK(message_received);
4923 : // clear out the message listener
4924 5 : CcTest::isolate()->RemoveMessageListeners(check_message_2);
4925 5 : }
4926 :
4927 :
4928 5 : static void check_message_3(v8::Local<v8::Message> message,
4929 : v8::Local<Value> data) {
4930 5 : CHECK(message->IsSharedCrossOrigin());
4931 10 : CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4932 10 : CHECK(message->GetScriptOrigin().Options().IsOpaque());
4933 15 : CHECK_EQ(6.75, message->GetScriptOrigin()
4934 : .ResourceName()
4935 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4936 : .FromJust());
4937 15 : CHECK_EQ(7.40, message->GetScriptOrigin()
4938 : .SourceMapUrl()
4939 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4940 : .FromJust());
4941 5 : message_received = true;
4942 5 : }
4943 :
4944 :
4945 26644 : TEST(MessageHandler3) {
4946 5 : message_received = false;
4947 5 : v8::Isolate* isolate = CcTest::isolate();
4948 10 : v8::HandleScope scope(isolate);
4949 5 : CHECK(!message_received);
4950 5 : isolate->AddMessageListener(check_message_3);
4951 5 : LocalContext context;
4952 : v8::ScriptOrigin origin =
4953 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4954 : v8::Integer::New(isolate, 2), v8::True(isolate),
4955 5 : Local<v8::Integer>(), v8_str("7.40"), v8::True(isolate));
4956 : v8::Local<v8::Script> script =
4957 10 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4958 : .ToLocalChecked();
4959 10 : CHECK(script->Run(context.local()).IsEmpty());
4960 5 : CHECK(message_received);
4961 : // clear out the message listener
4962 5 : isolate->RemoveMessageListeners(check_message_3);
4963 5 : }
4964 :
4965 :
4966 5 : static void check_message_4(v8::Local<v8::Message> message,
4967 : v8::Local<Value> data) {
4968 5 : CHECK(!message->IsSharedCrossOrigin());
4969 15 : CHECK_EQ(6.75, message->GetScriptOrigin()
4970 : .ResourceName()
4971 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4972 : .FromJust());
4973 5 : message_received = true;
4974 5 : }
4975 :
4976 :
4977 26644 : TEST(MessageHandler4) {
4978 5 : message_received = false;
4979 5 : v8::Isolate* isolate = CcTest::isolate();
4980 10 : v8::HandleScope scope(isolate);
4981 5 : CHECK(!message_received);
4982 5 : isolate->AddMessageListener(check_message_4);
4983 5 : LocalContext context;
4984 : v8::ScriptOrigin origin =
4985 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4986 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
4987 : v8::Local<v8::Script> script =
4988 10 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4989 : .ToLocalChecked();
4990 10 : CHECK(script->Run(context.local()).IsEmpty());
4991 5 : CHECK(message_received);
4992 : // clear out the message listener
4993 5 : isolate->RemoveMessageListeners(check_message_4);
4994 5 : }
4995 :
4996 :
4997 5 : static void check_message_5a(v8::Local<v8::Message> message,
4998 : v8::Local<Value> data) {
4999 5 : CHECK(message->IsSharedCrossOrigin());
5000 15 : CHECK_EQ(6.75, message->GetScriptOrigin()
5001 : .ResourceName()
5002 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
5003 : .FromJust());
5004 5 : message_received = true;
5005 5 : }
5006 :
5007 :
5008 5 : static void check_message_5b(v8::Local<v8::Message> message,
5009 : v8::Local<Value> data) {
5010 5 : CHECK(!message->IsSharedCrossOrigin());
5011 15 : CHECK_EQ(6.75, message->GetScriptOrigin()
5012 : .ResourceName()
5013 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
5014 : .FromJust());
5015 5 : message_received = true;
5016 5 : }
5017 :
5018 :
5019 26644 : TEST(MessageHandler5) {
5020 5 : message_received = false;
5021 5 : v8::Isolate* isolate = CcTest::isolate();
5022 10 : v8::HandleScope scope(isolate);
5023 5 : CHECK(!message_received);
5024 5 : isolate->AddMessageListener(check_message_5a);
5025 5 : LocalContext context;
5026 : v8::ScriptOrigin origin1 =
5027 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5028 5 : v8::Integer::New(isolate, 2), v8::True(isolate));
5029 : v8::Local<v8::Script> script =
5030 10 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
5031 : .ToLocalChecked();
5032 10 : CHECK(script->Run(context.local()).IsEmpty());
5033 5 : CHECK(message_received);
5034 : // clear out the message listener
5035 5 : isolate->RemoveMessageListeners(check_message_5a);
5036 :
5037 5 : message_received = false;
5038 5 : isolate->AddMessageListener(check_message_5b);
5039 : v8::ScriptOrigin origin2 =
5040 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5041 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
5042 10 : script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
5043 : .ToLocalChecked();
5044 10 : CHECK(script->Run(context.local()).IsEmpty());
5045 5 : CHECK(message_received);
5046 : // clear out the message listener
5047 5 : isolate->RemoveMessageListeners(check_message_5b);
5048 5 : }
5049 :
5050 :
5051 26645 : THREADED_TEST(GetSetProperty) {
5052 6 : LocalContext context;
5053 6 : v8::Isolate* isolate = context->GetIsolate();
5054 12 : v8::HandleScope scope(isolate);
5055 24 : CHECK(context->Global()
5056 : ->Set(context.local(), v8_str("foo"), v8_num(14))
5057 : .FromJust());
5058 24 : CHECK(context->Global()
5059 : ->Set(context.local(), v8_str("12"), v8_num(92))
5060 : .FromJust());
5061 24 : CHECK(context->Global()
5062 : ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
5063 : .FromJust());
5064 24 : CHECK(context->Global()
5065 : ->Set(context.local(), v8_num(13), v8_num(56))
5066 : .FromJust());
5067 : Local<Value> foo = CompileRun("this.foo");
5068 12 : CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
5069 : Local<Value> twelve = CompileRun("this[12]");
5070 12 : CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
5071 : Local<Value> sixteen = CompileRun("this[16]");
5072 12 : CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
5073 : Local<Value> thirteen = CompileRun("this[13]");
5074 12 : CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
5075 30 : CHECK_EQ(92, context->Global()
5076 : ->Get(context.local(), v8::Integer::New(isolate, 12))
5077 : .ToLocalChecked()
5078 : ->Int32Value(context.local())
5079 : .FromJust());
5080 30 : CHECK_EQ(92, context->Global()
5081 : ->Get(context.local(), v8_str("12"))
5082 : .ToLocalChecked()
5083 : ->Int32Value(context.local())
5084 : .FromJust());
5085 30 : CHECK_EQ(92, context->Global()
5086 : ->Get(context.local(), v8_num(12))
5087 : .ToLocalChecked()
5088 : ->Int32Value(context.local())
5089 : .FromJust());
5090 30 : CHECK_EQ(32, context->Global()
5091 : ->Get(context.local(), v8::Integer::New(isolate, 16))
5092 : .ToLocalChecked()
5093 : ->Int32Value(context.local())
5094 : .FromJust());
5095 30 : CHECK_EQ(32, context->Global()
5096 : ->Get(context.local(), v8_str("16"))
5097 : .ToLocalChecked()
5098 : ->Int32Value(context.local())
5099 : .FromJust());
5100 30 : CHECK_EQ(32, context->Global()
5101 : ->Get(context.local(), v8_num(16))
5102 : .ToLocalChecked()
5103 : ->Int32Value(context.local())
5104 : .FromJust());
5105 30 : CHECK_EQ(56, context->Global()
5106 : ->Get(context.local(), v8::Integer::New(isolate, 13))
5107 : .ToLocalChecked()
5108 : ->Int32Value(context.local())
5109 : .FromJust());
5110 30 : CHECK_EQ(56, context->Global()
5111 : ->Get(context.local(), v8_str("13"))
5112 : .ToLocalChecked()
5113 : ->Int32Value(context.local())
5114 : .FromJust());
5115 30 : CHECK_EQ(56, context->Global()
5116 : ->Get(context.local(), v8_num(13))
5117 : .ToLocalChecked()
5118 : ->Int32Value(context.local())
5119 : .FromJust());
5120 6 : }
5121 :
5122 :
5123 26645 : THREADED_TEST(PropertyAttributes) {
5124 6 : LocalContext context;
5125 12 : v8::HandleScope scope(context->GetIsolate());
5126 : // none
5127 6 : Local<String> prop = v8_str("none");
5128 24 : CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5129 18 : CHECK_EQ(v8::None, context->Global()
5130 : ->GetPropertyAttributes(context.local(), prop)
5131 : .FromJust());
5132 : // read-only
5133 6 : prop = v8_str("read_only");
5134 12 : context->Global()
5135 24 : ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5136 : .FromJust();
5137 24 : CHECK_EQ(7, context->Global()
5138 : ->Get(context.local(), prop)
5139 : .ToLocalChecked()
5140 : ->Int32Value(context.local())
5141 : .FromJust());
5142 18 : CHECK_EQ(v8::ReadOnly, context->Global()
5143 : ->GetPropertyAttributes(context.local(), prop)
5144 : .FromJust());
5145 : CompileRun("read_only = 9");
5146 24 : CHECK_EQ(7, context->Global()
5147 : ->Get(context.local(), prop)
5148 : .ToLocalChecked()
5149 : ->Int32Value(context.local())
5150 : .FromJust());
5151 24 : CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5152 24 : CHECK_EQ(7, context->Global()
5153 : ->Get(context.local(), prop)
5154 : .ToLocalChecked()
5155 : ->Int32Value(context.local())
5156 : .FromJust());
5157 : // dont-delete
5158 6 : prop = v8_str("dont_delete");
5159 12 : context->Global()
5160 24 : ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5161 : .FromJust();
5162 24 : CHECK_EQ(13, context->Global()
5163 : ->Get(context.local(), prop)
5164 : .ToLocalChecked()
5165 : ->Int32Value(context.local())
5166 : .FromJust());
5167 : CompileRun("delete dont_delete");
5168 24 : CHECK_EQ(13, context->Global()
5169 : ->Get(context.local(), prop)
5170 : .ToLocalChecked()
5171 : ->Int32Value(context.local())
5172 : .FromJust());
5173 18 : CHECK_EQ(v8::DontDelete, context->Global()
5174 : ->GetPropertyAttributes(context.local(), prop)
5175 : .FromJust());
5176 : // dont-enum
5177 6 : prop = v8_str("dont_enum");
5178 12 : context->Global()
5179 24 : ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5180 : .FromJust();
5181 18 : CHECK_EQ(v8::DontEnum, context->Global()
5182 : ->GetPropertyAttributes(context.local(), prop)
5183 : .FromJust());
5184 : // absent
5185 6 : prop = v8_str("absent");
5186 18 : CHECK_EQ(v8::None, context->Global()
5187 : ->GetPropertyAttributes(context.local(), prop)
5188 : .FromJust());
5189 6 : Local<Value> fake_prop = v8_num(1);
5190 18 : CHECK_EQ(v8::None, context->Global()
5191 : ->GetPropertyAttributes(context.local(), fake_prop)
5192 : .FromJust());
5193 : // exception
5194 12 : TryCatch try_catch(context->GetIsolate());
5195 : Local<Value> exception =
5196 6 : CompileRun("({ toString: function() { throw 'exception';} })");
5197 18 : CHECK(context->Global()
5198 : ->GetPropertyAttributes(context.local(), exception)
5199 : .IsNothing());
5200 6 : CHECK(try_catch.HasCaught());
5201 : String::Utf8Value exception_value(context->GetIsolate(),
5202 18 : try_catch.Exception());
5203 6 : CHECK_EQ(0, strcmp("exception", *exception_value));
5204 6 : try_catch.Reset();
5205 6 : }
5206 :
5207 :
5208 26645 : THREADED_TEST(Array) {
5209 6 : LocalContext context;
5210 12 : v8::HandleScope scope(context->GetIsolate());
5211 6 : Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5212 6 : CHECK_EQ(0u, array->Length());
5213 12 : CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5214 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5215 12 : CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5216 12 : CHECK(!array->Has(context.local(), 100).FromJust());
5217 18 : CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5218 6 : CHECK_EQ(3u, array->Length());
5219 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5220 12 : CHECK(!array->Has(context.local(), 1).FromJust());
5221 12 : CHECK(array->Has(context.local(), 2).FromJust());
5222 18 : CHECK_EQ(7, array->Get(context.local(), 2)
5223 : .ToLocalChecked()
5224 : ->Int32Value(context.local())
5225 : .FromJust());
5226 : Local<Value> obj = CompileRun("[1, 2, 3]");
5227 : Local<v8::Array> arr = obj.As<v8::Array>();
5228 6 : CHECK_EQ(3u, arr->Length());
5229 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5230 : .ToLocalChecked()
5231 : ->Int32Value(context.local())
5232 : .FromJust());
5233 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5234 : .ToLocalChecked()
5235 : ->Int32Value(context.local())
5236 : .FromJust());
5237 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5238 : .ToLocalChecked()
5239 : ->Int32Value(context.local())
5240 : .FromJust());
5241 6 : array = v8::Array::New(context->GetIsolate(), 27);
5242 6 : CHECK_EQ(27u, array->Length());
5243 6 : array = v8::Array::New(context->GetIsolate(), -27);
5244 6 : CHECK_EQ(0u, array->Length());
5245 :
5246 12 : std::vector<Local<Value>> vector = {v8_num(1), v8_num(2), v8_num(3)};
5247 6 : array = v8::Array::New(context->GetIsolate(), vector.data(), vector.size());
5248 12 : CHECK_EQ(vector.size(), array->Length());
5249 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5250 : .ToLocalChecked()
5251 : ->Int32Value(context.local())
5252 : .FromJust());
5253 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5254 : .ToLocalChecked()
5255 : ->Int32Value(context.local())
5256 : .FromJust());
5257 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5258 : .ToLocalChecked()
5259 : ->Int32Value(context.local())
5260 : .FromJust());
5261 6 : }
5262 :
5263 :
5264 30 : void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5265 30 : v8::EscapableHandleScope scope(args.GetIsolate());
5266 30 : ApiTestFuzzer::Fuzz();
5267 30 : Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5268 150 : for (int i = 0; i < args.Length(); i++) {
5269 180 : CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5270 : .FromJust());
5271 : }
5272 : args.GetReturnValue().Set(scope.Escape(result));
5273 30 : }
5274 :
5275 :
5276 26645 : THREADED_TEST(Vector) {
5277 6 : v8::Isolate* isolate = CcTest::isolate();
5278 12 : v8::HandleScope scope(isolate);
5279 6 : Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5280 18 : global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5281 6 : LocalContext context(nullptr, global);
5282 :
5283 : const char* fun = "f()";
5284 : Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5285 6 : CHECK_EQ(0u, a0->Length());
5286 :
5287 : const char* fun2 = "f(11)";
5288 : Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5289 6 : CHECK_EQ(1u, a1->Length());
5290 18 : CHECK_EQ(11, a1->Get(context.local(), 0)
5291 : .ToLocalChecked()
5292 : ->Int32Value(context.local())
5293 : .FromJust());
5294 :
5295 : const char* fun3 = "f(12, 13)";
5296 : Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5297 6 : CHECK_EQ(2u, a2->Length());
5298 18 : CHECK_EQ(12, a2->Get(context.local(), 0)
5299 : .ToLocalChecked()
5300 : ->Int32Value(context.local())
5301 : .FromJust());
5302 18 : CHECK_EQ(13, a2->Get(context.local(), 1)
5303 : .ToLocalChecked()
5304 : ->Int32Value(context.local())
5305 : .FromJust());
5306 :
5307 : const char* fun4 = "f(14, 15, 16)";
5308 : Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5309 6 : CHECK_EQ(3u, a3->Length());
5310 18 : CHECK_EQ(14, a3->Get(context.local(), 0)
5311 : .ToLocalChecked()
5312 : ->Int32Value(context.local())
5313 : .FromJust());
5314 18 : CHECK_EQ(15, a3->Get(context.local(), 1)
5315 : .ToLocalChecked()
5316 : ->Int32Value(context.local())
5317 : .FromJust());
5318 18 : CHECK_EQ(16, a3->Get(context.local(), 2)
5319 : .ToLocalChecked()
5320 : ->Int32Value(context.local())
5321 : .FromJust());
5322 :
5323 : const char* fun5 = "f(17, 18, 19, 20)";
5324 : Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5325 6 : CHECK_EQ(4u, a4->Length());
5326 18 : CHECK_EQ(17, a4->Get(context.local(), 0)
5327 : .ToLocalChecked()
5328 : ->Int32Value(context.local())
5329 : .FromJust());
5330 18 : CHECK_EQ(18, a4->Get(context.local(), 1)
5331 : .ToLocalChecked()
5332 : ->Int32Value(context.local())
5333 : .FromJust());
5334 18 : CHECK_EQ(19, a4->Get(context.local(), 2)
5335 : .ToLocalChecked()
5336 : ->Int32Value(context.local())
5337 : .FromJust());
5338 18 : CHECK_EQ(20, a4->Get(context.local(), 3)
5339 : .ToLocalChecked()
5340 : ->Int32Value(context.local())
5341 : .FromJust());
5342 6 : }
5343 :
5344 :
5345 26645 : THREADED_TEST(FunctionCall) {
5346 6 : LocalContext context;
5347 6 : v8::Isolate* isolate = context->GetIsolate();
5348 12 : v8::HandleScope scope(isolate);
5349 : CompileRun(
5350 : "function Foo() {"
5351 : " var result = [];"
5352 : " for (var i = 0; i < arguments.length; i++) {"
5353 : " result.push(arguments[i]);"
5354 : " }"
5355 : " return result;"
5356 : "}"
5357 : "function ReturnThisSloppy() {"
5358 : " return this;"
5359 : "}"
5360 : "function ReturnThisStrict() {"
5361 : " 'use strict';"
5362 : " return this;"
5363 : "}");
5364 : Local<Function> Foo = Local<Function>::Cast(
5365 24 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5366 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5367 12 : context->Global()
5368 18 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
5369 : .ToLocalChecked());
5370 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
5371 12 : context->Global()
5372 18 : ->Get(context.local(), v8_str("ReturnThisStrict"))
5373 : .ToLocalChecked());
5374 :
5375 : v8::Local<Value>* args0 = nullptr;
5376 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5377 12 : Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5378 6 : CHECK_EQ(0u, a0->Length());
5379 :
5380 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5381 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5382 12 : Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5383 6 : CHECK_EQ(1u, a1->Length());
5384 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5385 : .ToLocalChecked()
5386 : ->NumberValue(context.local())
5387 : .FromJust());
5388 :
5389 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5390 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5391 12 : Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5392 6 : CHECK_EQ(2u, a2->Length());
5393 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5394 : .ToLocalChecked()
5395 : ->NumberValue(context.local())
5396 : .FromJust());
5397 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5398 : .ToLocalChecked()
5399 : ->NumberValue(context.local())
5400 : .FromJust());
5401 :
5402 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5403 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5404 12 : Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5405 6 : CHECK_EQ(3u, a3->Length());
5406 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5407 : .ToLocalChecked()
5408 : ->NumberValue(context.local())
5409 : .FromJust());
5410 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5411 : .ToLocalChecked()
5412 : ->NumberValue(context.local())
5413 : .FromJust());
5414 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5415 : .ToLocalChecked()
5416 : ->NumberValue(context.local())
5417 : .FromJust());
5418 :
5419 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5420 6 : v8_num(10.11)};
5421 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5422 12 : Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5423 6 : CHECK_EQ(4u, a4->Length());
5424 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5425 : .ToLocalChecked()
5426 : ->NumberValue(context.local())
5427 : .FromJust());
5428 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5429 : .ToLocalChecked()
5430 : ->NumberValue(context.local())
5431 : .FromJust());
5432 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5433 : .ToLocalChecked()
5434 : ->NumberValue(context.local())
5435 : .FromJust());
5436 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5437 : .ToLocalChecked()
5438 : ->NumberValue(context.local())
5439 : .FromJust());
5440 :
5441 : Local<v8::Value> r1 =
5442 : ReturnThisSloppy
5443 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5444 : .ToLocalChecked();
5445 12 : CHECK(r1->StrictEquals(context->Global()));
5446 : Local<v8::Value> r2 =
5447 12 : ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, nullptr)
5448 : .ToLocalChecked();
5449 12 : CHECK(r2->StrictEquals(context->Global()));
5450 : Local<v8::Value> r3 =
5451 12 : ReturnThisSloppy->Call(context.local(), v8_num(42), 0, nullptr)
5452 : .ToLocalChecked();
5453 6 : CHECK(r3->IsNumberObject());
5454 6 : CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5455 : Local<v8::Value> r4 =
5456 18 : ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, nullptr)
5457 : .ToLocalChecked();
5458 6 : CHECK(r4->IsStringObject());
5459 18 : CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5460 : Local<v8::Value> r5 =
5461 12 : ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, nullptr)
5462 : .ToLocalChecked();
5463 6 : CHECK(r5->IsBooleanObject());
5464 6 : CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5465 :
5466 : Local<v8::Value> r6 =
5467 : ReturnThisStrict
5468 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5469 : .ToLocalChecked();
5470 6 : CHECK(r6->IsUndefined());
5471 : Local<v8::Value> r7 =
5472 12 : ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, nullptr)
5473 : .ToLocalChecked();
5474 6 : CHECK(r7->IsNull());
5475 : Local<v8::Value> r8 =
5476 12 : ReturnThisStrict->Call(context.local(), v8_num(42), 0, nullptr)
5477 : .ToLocalChecked();
5478 6 : CHECK(r8->StrictEquals(v8_num(42)));
5479 : Local<v8::Value> r9 =
5480 18 : ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, nullptr)
5481 : .ToLocalChecked();
5482 12 : CHECK(r9->StrictEquals(v8_str("hello")));
5483 : Local<v8::Value> r10 =
5484 12 : ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, nullptr)
5485 : .ToLocalChecked();
5486 6 : CHECK(r10->StrictEquals(v8::True(isolate)));
5487 6 : }
5488 :
5489 :
5490 26645 : THREADED_TEST(ConstructCall) {
5491 6 : LocalContext context;
5492 6 : v8::Isolate* isolate = context->GetIsolate();
5493 12 : v8::HandleScope scope(isolate);
5494 : CompileRun(
5495 : "function Foo() {"
5496 : " var result = [];"
5497 : " for (var i = 0; i < arguments.length; i++) {"
5498 : " result.push(arguments[i]);"
5499 : " }"
5500 : " return result;"
5501 : "}");
5502 : Local<Function> Foo = Local<Function>::Cast(
5503 24 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5504 :
5505 : v8::Local<Value>* args0 = nullptr;
5506 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5507 6 : Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5508 6 : CHECK_EQ(0u, a0->Length());
5509 :
5510 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5511 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5512 6 : Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5513 6 : CHECK_EQ(1u, a1->Length());
5514 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5515 : .ToLocalChecked()
5516 : ->NumberValue(context.local())
5517 : .FromJust());
5518 :
5519 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5520 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5521 6 : Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5522 6 : CHECK_EQ(2u, a2->Length());
5523 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5524 : .ToLocalChecked()
5525 : ->NumberValue(context.local())
5526 : .FromJust());
5527 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5528 : .ToLocalChecked()
5529 : ->NumberValue(context.local())
5530 : .FromJust());
5531 :
5532 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5533 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5534 6 : Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5535 6 : CHECK_EQ(3u, a3->Length());
5536 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5537 : .ToLocalChecked()
5538 : ->NumberValue(context.local())
5539 : .FromJust());
5540 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5541 : .ToLocalChecked()
5542 : ->NumberValue(context.local())
5543 : .FromJust());
5544 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5545 : .ToLocalChecked()
5546 : ->NumberValue(context.local())
5547 : .FromJust());
5548 :
5549 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5550 6 : v8_num(10.11)};
5551 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5552 6 : Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5553 6 : CHECK_EQ(4u, a4->Length());
5554 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5555 : .ToLocalChecked()
5556 : ->NumberValue(context.local())
5557 : .FromJust());
5558 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5559 : .ToLocalChecked()
5560 : ->NumberValue(context.local())
5561 : .FromJust());
5562 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5563 : .ToLocalChecked()
5564 : ->NumberValue(context.local())
5565 : .FromJust());
5566 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5567 : .ToLocalChecked()
5568 : ->NumberValue(context.local())
5569 : .FromJust());
5570 6 : }
5571 :
5572 :
5573 26645 : THREADED_TEST(ConversionNumber) {
5574 6 : LocalContext env;
5575 6 : v8::Isolate* isolate = env->GetIsolate();
5576 12 : v8::HandleScope scope(isolate);
5577 : // Very large number.
5578 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5579 : Local<Value> obj =
5580 24 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5581 12 : CHECK_EQ(5312874545152.0,
5582 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5583 12 : CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5584 12 : CHECK_EQ(0, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5585 : // Large number.
5586 : CompileRun("var obj = -1234567890123;");
5587 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5588 12 : CHECK_EQ(-1234567890123.0,
5589 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5590 12 : CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5591 18 : CHECK_EQ(2382691125, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5592 : // Small positive integer.
5593 : CompileRun("var obj = 42;");
5594 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5595 12 : CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5596 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5597 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5598 : // Negative integer.
5599 : CompileRun("var obj = -37;");
5600 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5601 12 : CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5602 12 : CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5603 18 : CHECK_EQ(4294967259, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5604 : // Positive non-int32 integer.
5605 : CompileRun("var obj = 0x81234567;");
5606 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5607 12 : CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5608 12 : CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5609 18 : CHECK_EQ(2166572391, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5610 : // Fraction.
5611 : CompileRun("var obj = 42.3;");
5612 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5613 12 : CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5614 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5615 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5616 : // Large negative fraction.
5617 : CompileRun("var obj = -5726623061.75;");
5618 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5619 12 : CHECK_EQ(-5726623061.75,
5620 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5621 12 : CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5622 18 : CHECK_EQ(2863311531, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5623 6 : }
5624 :
5625 :
5626 26645 : THREADED_TEST(isNumberType) {
5627 6 : LocalContext env;
5628 12 : v8::HandleScope scope(env->GetIsolate());
5629 : // Very large number.
5630 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5631 : Local<Value> obj =
5632 24 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5633 6 : CHECK(!obj->IsInt32());
5634 6 : CHECK(!obj->IsUint32());
5635 : // Large negative number.
5636 : CompileRun("var obj = -1234567890123;");
5637 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5638 6 : CHECK(!obj->IsInt32());
5639 6 : CHECK(!obj->IsUint32());
5640 : // Small positive integer.
5641 : CompileRun("var obj = 42;");
5642 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5643 6 : CHECK(obj->IsInt32());
5644 6 : CHECK(obj->IsUint32());
5645 : // Negative integer.
5646 : CompileRun("var obj = -37;");
5647 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5648 6 : CHECK(obj->IsInt32());
5649 6 : CHECK(!obj->IsUint32());
5650 : // Positive non-int32 integer.
5651 : CompileRun("var obj = 0x81234567;");
5652 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5653 6 : CHECK(!obj->IsInt32());
5654 6 : CHECK(obj->IsUint32());
5655 : // Fraction.
5656 : CompileRun("var obj = 42.3;");
5657 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5658 6 : CHECK(!obj->IsInt32());
5659 6 : CHECK(!obj->IsUint32());
5660 : // Large negative fraction.
5661 : CompileRun("var obj = -5726623061.75;");
5662 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5663 6 : CHECK(!obj->IsInt32());
5664 6 : CHECK(!obj->IsUint32());
5665 : // Positive zero
5666 : CompileRun("var obj = 0.0;");
5667 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5668 6 : CHECK(obj->IsInt32());
5669 6 : CHECK(obj->IsUint32());
5670 : // Negative zero
5671 : CompileRun("var obj = -0.0;");
5672 24 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5673 6 : CHECK(!obj->IsInt32());
5674 6 : CHECK(!obj->IsUint32());
5675 6 : }
5676 :
5677 26645 : THREADED_TEST(IntegerType) {
5678 6 : LocalContext env;
5679 12 : v8::HandleScope scope(env->GetIsolate());
5680 : Local<Value> result;
5681 :
5682 : // Small positive integer
5683 : result = CompileRun("42;");
5684 6 : CHECK(result->IsNumber());
5685 6 : CHECK_EQ(42, result.As<v8::Integer>()->Value());
5686 : // Small negative integer
5687 : result = CompileRun("-42;");
5688 6 : CHECK(result->IsNumber());
5689 6 : CHECK_EQ(-42, result.As<v8::Integer>()->Value());
5690 : // Positive non-int32 integer
5691 : result = CompileRun("1099511627776;");
5692 6 : CHECK(result->IsNumber());
5693 6 : CHECK_EQ(1099511627776, result.As<v8::Integer>()->Value());
5694 : // Negative non-int32 integer
5695 : result = CompileRun("-1099511627776;");
5696 6 : CHECK(result->IsNumber());
5697 6 : CHECK_EQ(-1099511627776, result.As<v8::Integer>()->Value());
5698 : // Positive non-integer
5699 : result = CompileRun("3.14;");
5700 6 : CHECK(result->IsNumber());
5701 6 : CHECK_EQ(3, result.As<v8::Integer>()->Value());
5702 : // Negative non-integer
5703 : result = CompileRun("-3.14;");
5704 6 : CHECK(result->IsNumber());
5705 6 : CHECK_EQ(-3, result.As<v8::Integer>()->Value());
5706 6 : }
5707 :
5708 54 : static void CheckUncle(v8::Isolate* isolate, v8::TryCatch* try_catch) {
5709 54 : CHECK(try_catch->HasCaught());
5710 108 : String::Utf8Value str_value(isolate, try_catch->Exception());
5711 54 : CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5712 54 : try_catch->Reset();
5713 54 : }
5714 :
5715 26645 : THREADED_TEST(ConversionException) {
5716 6 : LocalContext env;
5717 6 : v8::Isolate* isolate = env->GetIsolate();
5718 12 : v8::HandleScope scope(isolate);
5719 : CompileRun(
5720 : "function TestClass() { };"
5721 : "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5722 : "var obj = new TestClass();");
5723 : Local<Value> obj =
5724 24 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5725 :
5726 12 : v8::TryCatch try_catch(isolate);
5727 :
5728 12 : CHECK(obj->ToString(env.local()).IsEmpty());
5729 6 : CheckUncle(isolate, &try_catch);
5730 :
5731 12 : CHECK(obj->ToNumber(env.local()).IsEmpty());
5732 6 : CheckUncle(isolate, &try_catch);
5733 :
5734 12 : CHECK(obj->ToInteger(env.local()).IsEmpty());
5735 6 : CheckUncle(isolate, &try_catch);
5736 :
5737 12 : CHECK(obj->ToUint32(env.local()).IsEmpty());
5738 6 : CheckUncle(isolate, &try_catch);
5739 :
5740 12 : CHECK(obj->ToInt32(env.local()).IsEmpty());
5741 6 : CheckUncle(isolate, &try_catch);
5742 :
5743 12 : CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5744 6 : CHECK(try_catch.HasCaught());
5745 6 : try_catch.Reset();
5746 :
5747 12 : CHECK(obj->Int32Value(env.local()).IsNothing());
5748 6 : CheckUncle(isolate, &try_catch);
5749 :
5750 12 : CHECK(obj->Uint32Value(env.local()).IsNothing());
5751 6 : CheckUncle(isolate, &try_catch);
5752 :
5753 12 : CHECK(obj->NumberValue(env.local()).IsNothing());
5754 6 : CheckUncle(isolate, &try_catch);
5755 :
5756 12 : CHECK(obj->IntegerValue(env.local()).IsNothing());
5757 6 : CheckUncle(isolate, &try_catch);
5758 6 : }
5759 :
5760 :
5761 28 : void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5762 28 : ApiTestFuzzer::Fuzz();
5763 56 : args.GetIsolate()->ThrowException(v8_str("konto"));
5764 28 : }
5765 :
5766 :
5767 5 : void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5768 5 : if (args.Length() < 1) {
5769 : args.GetReturnValue().Set(false);
5770 0 : return;
5771 : }
5772 10 : v8::HandleScope scope(args.GetIsolate());
5773 10 : v8::TryCatch try_catch(args.GetIsolate());
5774 : Local<Value> result =
5775 : CompileRun(args[0]
5776 10 : ->ToString(args.GetIsolate()->GetCurrentContext())
5777 5 : .ToLocalChecked());
5778 10 : CHECK(!try_catch.HasCaught() || result.IsEmpty());
5779 5 : args.GetReturnValue().Set(try_catch.HasCaught());
5780 : }
5781 :
5782 :
5783 26645 : THREADED_TEST(APICatch) {
5784 6 : v8::Isolate* isolate = CcTest::isolate();
5785 12 : v8::HandleScope scope(isolate);
5786 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5787 18 : templ->Set(v8_str("ThrowFromC"),
5788 6 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5789 6 : LocalContext context(nullptr, templ);
5790 : CompileRun(
5791 : "var thrown = false;"
5792 : "try {"
5793 : " ThrowFromC();"
5794 : "} catch (e) {"
5795 : " thrown = true;"
5796 : "}");
5797 12 : Local<Value> thrown = context->Global()
5798 18 : ->Get(context.local(), v8_str("thrown"))
5799 : .ToLocalChecked();
5800 6 : CHECK(thrown->BooleanValue(isolate));
5801 6 : }
5802 :
5803 :
5804 26645 : THREADED_TEST(APIThrowTryCatch) {
5805 6 : v8::Isolate* isolate = CcTest::isolate();
5806 12 : v8::HandleScope scope(isolate);
5807 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5808 18 : templ->Set(v8_str("ThrowFromC"),
5809 6 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5810 6 : LocalContext context(nullptr, templ);
5811 12 : v8::TryCatch try_catch(isolate);
5812 : CompileRun("ThrowFromC();");
5813 6 : CHECK(try_catch.HasCaught());
5814 6 : }
5815 :
5816 :
5817 : // Test that a try-finally block doesn't shadow a try-catch block
5818 : // when setting up an external handler.
5819 : //
5820 : // BUG(271): Some of the exception propagation does not work on the
5821 : // ARM simulator because the simulator separates the C++ stack and the
5822 : // JS stack. This test therefore fails on the simulator. The test is
5823 : // not threaded to allow the threading tests to run on the simulator.
5824 26644 : TEST(TryCatchInTryFinally) {
5825 5 : v8::Isolate* isolate = CcTest::isolate();
5826 10 : v8::HandleScope scope(isolate);
5827 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5828 15 : templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5829 5 : LocalContext context(nullptr, templ);
5830 : Local<Value> result = CompileRun(
5831 : "try {"
5832 : " try {"
5833 : " CCatcher('throw 7;');"
5834 : " } finally {"
5835 : " }"
5836 : "} catch (e) {"
5837 : "}");
5838 5 : CHECK(result->IsTrue());
5839 5 : }
5840 :
5841 :
5842 5 : static void check_custom_error_tostring(v8::Local<v8::Message> message,
5843 : v8::Local<v8::Value> data) {
5844 : const char* uncaught_error = "Uncaught MyError toString";
5845 25 : CHECK(message->Get()
5846 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5847 : v8_str(uncaught_error))
5848 : .FromJust());
5849 5 : }
5850 :
5851 :
5852 26644 : TEST(CustomErrorToString) {
5853 5 : LocalContext context;
5854 10 : v8::HandleScope scope(context->GetIsolate());
5855 5 : context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5856 : CompileRun(
5857 : "function MyError(name, message) { "
5858 : " this.name = name; "
5859 : " this.message = message; "
5860 : "} "
5861 : "MyError.prototype = Object.create(Error.prototype); "
5862 : "MyError.prototype.toString = function() { "
5863 : " return 'MyError toString'; "
5864 : "}; "
5865 : "throw new MyError('my name', 'my message'); ");
5866 5 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5867 5 : }
5868 :
5869 :
5870 15 : static void check_custom_error_message(v8::Local<v8::Message> message,
5871 : v8::Local<v8::Value> data) {
5872 : const char* uncaught_error = "Uncaught MyError: my message";
5873 45 : printf("%s\n", *v8::String::Utf8Value(CcTest::isolate(), message->Get()));
5874 60 : CHECK(message->Get()
5875 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5876 : v8_str(uncaught_error))
5877 : .FromJust());
5878 15 : }
5879 :
5880 :
5881 26644 : TEST(CustomErrorMessage) {
5882 5 : LocalContext context;
5883 10 : v8::HandleScope scope(context->GetIsolate());
5884 5 : context->GetIsolate()->AddMessageListener(check_custom_error_message);
5885 :
5886 : // Handlebars.
5887 : CompileRun(
5888 : "function MyError(msg) { "
5889 : " this.name = 'MyError'; "
5890 : " this.message = msg; "
5891 : "} "
5892 : "MyError.prototype = new Error(); "
5893 : "throw new MyError('my message'); ");
5894 :
5895 : // Closure.
5896 : CompileRun(
5897 : "function MyError(msg) { "
5898 : " this.name = 'MyError'; "
5899 : " this.message = msg; "
5900 : "} "
5901 : "inherits = function(childCtor, parentCtor) { "
5902 : " function tempCtor() {}; "
5903 : " tempCtor.prototype = parentCtor.prototype; "
5904 : " childCtor.superClass_ = parentCtor.prototype; "
5905 : " childCtor.prototype = new tempCtor(); "
5906 : " childCtor.prototype.constructor = childCtor; "
5907 : "}; "
5908 : "inherits(MyError, Error); "
5909 : "throw new MyError('my message'); ");
5910 :
5911 : // Object.create.
5912 : CompileRun(
5913 : "function MyError(msg) { "
5914 : " this.name = 'MyError'; "
5915 : " this.message = msg; "
5916 : "} "
5917 : "MyError.prototype = Object.create(Error.prototype); "
5918 : "throw new MyError('my message'); ");
5919 :
5920 5 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5921 5 : }
5922 :
5923 :
5924 10 : static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5925 : v8::Local<v8::Value> data) {
5926 10 : CHECK(data->IsExternal());
5927 10 : int* callcount = static_cast<int*>(data.As<v8::External>()->Value());
5928 10 : ++*callcount;
5929 :
5930 : const char* uncaught_error = "Uncaught exception";
5931 50 : CHECK(message->Get()
5932 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5933 : v8_str(uncaught_error))
5934 : .FromJust());
5935 : // Test that compiling code inside a message handler works.
5936 40 : CHECK(CompileRunChecked(CcTest::isolate(), "(function(a) { return a; })(42)")
5937 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5938 : v8::Integer::NewFromUnsigned(CcTest::isolate(), 42))
5939 : .FromJust());
5940 10 : }
5941 :
5942 :
5943 26644 : TEST(CustomErrorRethrowsOnToString) {
5944 5 : int callcount = 0;
5945 5 : LocalContext context;
5946 5 : v8::Isolate* isolate = context->GetIsolate();
5947 10 : v8::HandleScope scope(isolate);
5948 15 : context->GetIsolate()->AddMessageListener(
5949 5 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5950 :
5951 : CompileRun(
5952 : "var e = { toString: function() { throw e; } };"
5953 : "try { throw e; } finally {}");
5954 :
5955 5 : CHECK_EQ(callcount, 1);
5956 5 : context->GetIsolate()->RemoveMessageListeners(
5957 5 : check_custom_rethrowing_message);
5958 5 : }
5959 :
5960 26644 : TEST(CustomErrorRethrowsOnToStringInsideVerboseTryCatch) {
5961 5 : int callcount = 0;
5962 5 : LocalContext context;
5963 5 : v8::Isolate* isolate = context->GetIsolate();
5964 10 : v8::HandleScope scope(isolate);
5965 10 : v8::TryCatch try_catch(isolate);
5966 5 : try_catch.SetVerbose(true);
5967 15 : context->GetIsolate()->AddMessageListener(
5968 5 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5969 :
5970 : CompileRun(
5971 : "var e = { toString: function() { throw e; } };"
5972 : "try { throw e; } finally {}");
5973 :
5974 5 : CHECK_EQ(callcount, 1);
5975 5 : context->GetIsolate()->RemoveMessageListeners(
5976 5 : check_custom_rethrowing_message);
5977 5 : }
5978 :
5979 :
5980 15 : static void receive_message(v8::Local<v8::Message> message,
5981 : v8::Local<v8::Value> data) {
5982 15 : message->Get();
5983 15 : message_received = true;
5984 15 : }
5985 :
5986 :
5987 26644 : TEST(APIThrowMessage) {
5988 5 : message_received = false;
5989 5 : v8::Isolate* isolate = CcTest::isolate();
5990 10 : v8::HandleScope scope(isolate);
5991 5 : isolate->AddMessageListener(receive_message);
5992 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5993 15 : templ->Set(v8_str("ThrowFromC"),
5994 5 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5995 5 : LocalContext context(nullptr, templ);
5996 : CompileRun("ThrowFromC();");
5997 5 : CHECK(message_received);
5998 5 : isolate->RemoveMessageListeners(receive_message);
5999 5 : }
6000 :
6001 :
6002 26644 : TEST(APIThrowMessageAndVerboseTryCatch) {
6003 5 : message_received = false;
6004 5 : v8::Isolate* isolate = CcTest::isolate();
6005 10 : v8::HandleScope scope(isolate);
6006 5 : isolate->AddMessageListener(receive_message);
6007 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6008 15 : templ->Set(v8_str("ThrowFromC"),
6009 5 : v8::FunctionTemplate::New(isolate, ThrowFromC));
6010 5 : LocalContext context(nullptr, templ);
6011 10 : v8::TryCatch try_catch(isolate);
6012 5 : try_catch.SetVerbose(true);
6013 : Local<Value> result = CompileRun("ThrowFromC();");
6014 5 : CHECK(try_catch.HasCaught());
6015 5 : CHECK(result.IsEmpty());
6016 5 : CHECK(message_received);
6017 5 : isolate->RemoveMessageListeners(receive_message);
6018 5 : }
6019 :
6020 :
6021 26644 : TEST(APIStackOverflowAndVerboseTryCatch) {
6022 5 : message_received = false;
6023 5 : LocalContext context;
6024 10 : v8::HandleScope scope(context->GetIsolate());
6025 5 : context->GetIsolate()->AddMessageListener(receive_message);
6026 10 : v8::TryCatch try_catch(context->GetIsolate());
6027 5 : try_catch.SetVerbose(true);
6028 : Local<Value> result = CompileRun("function foo() { foo(); } foo();");
6029 5 : CHECK(try_catch.HasCaught());
6030 5 : CHECK(result.IsEmpty());
6031 5 : CHECK(message_received);
6032 5 : context->GetIsolate()->RemoveMessageListeners(receive_message);
6033 5 : }
6034 :
6035 :
6036 26645 : THREADED_TEST(ExternalScriptException) {
6037 6 : v8::Isolate* isolate = CcTest::isolate();
6038 12 : v8::HandleScope scope(isolate);
6039 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6040 18 : templ->Set(v8_str("ThrowFromC"),
6041 6 : v8::FunctionTemplate::New(isolate, ThrowFromC));
6042 6 : LocalContext context(nullptr, templ);
6043 :
6044 12 : v8::TryCatch try_catch(isolate);
6045 : Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
6046 6 : CHECK(result.IsEmpty());
6047 6 : CHECK(try_catch.HasCaught());
6048 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6049 6 : CHECK_EQ(0, strcmp("konto", *exception_value));
6050 6 : }
6051 :
6052 :
6053 85 : void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
6054 85 : ApiTestFuzzer::Fuzz();
6055 85 : CHECK_EQ(4, args.Length());
6056 85 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6057 170 : int count = args[0]->Int32Value(context).FromJust();
6058 170 : int cInterval = args[2]->Int32Value(context).FromJust();
6059 85 : if (count == 0) {
6060 10 : args.GetIsolate()->ThrowException(v8_str("FromC"));
6061 5 : return;
6062 : } else {
6063 80 : Local<v8::Object> global = context->Global();
6064 : Local<Value> fun =
6065 240 : global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
6066 320 : v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
6067 80 : if (count % cInterval == 0) {
6068 60 : v8::TryCatch try_catch(args.GetIsolate());
6069 : Local<Value> result = fun.As<Function>()
6070 60 : ->Call(context, global, 4, argv)
6071 : .FromMaybe(Local<Value>());
6072 60 : int expected = args[3]->Int32Value(context).FromJust();
6073 30 : if (try_catch.HasCaught()) {
6074 15 : CHECK_EQ(expected, count);
6075 15 : CHECK(result.IsEmpty());
6076 15 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
6077 : } else {
6078 15 : CHECK_NE(expected, count);
6079 : }
6080 : args.GetReturnValue().Set(result);
6081 : return;
6082 : } else {
6083 : args.GetReturnValue().Set(fun.As<Function>()
6084 100 : ->Call(context, global, 4, argv)
6085 : .FromMaybe(v8::Local<v8::Value>()));
6086 50 : return;
6087 : }
6088 : }
6089 : }
6090 :
6091 :
6092 25 : void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
6093 25 : ApiTestFuzzer::Fuzz();
6094 25 : CHECK_EQ(3, args.Length());
6095 : v8::Isolate* isolate = args.GetIsolate();
6096 25 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
6097 25 : bool equality = args[0]->BooleanValue(isolate);
6098 50 : int count = args[1]->Int32Value(context).FromJust();
6099 50 : int expected = args[2]->Int32Value(context).FromJust();
6100 25 : if (equality) {
6101 15 : CHECK_EQ(count, expected);
6102 : } else {
6103 10 : CHECK_NE(count, expected);
6104 : }
6105 25 : }
6106 :
6107 :
6108 26645 : THREADED_TEST(EvalInTryFinally) {
6109 6 : LocalContext context;
6110 12 : v8::HandleScope scope(context->GetIsolate());
6111 12 : v8::TryCatch try_catch(context->GetIsolate());
6112 : CompileRun(
6113 : "(function() {"
6114 : " try {"
6115 : " eval('asldkf (*&^&*^');"
6116 : " } finally {"
6117 : " return;"
6118 : " }"
6119 : "})()");
6120 6 : CHECK(!try_catch.HasCaught());
6121 6 : }
6122 :
6123 :
6124 : // This test works by making a stack of alternating JavaScript and C
6125 : // activations. These activations set up exception handlers with regular
6126 : // intervals, one interval for C activations and another for JavaScript
6127 : // activations. When enough activations have been created an exception is
6128 : // thrown and we check that the right activation catches the exception and that
6129 : // no other activations do. The right activation is always the topmost one with
6130 : // a handler, regardless of whether it is in JavaScript or C.
6131 : //
6132 : // The notation used to describe a test case looks like this:
6133 : //
6134 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6135 : //
6136 : // Each entry is an activation, either JS or C. The index is the count at that
6137 : // level. Stars identify activations with exception handlers, the @ identifies
6138 : // the exception handler that should catch the exception.
6139 : //
6140 : // BUG(271): Some of the exception propagation does not work on the
6141 : // ARM simulator because the simulator separates the C++ stack and the
6142 : // JS stack. This test therefore fails on the simulator. The test is
6143 : // not threaded to allow the threading tests to run on the simulator.
6144 26644 : TEST(ExceptionOrder) {
6145 5 : v8::Isolate* isolate = CcTest::isolate();
6146 10 : v8::HandleScope scope(isolate);
6147 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6148 15 : templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
6149 15 : templ->Set(v8_str("CThrowCountDown"),
6150 5 : v8::FunctionTemplate::New(isolate, CThrowCountDown));
6151 5 : LocalContext context(nullptr, templ);
6152 : CompileRun(
6153 : "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
6154 : " if (count == 0) throw 'FromJS';"
6155 : " if (count % jsInterval == 0) {"
6156 : " try {"
6157 : " var value = CThrowCountDown(count - 1,"
6158 : " jsInterval,"
6159 : " cInterval,"
6160 : " expected);"
6161 : " check(false, count, expected);"
6162 : " return value;"
6163 : " } catch (e) {"
6164 : " check(true, count, expected);"
6165 : " }"
6166 : " } else {"
6167 : " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
6168 : " }"
6169 : "}");
6170 : Local<Function> fun = Local<Function>::Cast(
6171 10 : context->Global()
6172 15 : ->Get(context.local(), v8_str("JSThrowCountDown"))
6173 : .ToLocalChecked());
6174 :
6175 : const int argc = 4;
6176 : // count jsInterval cInterval expected
6177 :
6178 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6179 5 : v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6180 10 : fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6181 :
6182 : // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6183 5 : v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6184 10 : fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6185 :
6186 : // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6187 5 : v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6188 10 : fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6189 :
6190 : // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6191 5 : v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6192 10 : fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6193 :
6194 : // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6195 5 : v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6196 10 : fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6197 :
6198 : // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6199 5 : v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6200 10 : fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6201 5 : }
6202 :
6203 :
6204 42 : void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6205 42 : ApiTestFuzzer::Fuzz();
6206 42 : CHECK_EQ(1, args.Length());
6207 42 : args.GetIsolate()->ThrowException(args[0]);
6208 42 : }
6209 :
6210 :
6211 26645 : THREADED_TEST(ThrowValues) {
6212 6 : v8::Isolate* isolate = CcTest::isolate();
6213 12 : v8::HandleScope scope(isolate);
6214 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6215 18 : templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6216 6 : LocalContext context(nullptr, templ);
6217 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6218 : CompileRun("function Run(obj) {"
6219 : " try {"
6220 : " Throw(obj);"
6221 : " } catch (e) {"
6222 : " return e;"
6223 : " }"
6224 : " return 'no exception';"
6225 : "}"
6226 : "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6227 6 : CHECK_EQ(5u, result->Length());
6228 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6229 : .ToLocalChecked()
6230 : ->IsString());
6231 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6232 : .ToLocalChecked()
6233 : ->IsNumber());
6234 24 : CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6235 : .ToLocalChecked()
6236 : ->Int32Value(context.local())
6237 : .FromJust());
6238 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6239 : .ToLocalChecked()
6240 : ->IsNumber());
6241 24 : CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6242 : .ToLocalChecked()
6243 : ->Int32Value(context.local())
6244 : .FromJust());
6245 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6246 : .ToLocalChecked()
6247 : ->IsNull());
6248 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6249 : .ToLocalChecked()
6250 : ->IsUndefined());
6251 6 : }
6252 :
6253 :
6254 26645 : THREADED_TEST(CatchZero) {
6255 6 : LocalContext context;
6256 12 : v8::HandleScope scope(context->GetIsolate());
6257 12 : v8::TryCatch try_catch(context->GetIsolate());
6258 6 : CHECK(!try_catch.HasCaught());
6259 : CompileRun("throw 10");
6260 6 : CHECK(try_catch.HasCaught());
6261 18 : CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6262 6 : try_catch.Reset();
6263 6 : CHECK(!try_catch.HasCaught());
6264 : CompileRun("throw 0");
6265 6 : CHECK(try_catch.HasCaught());
6266 18 : CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6267 6 : }
6268 :
6269 :
6270 26645 : THREADED_TEST(CatchExceptionFromWith) {
6271 6 : LocalContext context;
6272 12 : v8::HandleScope scope(context->GetIsolate());
6273 12 : v8::TryCatch try_catch(context->GetIsolate());
6274 6 : CHECK(!try_catch.HasCaught());
6275 : CompileRun("var o = {}; with (o) { throw 42; }");
6276 6 : CHECK(try_catch.HasCaught());
6277 6 : }
6278 :
6279 :
6280 26645 : THREADED_TEST(TryCatchAndFinallyHidingException) {
6281 6 : LocalContext context;
6282 12 : v8::HandleScope scope(context->GetIsolate());
6283 12 : v8::TryCatch try_catch(context->GetIsolate());
6284 6 : CHECK(!try_catch.HasCaught());
6285 : CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6286 : CompileRun("f({toString: function() { throw 42; }});");
6287 6 : CHECK(!try_catch.HasCaught());
6288 6 : }
6289 :
6290 :
6291 6 : void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6292 6 : v8::TryCatch try_catch(args.GetIsolate());
6293 6 : }
6294 :
6295 :
6296 26645 : THREADED_TEST(TryCatchAndFinally) {
6297 6 : LocalContext context;
6298 6 : v8::Isolate* isolate = context->GetIsolate();
6299 12 : v8::HandleScope scope(isolate);
6300 36 : CHECK(context->Global()
6301 : ->Set(context.local(), v8_str("native_with_try_catch"),
6302 : v8::FunctionTemplate::New(isolate, WithTryCatch)
6303 : ->GetFunction(context.local())
6304 : .ToLocalChecked())
6305 : .FromJust());
6306 12 : v8::TryCatch try_catch(isolate);
6307 6 : CHECK(!try_catch.HasCaught());
6308 : CompileRun(
6309 : "try {\n"
6310 : " throw new Error('a');\n"
6311 : "} finally {\n"
6312 : " native_with_try_catch();\n"
6313 : "}\n");
6314 6 : CHECK(try_catch.HasCaught());
6315 6 : }
6316 :
6317 :
6318 30 : static void TryCatchNested1Helper(int depth) {
6319 30 : if (depth > 0) {
6320 50 : v8::TryCatch try_catch(CcTest::isolate());
6321 25 : try_catch.SetVerbose(true);
6322 25 : TryCatchNested1Helper(depth - 1);
6323 25 : CHECK(try_catch.HasCaught());
6324 25 : try_catch.ReThrow();
6325 : } else {
6326 10 : CcTest::isolate()->ThrowException(v8_str("E1"));
6327 : }
6328 30 : }
6329 :
6330 :
6331 30 : static void TryCatchNested2Helper(int depth) {
6332 30 : if (depth > 0) {
6333 50 : v8::TryCatch try_catch(CcTest::isolate());
6334 25 : try_catch.SetVerbose(true);
6335 25 : TryCatchNested2Helper(depth - 1);
6336 25 : CHECK(try_catch.HasCaught());
6337 25 : try_catch.ReThrow();
6338 : } else {
6339 : CompileRun("throw 'E2';");
6340 : }
6341 30 : }
6342 :
6343 :
6344 26644 : TEST(TryCatchNested) {
6345 5 : v8::V8::Initialize();
6346 5 : LocalContext context;
6347 10 : v8::HandleScope scope(context->GetIsolate());
6348 :
6349 : {
6350 : // Test nested try-catch with a native throw in the end.
6351 10 : v8::TryCatch try_catch(context->GetIsolate());
6352 5 : TryCatchNested1Helper(5);
6353 5 : CHECK(try_catch.HasCaught());
6354 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6355 : try_catch.Exception()),
6356 : "E1"));
6357 : }
6358 :
6359 : {
6360 : // Test nested try-catch with a JavaScript throw in the end.
6361 10 : v8::TryCatch try_catch(context->GetIsolate());
6362 5 : TryCatchNested2Helper(5);
6363 5 : CHECK(try_catch.HasCaught());
6364 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6365 : try_catch.Exception()),
6366 : "E2"));
6367 : }
6368 5 : }
6369 :
6370 :
6371 10 : void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6372 10 : CHECK(try_catch->HasCaught());
6373 10 : Local<Message> message = try_catch->Message();
6374 20 : Local<Value> resource = message->GetScriptOrigin().ResourceName();
6375 10 : CHECK_EQ(
6376 : 0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), resource), "inner"));
6377 20 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), message->Get()),
6378 : "Uncaught Error: a"));
6379 20 : CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6380 : .FromJust());
6381 20 : CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6382 : .FromJust());
6383 10 : }
6384 :
6385 :
6386 5 : void TryCatchMixedNestingHelper(
6387 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6388 5 : ApiTestFuzzer::Fuzz();
6389 10 : v8::TryCatch try_catch(args.GetIsolate());
6390 5 : CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6391 5 : CHECK(try_catch.HasCaught());
6392 5 : TryCatchMixedNestingCheck(&try_catch);
6393 5 : try_catch.ReThrow();
6394 5 : }
6395 :
6396 :
6397 : // This test ensures that an outer TryCatch in the following situation:
6398 : // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6399 : // does not clobber the Message object generated for the inner TryCatch.
6400 : // This exercises the ability of TryCatch.ReThrow() to restore the
6401 : // inner pending Message before throwing the exception again.
6402 26644 : TEST(TryCatchMixedNesting) {
6403 5 : v8::Isolate* isolate = CcTest::isolate();
6404 10 : v8::HandleScope scope(isolate);
6405 5 : v8::V8::Initialize();
6406 10 : v8::TryCatch try_catch(isolate);
6407 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6408 15 : templ->Set(v8_str("TryCatchMixedNestingHelper"),
6409 5 : v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6410 5 : LocalContext context(nullptr, templ);
6411 5 : CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6412 5 : TryCatchMixedNestingCheck(&try_catch);
6413 5 : }
6414 :
6415 :
6416 5 : void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6417 5 : ApiTestFuzzer::Fuzz();
6418 10 : v8::TryCatch try_catch(args.GetIsolate());
6419 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6420 5 : CHECK(try_catch.HasCaught());
6421 5 : }
6422 :
6423 :
6424 26644 : TEST(TryCatchNative) {
6425 5 : v8::Isolate* isolate = CcTest::isolate();
6426 10 : v8::HandleScope scope(isolate);
6427 5 : v8::V8::Initialize();
6428 10 : v8::TryCatch try_catch(isolate);
6429 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6430 15 : templ->Set(v8_str("TryCatchNativeHelper"),
6431 5 : v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6432 5 : LocalContext context(nullptr, templ);
6433 : CompileRun("TryCatchNativeHelper();");
6434 5 : CHECK(!try_catch.HasCaught());
6435 5 : }
6436 :
6437 :
6438 5 : void TryCatchNativeResetHelper(
6439 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6440 5 : ApiTestFuzzer::Fuzz();
6441 10 : v8::TryCatch try_catch(args.GetIsolate());
6442 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6443 5 : CHECK(try_catch.HasCaught());
6444 5 : try_catch.Reset();
6445 5 : CHECK(!try_catch.HasCaught());
6446 5 : }
6447 :
6448 :
6449 26644 : TEST(TryCatchNativeReset) {
6450 5 : v8::Isolate* isolate = CcTest::isolate();
6451 10 : v8::HandleScope scope(isolate);
6452 5 : v8::V8::Initialize();
6453 10 : v8::TryCatch try_catch(isolate);
6454 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6455 15 : templ->Set(v8_str("TryCatchNativeResetHelper"),
6456 5 : v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6457 5 : LocalContext context(nullptr, templ);
6458 : CompileRun("TryCatchNativeResetHelper();");
6459 5 : CHECK(!try_catch.HasCaught());
6460 5 : }
6461 :
6462 :
6463 26645 : THREADED_TEST(Equality) {
6464 6 : LocalContext context;
6465 6 : v8::Isolate* isolate = context->GetIsolate();
6466 12 : v8::HandleScope scope(context->GetIsolate());
6467 : // Check that equality works at all before relying on CHECK_EQ
6468 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6469 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6470 :
6471 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6472 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6473 24 : CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6474 24 : CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6475 24 : CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6476 :
6477 : // Assume String is not internalized.
6478 18 : CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6479 18 : CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6480 12 : CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6481 12 : CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6482 12 : CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6483 12 : CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6484 6 : Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6485 6 : CHECK(!not_a_number->StrictEquals(not_a_number));
6486 6 : CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6487 6 : CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6488 :
6489 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
6490 : v8::Persistent<v8::Object> alias(isolate, obj);
6491 6 : CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6492 : alias.Reset();
6493 :
6494 18 : CHECK(v8_str("a")->SameValue(v8_str("a")));
6495 18 : CHECK(!v8_str("a")->SameValue(v8_str("b")));
6496 12 : CHECK(!v8_str("5")->SameValue(v8_num(5)));
6497 12 : CHECK(v8_num(1)->SameValue(v8_num(1)));
6498 12 : CHECK(!v8_num(1)->SameValue(v8_num(2)));
6499 12 : CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6500 6 : CHECK(not_a_number->SameValue(not_a_number));
6501 6 : CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6502 6 : CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6503 6 : }
6504 :
6505 26645 : THREADED_TEST(TypeOf) {
6506 6 : LocalContext context;
6507 6 : v8::Isolate* isolate = context->GetIsolate();
6508 12 : v8::HandleScope scope(context->GetIsolate());
6509 :
6510 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6511 6 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6512 :
6513 24 : CHECK(v8::Undefined(isolate)
6514 : ->TypeOf(isolate)
6515 : ->Equals(context.local(), v8_str("undefined"))
6516 : .FromJust());
6517 24 : CHECK(v8::Null(isolate)
6518 : ->TypeOf(isolate)
6519 : ->Equals(context.local(), v8_str("object"))
6520 : .FromJust());
6521 30 : CHECK(v8_str("str")
6522 : ->TypeOf(isolate)
6523 : ->Equals(context.local(), v8_str("string"))
6524 : .FromJust());
6525 30 : CHECK(v8_num(0.0)
6526 : ->TypeOf(isolate)
6527 : ->Equals(context.local(), v8_str("number"))
6528 : .FromJust());
6529 30 : CHECK(v8_num(1)
6530 : ->TypeOf(isolate)
6531 : ->Equals(context.local(), v8_str("number"))
6532 : .FromJust());
6533 30 : CHECK(v8::Object::New(isolate)
6534 : ->TypeOf(isolate)
6535 : ->Equals(context.local(), v8_str("object"))
6536 : .FromJust());
6537 24 : CHECK(v8::Boolean::New(isolate, true)
6538 : ->TypeOf(isolate)
6539 : ->Equals(context.local(), v8_str("boolean"))
6540 : .FromJust());
6541 24 : CHECK(fun->TypeOf(isolate)
6542 : ->Equals(context.local(), v8_str("function"))
6543 : .FromJust());
6544 6 : }
6545 :
6546 26645 : THREADED_TEST(InstanceOf) {
6547 6 : LocalContext env;
6548 12 : v8::HandleScope scope(env->GetIsolate());
6549 : CompileRun(
6550 : "var A = {};"
6551 : "var B = {};"
6552 : "var C = {};"
6553 : "B.__proto__ = A;"
6554 : "C.__proto__ = B;"
6555 : "function F() {}"
6556 : "F.prototype = A;"
6557 : "var G = { [Symbol.hasInstance] : null};"
6558 : "var H = { [Symbol.hasInstance] : () => { throw new Error(); } };"
6559 : "var J = { [Symbol.hasInstance] : () => true };"
6560 : "class K {}"
6561 : "var D = new K;"
6562 : "class L extends K {}"
6563 : "var E = new L");
6564 :
6565 6 : v8::Local<v8::Object> f = v8::Local<v8::Object>::Cast(CompileRun("F"));
6566 6 : v8::Local<v8::Object> g = v8::Local<v8::Object>::Cast(CompileRun("G"));
6567 6 : v8::Local<v8::Object> h = v8::Local<v8::Object>::Cast(CompileRun("H"));
6568 6 : v8::Local<v8::Object> j = v8::Local<v8::Object>::Cast(CompileRun("J"));
6569 6 : v8::Local<v8::Object> k = v8::Local<v8::Object>::Cast(CompileRun("K"));
6570 6 : v8::Local<v8::Object> l = v8::Local<v8::Object>::Cast(CompileRun("L"));
6571 : v8::Local<v8::Value> a = v8::Local<v8::Value>::Cast(CompileRun("A"));
6572 : v8::Local<v8::Value> b = v8::Local<v8::Value>::Cast(CompileRun("B"));
6573 : v8::Local<v8::Value> c = v8::Local<v8::Value>::Cast(CompileRun("C"));
6574 : v8::Local<v8::Value> d = v8::Local<v8::Value>::Cast(CompileRun("D"));
6575 : v8::Local<v8::Value> e = v8::Local<v8::Value>::Cast(CompileRun("E"));
6576 :
6577 12 : v8::TryCatch try_catch(env->GetIsolate());
6578 12 : CHECK(!a->InstanceOf(env.local(), f).ToChecked());
6579 12 : CHECK(b->InstanceOf(env.local(), f).ToChecked());
6580 12 : CHECK(c->InstanceOf(env.local(), f).ToChecked());
6581 12 : CHECK(!d->InstanceOf(env.local(), f).ToChecked());
6582 12 : CHECK(!e->InstanceOf(env.local(), f).ToChecked());
6583 6 : CHECK(!try_catch.HasCaught());
6584 :
6585 12 : CHECK(a->InstanceOf(env.local(), g).IsNothing());
6586 6 : CHECK(try_catch.HasCaught());
6587 6 : try_catch.Reset();
6588 :
6589 12 : CHECK(b->InstanceOf(env.local(), h).IsNothing());
6590 6 : CHECK(try_catch.HasCaught());
6591 6 : try_catch.Reset();
6592 :
6593 18 : CHECK(v8_num(1)->InstanceOf(env.local(), j).ToChecked());
6594 6 : CHECK(!try_catch.HasCaught());
6595 :
6596 12 : CHECK(d->InstanceOf(env.local(), k).ToChecked());
6597 12 : CHECK(e->InstanceOf(env.local(), k).ToChecked());
6598 12 : CHECK(!d->InstanceOf(env.local(), l).ToChecked());
6599 12 : CHECK(e->InstanceOf(env.local(), l).ToChecked());
6600 6 : CHECK(!try_catch.HasCaught());
6601 6 : }
6602 :
6603 26645 : THREADED_TEST(MultiRun) {
6604 6 : LocalContext context;
6605 12 : v8::HandleScope scope(context->GetIsolate());
6606 : Local<Script> script = v8_compile("x");
6607 126 : for (int i = 0; i < 10; i++) {
6608 60 : script->Run(context.local()).IsEmpty();
6609 : }
6610 6 : }
6611 :
6612 :
6613 204 : static void GetXValue(Local<Name> name,
6614 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6615 204 : ApiTestFuzzer::Fuzz();
6616 816 : CHECK(info.Data()
6617 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6618 : .FromJust());
6619 816 : CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6620 : .FromJust());
6621 : info.GetReturnValue().Set(name);
6622 204 : }
6623 :
6624 :
6625 26645 : THREADED_TEST(SimplePropertyRead) {
6626 6 : LocalContext context;
6627 6 : v8::Isolate* isolate = context->GetIsolate();
6628 12 : v8::HandleScope scope(isolate);
6629 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6630 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6631 30 : CHECK(context->Global()
6632 : ->Set(context.local(), v8_str("obj"),
6633 : templ->NewInstance(context.local()).ToLocalChecked())
6634 : .FromJust());
6635 : Local<Script> script = v8_compile("obj.x");
6636 126 : for (int i = 0; i < 10; i++) {
6637 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
6638 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6639 : }
6640 6 : }
6641 :
6642 :
6643 26645 : THREADED_TEST(DefinePropertyOnAPIAccessor) {
6644 6 : LocalContext context;
6645 6 : v8::Isolate* isolate = context->GetIsolate();
6646 12 : v8::HandleScope scope(isolate);
6647 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6648 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6649 30 : CHECK(context->Global()
6650 : ->Set(context.local(), v8_str("obj"),
6651 : templ->NewInstance(context.local()).ToLocalChecked())
6652 : .FromJust());
6653 :
6654 : // Uses getOwnPropertyDescriptor to check the configurable status
6655 : Local<Script> script_desc = v8_compile(
6656 : "var prop = Object.getOwnPropertyDescriptor( "
6657 : "obj, 'x');"
6658 : "prop.configurable;");
6659 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6660 6 : CHECK(result->BooleanValue(isolate));
6661 :
6662 : // Redefine get - but still configurable
6663 : Local<Script> script_define = v8_compile(
6664 : "var desc = { get: function(){return 42; },"
6665 : " configurable: true };"
6666 : "Object.defineProperty(obj, 'x', desc);"
6667 : "obj.x");
6668 6 : result = script_define->Run(context.local()).ToLocalChecked();
6669 18 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6670 :
6671 : // Check that the accessor is still configurable
6672 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6673 6 : CHECK(result->BooleanValue(isolate));
6674 :
6675 : // Redefine to a non-configurable
6676 : script_define = v8_compile(
6677 : "var desc = { get: function(){return 43; },"
6678 : " configurable: false };"
6679 : "Object.defineProperty(obj, 'x', desc);"
6680 : "obj.x");
6681 6 : result = script_define->Run(context.local()).ToLocalChecked();
6682 18 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6683 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6684 6 : CHECK(!result->BooleanValue(isolate));
6685 :
6686 : // Make sure that it is not possible to redefine again
6687 12 : v8::TryCatch try_catch(isolate);
6688 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6689 6 : CHECK(try_catch.HasCaught());
6690 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6691 6 : CHECK_EQ(0,
6692 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6693 6 : }
6694 :
6695 :
6696 26645 : THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6697 6 : v8::Isolate* isolate = CcTest::isolate();
6698 12 : v8::HandleScope scope(isolate);
6699 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6700 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6701 6 : LocalContext context;
6702 30 : CHECK(context->Global()
6703 : ->Set(context.local(), v8_str("obj"),
6704 : templ->NewInstance(context.local()).ToLocalChecked())
6705 : .FromJust());
6706 :
6707 : Local<Script> script_desc = v8_compile(
6708 : "var prop ="
6709 : "Object.getOwnPropertyDescriptor( "
6710 : "obj, 'x');"
6711 : "prop.configurable;");
6712 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6713 6 : CHECK(result->BooleanValue(isolate));
6714 :
6715 : Local<Script> script_define = v8_compile(
6716 : "var desc = {get: function(){return 42; },"
6717 : " configurable: true };"
6718 : "Object.defineProperty(obj, 'x', desc);"
6719 : "obj.x");
6720 6 : result = script_define->Run(context.local()).ToLocalChecked();
6721 18 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6722 :
6723 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6724 6 : CHECK(result->BooleanValue(isolate));
6725 :
6726 : script_define = v8_compile(
6727 : "var desc = {get: function(){return 43; },"
6728 : " configurable: false };"
6729 : "Object.defineProperty(obj, 'x', desc);"
6730 : "obj.x");
6731 6 : result = script_define->Run(context.local()).ToLocalChecked();
6732 18 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6733 :
6734 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6735 6 : CHECK(!result->BooleanValue(isolate));
6736 :
6737 12 : v8::TryCatch try_catch(isolate);
6738 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6739 6 : CHECK(try_catch.HasCaught());
6740 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6741 6 : CHECK_EQ(0,
6742 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6743 6 : }
6744 :
6745 :
6746 72 : static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6747 : char const* name) {
6748 : return v8::Local<v8::Object>::Cast(
6749 : (*context)
6750 144 : ->Global()
6751 288 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6752 72 : .ToLocalChecked());
6753 : }
6754 :
6755 :
6756 26645 : THREADED_TEST(DefineAPIAccessorOnObject) {
6757 6 : v8::Isolate* isolate = CcTest::isolate();
6758 12 : v8::HandleScope scope(isolate);
6759 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6760 6 : LocalContext context;
6761 :
6762 30 : CHECK(context->Global()
6763 : ->Set(context.local(), v8_str("obj1"),
6764 : templ->NewInstance(context.local()).ToLocalChecked())
6765 : .FromJust());
6766 : CompileRun("var obj2 = {};");
6767 :
6768 6 : CHECK(CompileRun("obj1.x")->IsUndefined());
6769 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6770 :
6771 30 : CHECK(GetGlobalProperty(&context, "obj1")
6772 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6773 : v8_str("donut"))
6774 : .FromJust());
6775 :
6776 6 : ExpectString("obj1.x", "x");
6777 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6778 :
6779 30 : CHECK(GetGlobalProperty(&context, "obj2")
6780 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6781 : v8_str("donut"))
6782 : .FromJust());
6783 :
6784 6 : ExpectString("obj1.x", "x");
6785 6 : ExpectString("obj2.x", "x");
6786 :
6787 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6788 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6789 :
6790 : CompileRun(
6791 : "Object.defineProperty(obj1, 'x',"
6792 : "{ get: function() { return 'y'; }, configurable: true })");
6793 :
6794 6 : ExpectString("obj1.x", "y");
6795 6 : ExpectString("obj2.x", "x");
6796 :
6797 : CompileRun(
6798 : "Object.defineProperty(obj2, 'x',"
6799 : "{ get: function() { return 'y'; }, configurable: true })");
6800 :
6801 6 : ExpectString("obj1.x", "y");
6802 6 : ExpectString("obj2.x", "y");
6803 :
6804 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6805 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6806 :
6807 30 : CHECK(GetGlobalProperty(&context, "obj1")
6808 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6809 : v8_str("donut"))
6810 : .FromJust());
6811 30 : CHECK(GetGlobalProperty(&context, "obj2")
6812 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6813 : v8_str("donut"))
6814 : .FromJust());
6815 :
6816 6 : ExpectString("obj1.x", "x");
6817 6 : ExpectString("obj2.x", "x");
6818 :
6819 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6820 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6821 :
6822 : // Define getters/setters, but now make them not configurable.
6823 : CompileRun(
6824 : "Object.defineProperty(obj1, 'x',"
6825 : "{ get: function() { return 'z'; }, configurable: false })");
6826 : CompileRun(
6827 : "Object.defineProperty(obj2, 'x',"
6828 : "{ get: function() { return 'z'; }, configurable: false })");
6829 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6830 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6831 :
6832 6 : ExpectString("obj1.x", "z");
6833 6 : ExpectString("obj2.x", "z");
6834 :
6835 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6836 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6837 : v8_str("donut"))
6838 : .FromJust());
6839 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6840 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6841 : v8_str("donut"))
6842 : .FromJust());
6843 :
6844 6 : ExpectString("obj1.x", "z");
6845 6 : ExpectString("obj2.x", "z");
6846 6 : }
6847 :
6848 :
6849 26645 : THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6850 6 : v8::Isolate* isolate = CcTest::isolate();
6851 12 : v8::HandleScope scope(isolate);
6852 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6853 6 : LocalContext context;
6854 :
6855 30 : CHECK(context->Global()
6856 : ->Set(context.local(), v8_str("obj1"),
6857 : templ->NewInstance(context.local()).ToLocalChecked())
6858 : .FromJust());
6859 : CompileRun("var obj2 = {};");
6860 :
6861 30 : CHECK(GetGlobalProperty(&context, "obj1")
6862 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6863 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6864 : .FromJust());
6865 30 : CHECK(GetGlobalProperty(&context, "obj2")
6866 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6867 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6868 : .FromJust());
6869 :
6870 6 : ExpectString("obj1.x", "x");
6871 6 : ExpectString("obj2.x", "x");
6872 :
6873 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6874 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6875 :
6876 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6877 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6878 : v8_str("donut"))
6879 : .FromJust());
6880 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6881 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6882 : v8_str("donut"))
6883 : .FromJust());
6884 :
6885 : {
6886 12 : v8::TryCatch try_catch(isolate);
6887 : CompileRun(
6888 : "Object.defineProperty(obj1, 'x',"
6889 : "{get: function() { return 'func'; }})");
6890 6 : CHECK(try_catch.HasCaught());
6891 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6892 6 : CHECK_EQ(
6893 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6894 : }
6895 : {
6896 12 : v8::TryCatch try_catch(isolate);
6897 : CompileRun(
6898 : "Object.defineProperty(obj2, 'x',"
6899 : "{get: function() { return 'func'; }})");
6900 6 : CHECK(try_catch.HasCaught());
6901 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6902 6 : CHECK_EQ(
6903 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6904 : }
6905 6 : }
6906 :
6907 :
6908 24 : static void Get239Value(Local<Name> name,
6909 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6910 24 : ApiTestFuzzer::Fuzz();
6911 96 : CHECK(info.Data()
6912 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6913 : .FromJust());
6914 96 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6915 : .FromJust());
6916 : info.GetReturnValue().Set(name);
6917 24 : }
6918 :
6919 :
6920 26645 : THREADED_TEST(ElementAPIAccessor) {
6921 6 : v8::Isolate* isolate = CcTest::isolate();
6922 12 : v8::HandleScope scope(isolate);
6923 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6924 6 : LocalContext context;
6925 :
6926 30 : CHECK(context->Global()
6927 : ->Set(context.local(), v8_str("obj1"),
6928 : templ->NewInstance(context.local()).ToLocalChecked())
6929 : .FromJust());
6930 : CompileRun("var obj2 = {};");
6931 :
6932 30 : CHECK(GetGlobalProperty(&context, "obj1")
6933 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6934 : v8_str("donut"))
6935 : .FromJust());
6936 30 : CHECK(GetGlobalProperty(&context, "obj2")
6937 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6938 : v8_str("donut"))
6939 : .FromJust());
6940 :
6941 6 : ExpectString("obj1[239]", "239");
6942 6 : ExpectString("obj2[239]", "239");
6943 6 : ExpectString("obj1['239']", "239");
6944 6 : ExpectString("obj2['239']", "239");
6945 6 : }
6946 :
6947 :
6948 26639 : v8::Persistent<Value> xValue;
6949 :
6950 :
6951 120 : static void SetXValue(Local<Name> name, Local<Value> value,
6952 : const v8::PropertyCallbackInfo<void>& info) {
6953 120 : Local<Context> context = info.GetIsolate()->GetCurrentContext();
6954 240 : CHECK(value->Equals(context, v8_num(4)).FromJust());
6955 360 : CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6956 360 : CHECK(name->Equals(context, v8_str("x")).FromJust());
6957 120 : CHECK(xValue.IsEmpty());
6958 : xValue.Reset(info.GetIsolate(), value);
6959 120 : }
6960 :
6961 :
6962 26645 : THREADED_TEST(SimplePropertyWrite) {
6963 6 : v8::Isolate* isolate = CcTest::isolate();
6964 12 : v8::HandleScope scope(isolate);
6965 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6966 18 : templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6967 6 : LocalContext context;
6968 30 : CHECK(context->Global()
6969 : ->Set(context.local(), v8_str("obj"),
6970 : templ->NewInstance(context.local()).ToLocalChecked())
6971 : .FromJust());
6972 : Local<Script> script = v8_compile("obj.x = 4");
6973 126 : for (int i = 0; i < 10; i++) {
6974 60 : CHECK(xValue.IsEmpty());
6975 60 : script->Run(context.local()).ToLocalChecked();
6976 240 : CHECK(v8_num(4)
6977 : ->Equals(context.local(),
6978 : Local<Value>::New(CcTest::isolate(), xValue))
6979 : .FromJust());
6980 : xValue.Reset();
6981 : }
6982 6 : }
6983 :
6984 :
6985 26645 : THREADED_TEST(SetterOnly) {
6986 6 : v8::Isolate* isolate = CcTest::isolate();
6987 12 : v8::HandleScope scope(isolate);
6988 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6989 18 : templ->SetAccessor(v8_str("x"), nullptr, SetXValue, v8_str("donut"));
6990 6 : LocalContext context;
6991 30 : CHECK(context->Global()
6992 : ->Set(context.local(), v8_str("obj"),
6993 : templ->NewInstance(context.local()).ToLocalChecked())
6994 : .FromJust());
6995 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
6996 126 : for (int i = 0; i < 10; i++) {
6997 60 : CHECK(xValue.IsEmpty());
6998 60 : script->Run(context.local()).ToLocalChecked();
6999 240 : CHECK(v8_num(4)
7000 : ->Equals(context.local(),
7001 : Local<Value>::New(CcTest::isolate(), xValue))
7002 : .FromJust());
7003 : xValue.Reset();
7004 : }
7005 6 : }
7006 :
7007 :
7008 26645 : THREADED_TEST(NoAccessors) {
7009 6 : v8::Isolate* isolate = CcTest::isolate();
7010 12 : v8::HandleScope scope(isolate);
7011 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7012 18 : templ->SetAccessor(v8_str("x"),
7013 : static_cast<v8::AccessorGetterCallback>(nullptr), nullptr,
7014 6 : v8_str("donut"));
7015 6 : LocalContext context;
7016 30 : CHECK(context->Global()
7017 : ->Set(context.local(), v8_str("obj"),
7018 : templ->NewInstance(context.local()).ToLocalChecked())
7019 : .FromJust());
7020 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
7021 126 : for (int i = 0; i < 10; i++) {
7022 60 : script->Run(context.local()).ToLocalChecked();
7023 : }
7024 6 : }
7025 :
7026 :
7027 26645 : THREADED_TEST(MultiContexts) {
7028 6 : v8::Isolate* isolate = CcTest::isolate();
7029 12 : v8::HandleScope scope(isolate);
7030 6 : v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7031 18 : templ->Set(v8_str("dummy"),
7032 6 : v8::FunctionTemplate::New(isolate, DummyCallHandler));
7033 :
7034 6 : Local<String> password = v8_str("Password");
7035 :
7036 : // Create an environment
7037 6 : LocalContext context0(nullptr, templ);
7038 6 : context0->SetSecurityToken(password);
7039 6 : v8::Local<v8::Object> global0 = context0->Global();
7040 18 : CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
7041 : .FromJust());
7042 24 : CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
7043 : .ToLocalChecked()
7044 : ->Int32Value(context0.local())
7045 : .FromJust());
7046 :
7047 : // Create an independent environment
7048 6 : LocalContext context1(nullptr, templ);
7049 6 : context1->SetSecurityToken(password);
7050 6 : v8::Local<v8::Object> global1 = context1->Global();
7051 18 : CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
7052 : .FromJust());
7053 12 : CHECK(!global0->Equals(context1.local(), global1).FromJust());
7054 24 : CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
7055 : .ToLocalChecked()
7056 : ->Int32Value(context0.local())
7057 : .FromJust());
7058 24 : CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
7059 : .ToLocalChecked()
7060 : ->Int32Value(context1.local())
7061 : .FromJust());
7062 :
7063 : // Now create a new context with the old global
7064 6 : LocalContext context2(nullptr, templ, global1);
7065 6 : context2->SetSecurityToken(password);
7066 6 : v8::Local<v8::Object> global2 = context2->Global();
7067 12 : CHECK(global1->Equals(context2.local(), global2).FromJust());
7068 24 : CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
7069 : .ToLocalChecked()
7070 : ->Int32Value(context1.local())
7071 : .FromJust());
7072 24 : CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
7073 : .ToLocalChecked()
7074 : ->Int32Value(context2.local())
7075 : .FromJust());
7076 6 : }
7077 :
7078 :
7079 26645 : THREADED_TEST(FunctionPrototypeAcrossContexts) {
7080 : // Make sure that functions created by cloning boilerplates cannot
7081 : // communicate through their __proto__ field.
7082 :
7083 12 : v8::HandleScope scope(CcTest::isolate());
7084 :
7085 6 : LocalContext env0;
7086 6 : v8::Local<v8::Object> global0 = env0->Global();
7087 18 : v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
7088 : .ToLocalChecked()
7089 : .As<v8::Object>();
7090 : v8::Local<v8::Object> tostring0 =
7091 18 : object0->Get(env0.local(), v8_str("toString"))
7092 : .ToLocalChecked()
7093 : .As<v8::Object>();
7094 : v8::Local<v8::Object> proto0 =
7095 18 : tostring0->Get(env0.local(), v8_str("__proto__"))
7096 : .ToLocalChecked()
7097 : .As<v8::Object>();
7098 18 : CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
7099 :
7100 6 : LocalContext env1;
7101 6 : v8::Local<v8::Object> global1 = env1->Global();
7102 18 : v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
7103 : .ToLocalChecked()
7104 : .As<v8::Object>();
7105 : v8::Local<v8::Object> tostring1 =
7106 18 : object1->Get(env1.local(), v8_str("toString"))
7107 : .ToLocalChecked()
7108 : .As<v8::Object>();
7109 : v8::Local<v8::Object> proto1 =
7110 18 : tostring1->Get(env1.local(), v8_str("__proto__"))
7111 : .ToLocalChecked()
7112 : .As<v8::Object>();
7113 18 : CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
7114 6 : }
7115 :
7116 :
7117 26645 : THREADED_TEST(Regress892105) {
7118 : // Make sure that object and array literals created by cloning
7119 : // boilerplates cannot communicate through their __proto__
7120 : // field. This is rather difficult to check, but we try to add stuff
7121 : // to Object.prototype and Array.prototype and create a new
7122 : // environment. This should succeed.
7123 :
7124 12 : v8::HandleScope scope(CcTest::isolate());
7125 :
7126 : Local<String> source = v8_str(
7127 : "Object.prototype.obj = 1234;"
7128 : "Array.prototype.arr = 4567;"
7129 6 : "8901");
7130 :
7131 6 : LocalContext env0;
7132 6 : Local<Script> script0 = v8_compile(source);
7133 18 : CHECK_EQ(8901.0, script0->Run(env0.local())
7134 : .ToLocalChecked()
7135 : ->NumberValue(env0.local())
7136 : .FromJust());
7137 :
7138 6 : LocalContext env1;
7139 6 : Local<Script> script1 = v8_compile(source);
7140 18 : CHECK_EQ(8901.0, script1->Run(env1.local())
7141 : .ToLocalChecked()
7142 : ->NumberValue(env1.local())
7143 : .FromJust());
7144 6 : }
7145 :
7146 30 : static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
7147 : args.GetReturnValue().Set(args.This());
7148 30 : }
7149 :
7150 26645 : THREADED_TEST(UndetectableObject) {
7151 6 : LocalContext env;
7152 12 : v8::HandleScope scope(env->GetIsolate());
7153 :
7154 : Local<v8::FunctionTemplate> desc =
7155 6 : v8::FunctionTemplate::New(env->GetIsolate());
7156 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7157 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7158 :
7159 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7160 : .ToLocalChecked()
7161 : ->NewInstance(env.local())
7162 : .ToLocalChecked();
7163 24 : CHECK(
7164 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7165 :
7166 6 : ExpectString("undetectable.toString()", "[object Object]");
7167 6 : ExpectString("typeof undetectable", "undefined");
7168 6 : ExpectString("typeof(undetectable)", "undefined");
7169 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
7170 6 : ExpectBoolean("typeof undetectable == 'object'", false);
7171 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7172 6 : ExpectBoolean("!undetectable", true);
7173 :
7174 6 : ExpectObject("true&&undetectable", obj);
7175 6 : ExpectBoolean("false&&undetectable", false);
7176 6 : ExpectBoolean("true||undetectable", true);
7177 6 : ExpectObject("false||undetectable", obj);
7178 :
7179 6 : ExpectObject("undetectable&&true", obj);
7180 6 : ExpectObject("undetectable&&false", obj);
7181 6 : ExpectBoolean("undetectable||true", true);
7182 6 : ExpectBoolean("undetectable||false", false);
7183 :
7184 6 : ExpectBoolean("undetectable==null", true);
7185 6 : ExpectBoolean("null==undetectable", true);
7186 6 : ExpectBoolean("undetectable==undefined", true);
7187 6 : ExpectBoolean("undefined==undetectable", true);
7188 6 : ExpectBoolean("undetectable==undetectable", true);
7189 :
7190 :
7191 6 : ExpectBoolean("undetectable===null", false);
7192 6 : ExpectBoolean("null===undetectable", false);
7193 6 : ExpectBoolean("undetectable===undefined", false);
7194 6 : ExpectBoolean("undefined===undetectable", false);
7195 6 : ExpectBoolean("undetectable===undetectable", true);
7196 6 : }
7197 :
7198 :
7199 26645 : THREADED_TEST(VoidLiteral) {
7200 6 : LocalContext env;
7201 6 : v8::Isolate* isolate = env->GetIsolate();
7202 12 : v8::HandleScope scope(isolate);
7203 :
7204 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7205 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7206 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7207 :
7208 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7209 : .ToLocalChecked()
7210 : ->NewInstance(env.local())
7211 : .ToLocalChecked();
7212 24 : CHECK(
7213 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7214 :
7215 6 : ExpectBoolean("undefined == void 0", true);
7216 6 : ExpectBoolean("undetectable == void 0", true);
7217 6 : ExpectBoolean("null == void 0", true);
7218 6 : ExpectBoolean("undefined === void 0", true);
7219 6 : ExpectBoolean("undetectable === void 0", false);
7220 6 : ExpectBoolean("null === void 0", false);
7221 :
7222 6 : ExpectBoolean("void 0 == undefined", true);
7223 6 : ExpectBoolean("void 0 == undetectable", true);
7224 6 : ExpectBoolean("void 0 == null", true);
7225 6 : ExpectBoolean("void 0 === undefined", true);
7226 6 : ExpectBoolean("void 0 === undetectable", false);
7227 6 : ExpectBoolean("void 0 === null", false);
7228 :
7229 : ExpectString(
7230 : "(function() {"
7231 : " try {"
7232 : " return x === void 0;"
7233 : " } catch(e) {"
7234 : " return e.toString();"
7235 : " }"
7236 : "})()",
7237 6 : "ReferenceError: x is not defined");
7238 : ExpectString(
7239 : "(function() {"
7240 : " try {"
7241 : " return void 0 === x;"
7242 : " } catch(e) {"
7243 : " return e.toString();"
7244 : " }"
7245 : "})()",
7246 6 : "ReferenceError: x is not defined");
7247 6 : }
7248 :
7249 :
7250 26645 : THREADED_TEST(ExtensibleOnUndetectable) {
7251 6 : LocalContext env;
7252 6 : v8::Isolate* isolate = env->GetIsolate();
7253 12 : v8::HandleScope scope(isolate);
7254 :
7255 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7256 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7257 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7258 :
7259 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7260 : .ToLocalChecked()
7261 : ->NewInstance(env.local())
7262 : .ToLocalChecked();
7263 24 : CHECK(
7264 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7265 :
7266 : Local<String> source = v8_str(
7267 : "undetectable.x = 42;"
7268 6 : "undetectable.x");
7269 :
7270 6 : Local<Script> script = v8_compile(source);
7271 :
7272 24 : CHECK(v8::Integer::New(isolate, 42)
7273 : ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7274 : .FromJust());
7275 :
7276 6 : ExpectBoolean("Object.isExtensible(undetectable)", true);
7277 :
7278 6 : source = v8_str("Object.preventExtensions(undetectable);");
7279 6 : script = v8_compile(source);
7280 6 : script->Run(env.local()).ToLocalChecked();
7281 6 : ExpectBoolean("Object.isExtensible(undetectable)", false);
7282 :
7283 6 : source = v8_str("undetectable.y = 2000;");
7284 6 : script = v8_compile(source);
7285 6 : script->Run(env.local()).ToLocalChecked();
7286 6 : ExpectBoolean("undetectable.y == undefined", true);
7287 6 : }
7288 :
7289 26645 : THREADED_TEST(ConstructCallWithUndetectable) {
7290 6 : LocalContext env;
7291 6 : v8::Isolate* isolate = env->GetIsolate();
7292 12 : v8::HandleScope scope(isolate);
7293 :
7294 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7295 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7296 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7297 :
7298 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7299 : .ToLocalChecked()
7300 : ->NewInstance(env.local())
7301 : .ToLocalChecked();
7302 24 : CHECK(
7303 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7304 :
7305 : // Undetectable object cannot be called as constructor.
7306 12 : v8::TryCatch try_catch(env->GetIsolate());
7307 6 : CHECK(CompileRun("new undetectable()").IsEmpty());
7308 6 : CHECK(try_catch.HasCaught());
7309 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
7310 6 : CHECK_EQ(0, strcmp("TypeError: undetectable is not a constructor",
7311 : *exception_value));
7312 6 : }
7313 :
7314 : static int increment_callback_counter = 0;
7315 :
7316 12 : static void IncrementCounterConstructCallback(
7317 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7318 12 : increment_callback_counter++;
7319 48 : CHECK(Local<Object>::Cast(args.NewTarget())
7320 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("counter"),
7321 : v8_num(increment_callback_counter))
7322 : .FromJust());
7323 : args.GetReturnValue().Set(args.NewTarget());
7324 12 : }
7325 :
7326 26645 : THREADED_TEST(SetCallAsFunctionHandlerConstructor) {
7327 6 : LocalContext env;
7328 6 : v8::Isolate* isolate = env->GetIsolate();
7329 12 : v8::HandleScope scope(isolate);
7330 :
7331 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7332 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(
7333 6 : IncrementCounterConstructCallback); // callable
7334 :
7335 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7336 : .ToLocalChecked()
7337 : ->NewInstance(env.local())
7338 : .ToLocalChecked();
7339 24 : CHECK(env->Global()->Set(env.local(), v8_str("Counter"), obj).FromJust());
7340 :
7341 6 : ExpectInt32("(new Counter()).counter", 1);
7342 6 : CHECK_EQ(1, increment_callback_counter);
7343 6 : ExpectInt32("(new Counter()).counter", 2);
7344 6 : CHECK_EQ(2, increment_callback_counter);
7345 6 : }
7346 : // The point of this test is type checking. We run it only so compilers
7347 : // don't complain about an unused function.
7348 26644 : TEST(PersistentHandles) {
7349 5 : LocalContext env;
7350 5 : v8::Isolate* isolate = CcTest::isolate();
7351 10 : v8::HandleScope scope(isolate);
7352 5 : Local<String> str = v8_str("foo");
7353 : v8::Persistent<String> p_str(isolate, str);
7354 : p_str.Reset();
7355 : Local<Script> scr = v8_compile("");
7356 : v8::Persistent<Script> p_scr(isolate, scr);
7357 : p_scr.Reset();
7358 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7359 : v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7360 : p_templ.Reset();
7361 5 : }
7362 :
7363 :
7364 6 : static void HandleLogDelegator(
7365 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7366 6 : ApiTestFuzzer::Fuzz();
7367 6 : }
7368 :
7369 :
7370 26645 : THREADED_TEST(GlobalObjectTemplate) {
7371 6 : v8::Isolate* isolate = CcTest::isolate();
7372 12 : v8::HandleScope handle_scope(isolate);
7373 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7374 18 : global_template->Set(v8_str("JSNI_Log"),
7375 6 : v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7376 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
7377 : Context::Scope context_scope(context);
7378 : CompileRun("JSNI_Log('LOG')");
7379 6 : }
7380 :
7381 :
7382 : static const char* kSimpleExtensionSource =
7383 : "function Foo() {"
7384 : " return 4;"
7385 : "}";
7386 :
7387 :
7388 26644 : TEST(SimpleExtensions) {
7389 10 : v8::HandleScope handle_scope(CcTest::isolate());
7390 : v8::RegisterExtension(
7391 10 : v8::base::make_unique<Extension>("simpletest", kSimpleExtensionSource));
7392 5 : const char* extension_names[] = {"simpletest"};
7393 : v8::ExtensionConfiguration extensions(1, extension_names);
7394 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7395 : Context::Scope lock(context);
7396 : v8::Local<Value> result = CompileRun("Foo()");
7397 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7398 : .FromJust());
7399 5 : }
7400 :
7401 :
7402 : static const char* kStackTraceFromExtensionSource =
7403 : "function foo() {"
7404 : " throw new Error();"
7405 : "}"
7406 : "function bar() {"
7407 : " foo();"
7408 : "}";
7409 :
7410 :
7411 26644 : TEST(StackTraceInExtension) {
7412 10 : v8::HandleScope handle_scope(CcTest::isolate());
7413 10 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7414 5 : "stacktracetest", kStackTraceFromExtensionSource));
7415 5 : const char* extension_names[] = {"stacktracetest"};
7416 : v8::ExtensionConfiguration extensions(1, extension_names);
7417 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7418 : Context::Scope lock(context);
7419 : CompileRun(
7420 : "function user() { bar(); }"
7421 : "var error;"
7422 : "try{ user(); } catch (e) { error = e; }");
7423 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7424 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7425 5 : CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7426 5 : }
7427 :
7428 :
7429 26644 : TEST(NullExtensions) {
7430 10 : v8::HandleScope handle_scope(CcTest::isolate());
7431 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("nulltest", nullptr));
7432 5 : const char* extension_names[] = {"nulltest"};
7433 : v8::ExtensionConfiguration extensions(1, extension_names);
7434 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7435 : Context::Scope lock(context);
7436 : v8::Local<Value> result = CompileRun("1+3");
7437 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7438 : .FromJust());
7439 5 : }
7440 :
7441 : static const char* kEmbeddedExtensionSource =
7442 : "function Ret54321(){return 54321;}~~@@$"
7443 : "$%% THIS IS A SERIES OF NON-nullptr-TERMINATED STRINGS.";
7444 : static const int kEmbeddedExtensionSourceValidLen = 34;
7445 :
7446 :
7447 26644 : TEST(ExtensionMissingSourceLength) {
7448 10 : v8::HandleScope handle_scope(CcTest::isolate());
7449 10 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7450 5 : "srclentest_fail", kEmbeddedExtensionSource));
7451 5 : const char* extension_names[] = {"srclentest_fail"};
7452 : v8::ExtensionConfiguration extensions(1, extension_names);
7453 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7454 5 : CHECK_NULL(*context);
7455 5 : }
7456 :
7457 :
7458 26644 : TEST(ExtensionWithSourceLength) {
7459 20 : for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7460 20 : source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7461 30 : v8::HandleScope handle_scope(CcTest::isolate());
7462 : i::ScopedVector<char> extension_name(32);
7463 15 : i::SNPrintF(extension_name, "ext #%d", source_len);
7464 30 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7465 : extension_name.start(), kEmbeddedExtensionSource, 0, nullptr,
7466 15 : source_len));
7467 15 : const char* extension_names[1] = {extension_name.start()};
7468 : v8::ExtensionConfiguration extensions(1, extension_names);
7469 15 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7470 15 : if (source_len == kEmbeddedExtensionSourceValidLen) {
7471 : Context::Scope lock(context);
7472 5 : v8::Local<Value> result = CompileRun("Ret54321()");
7473 15 : CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7474 : ->Equals(context, result)
7475 : .FromJust());
7476 : } else {
7477 : // Anything but exactly the right length should fail to compile.
7478 10 : CHECK_NULL(*context);
7479 : }
7480 : }
7481 5 : }
7482 :
7483 :
7484 : static const char* kEvalExtensionSource1 =
7485 : "function UseEval1() {"
7486 : " var x = 42;"
7487 : " return eval('x');"
7488 : "}";
7489 :
7490 :
7491 : static const char* kEvalExtensionSource2 =
7492 : "(function() {"
7493 : " var x = 42;"
7494 : " function e() {"
7495 : " return eval('x');"
7496 : " }"
7497 : " this.UseEval2 = e;"
7498 : "})()";
7499 :
7500 :
7501 26644 : TEST(UseEvalFromExtension) {
7502 10 : v8::HandleScope handle_scope(CcTest::isolate());
7503 : v8::RegisterExtension(
7504 10 : v8::base::make_unique<Extension>("evaltest1", kEvalExtensionSource1));
7505 : v8::RegisterExtension(
7506 10 : v8::base::make_unique<Extension>("evaltest2", kEvalExtensionSource2));
7507 5 : const char* extension_names[] = {"evaltest1", "evaltest2"};
7508 : v8::ExtensionConfiguration extensions(2, extension_names);
7509 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7510 : Context::Scope lock(context);
7511 : v8::Local<Value> result = CompileRun("UseEval1()");
7512 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7513 : .FromJust());
7514 : result = CompileRun("UseEval2()");
7515 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7516 : .FromJust());
7517 5 : }
7518 :
7519 :
7520 : static const char* kWithExtensionSource1 =
7521 : "function UseWith1() {"
7522 : " var x = 42;"
7523 : " with({x:87}) { return x; }"
7524 : "}";
7525 :
7526 :
7527 : static const char* kWithExtensionSource2 =
7528 : "(function() {"
7529 : " var x = 42;"
7530 : " function e() {"
7531 : " with ({x:87}) { return x; }"
7532 : " }"
7533 : " this.UseWith2 = e;"
7534 : "})()";
7535 :
7536 :
7537 26644 : TEST(UseWithFromExtension) {
7538 10 : v8::HandleScope handle_scope(CcTest::isolate());
7539 : v8::RegisterExtension(
7540 10 : v8::base::make_unique<Extension>("withtest1", kWithExtensionSource1));
7541 : v8::RegisterExtension(
7542 10 : v8::base::make_unique<Extension>("withtest2", kWithExtensionSource2));
7543 5 : const char* extension_names[] = {"withtest1", "withtest2"};
7544 : v8::ExtensionConfiguration extensions(2, extension_names);
7545 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7546 : Context::Scope lock(context);
7547 : v8::Local<Value> result = CompileRun("UseWith1()");
7548 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7549 : .FromJust());
7550 : result = CompileRun("UseWith2()");
7551 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7552 : .FromJust());
7553 5 : }
7554 :
7555 :
7556 26644 : TEST(AutoExtensions) {
7557 10 : v8::HandleScope handle_scope(CcTest::isolate());
7558 : auto extension =
7559 5 : v8::base::make_unique<Extension>("autotest", kSimpleExtensionSource);
7560 : extension->set_auto_enable(true);
7561 10 : v8::RegisterExtension(std::move(extension));
7562 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
7563 : Context::Scope lock(context);
7564 : v8::Local<Value> result = CompileRun("Foo()");
7565 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7566 : .FromJust());
7567 5 : }
7568 :
7569 :
7570 : static const char* kSyntaxErrorInExtensionSource = "[";
7571 :
7572 :
7573 : // Test that a syntax error in an extension does not cause a fatal
7574 : // error but results in an empty context.
7575 26644 : TEST(SyntaxErrorExtensions) {
7576 10 : v8::HandleScope handle_scope(CcTest::isolate());
7577 10 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7578 5 : "syntaxerror", kSyntaxErrorInExtensionSource));
7579 5 : const char* extension_names[] = {"syntaxerror"};
7580 : v8::ExtensionConfiguration extensions(1, extension_names);
7581 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7582 5 : CHECK(context.IsEmpty());
7583 5 : }
7584 :
7585 :
7586 : static const char* kExceptionInExtensionSource = "throw 42";
7587 :
7588 :
7589 : // Test that an exception when installing an extension does not cause
7590 : // a fatal error but results in an empty context.
7591 26644 : TEST(ExceptionExtensions) {
7592 10 : v8::HandleScope handle_scope(CcTest::isolate());
7593 10 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7594 5 : "exception", kExceptionInExtensionSource));
7595 5 : const char* extension_names[] = {"exception"};
7596 : v8::ExtensionConfiguration extensions(1, extension_names);
7597 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7598 5 : CHECK(context.IsEmpty());
7599 5 : }
7600 :
7601 : static const char* kNativeCallInExtensionSource =
7602 : "function call_runtime_last_index_of(x) {"
7603 : " return %StringLastIndexOf(x, 'bob');"
7604 : "}";
7605 :
7606 : static const char* kNativeCallTest =
7607 : "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7608 :
7609 : // Test that a native runtime calls are supported in extensions.
7610 26644 : TEST(NativeCallInExtensions) {
7611 10 : v8::HandleScope handle_scope(CcTest::isolate());
7612 10 : v8::RegisterExtension(v8::base::make_unique<Extension>(
7613 5 : "nativecall", kNativeCallInExtensionSource));
7614 5 : const char* extension_names[] = {"nativecall"};
7615 : v8::ExtensionConfiguration extensions(1, extension_names);
7616 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7617 : Context::Scope lock(context);
7618 5 : v8::Local<Value> result = CompileRun(kNativeCallTest);
7619 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24))
7620 : .FromJust());
7621 5 : }
7622 :
7623 :
7624 30 : class NativeFunctionExtension : public Extension {
7625 : public:
7626 : NativeFunctionExtension(const char* name, const char* source,
7627 : v8::FunctionCallback fun = &Echo)
7628 15 : : Extension(name, source), function_(fun) {}
7629 :
7630 5 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7631 : v8::Isolate* isolate, v8::Local<v8::String> name) override {
7632 5 : return v8::FunctionTemplate::New(isolate, function_);
7633 : }
7634 :
7635 5 : static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7636 5 : if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7637 5 : }
7638 :
7639 : private:
7640 : v8::FunctionCallback function_;
7641 : };
7642 :
7643 :
7644 26644 : TEST(NativeFunctionDeclaration) {
7645 10 : v8::HandleScope handle_scope(CcTest::isolate());
7646 5 : const char* name = "nativedecl";
7647 15 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7648 5 : name, "native function foo();"));
7649 5 : const char* extension_names[] = {name};
7650 : v8::ExtensionConfiguration extensions(1, extension_names);
7651 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7652 : Context::Scope lock(context);
7653 : v8::Local<Value> result = CompileRun("foo(42);");
7654 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7655 : .FromJust());
7656 5 : }
7657 :
7658 :
7659 26644 : TEST(NativeFunctionDeclarationError) {
7660 10 : v8::HandleScope handle_scope(CcTest::isolate());
7661 5 : const char* name = "nativedeclerr";
7662 : // Syntax error in extension code.
7663 15 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7664 5 : name, "native\nfunction foo();"));
7665 5 : const char* extension_names[] = {name};
7666 : v8::ExtensionConfiguration extensions(1, extension_names);
7667 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7668 5 : CHECK(context.IsEmpty());
7669 5 : }
7670 :
7671 :
7672 26644 : TEST(NativeFunctionDeclarationErrorEscape) {
7673 10 : v8::HandleScope handle_scope(CcTest::isolate());
7674 5 : const char* name = "nativedeclerresc";
7675 : // Syntax error in extension code - escape code in "native" means that
7676 : // it's not treated as a keyword.
7677 15 : v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7678 5 : name, "nativ\\u0065 function foo();"));
7679 5 : const char* extension_names[] = {name};
7680 : v8::ExtensionConfiguration extensions(1, extension_names);
7681 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7682 5 : CHECK(context.IsEmpty());
7683 5 : }
7684 :
7685 :
7686 30 : static void CheckDependencies(const char* name, const char* expected) {
7687 60 : v8::HandleScope handle_scope(CcTest::isolate());
7688 : v8::ExtensionConfiguration config(1, &name);
7689 30 : LocalContext context(&config);
7690 180 : CHECK(
7691 : v8_str(expected)
7692 : ->Equals(context.local(), context->Global()
7693 : ->Get(context.local(), v8_str("loaded"))
7694 : .ToLocalChecked())
7695 : .FromJust());
7696 30 : }
7697 :
7698 :
7699 : /*
7700 : * Configuration:
7701 : *
7702 : * /-- B <--\
7703 : * A <- -- D <-- E
7704 : * \-- C <--/
7705 : */
7706 26645 : THREADED_TEST(ExtensionDependency) {
7707 : static const char* kEDeps[] = {"D"};
7708 : v8::RegisterExtension(
7709 12 : v8::base::make_unique<Extension>("E", "this.loaded += 'E';", 1, kEDeps));
7710 : static const char* kDDeps[] = {"B", "C"};
7711 : v8::RegisterExtension(
7712 12 : v8::base::make_unique<Extension>("D", "this.loaded += 'D';", 2, kDDeps));
7713 : static const char* kBCDeps[] = {"A"};
7714 : v8::RegisterExtension(
7715 12 : v8::base::make_unique<Extension>("B", "this.loaded += 'B';", 1, kBCDeps));
7716 : v8::RegisterExtension(
7717 12 : v8::base::make_unique<Extension>("C", "this.loaded += 'C';", 1, kBCDeps));
7718 : v8::RegisterExtension(
7719 12 : v8::base::make_unique<Extension>("A", "this.loaded += 'A';"));
7720 6 : CheckDependencies("A", "undefinedA");
7721 6 : CheckDependencies("B", "undefinedAB");
7722 6 : CheckDependencies("C", "undefinedAC");
7723 6 : CheckDependencies("D", "undefinedABCD");
7724 6 : CheckDependencies("E", "undefinedABCDE");
7725 12 : v8::HandleScope handle_scope(CcTest::isolate());
7726 : static const char* exts[2] = {"C", "E"};
7727 : v8::ExtensionConfiguration config(2, exts);
7728 6 : LocalContext context(&config);
7729 36 : CHECK(
7730 : v8_str("undefinedACBDE")
7731 : ->Equals(context.local(), context->Global()
7732 : ->Get(context.local(), v8_str("loaded"))
7733 : .ToLocalChecked())
7734 : .FromJust());
7735 6 : }
7736 :
7737 :
7738 : static const char* kExtensionTestScript =
7739 : "native function A();"
7740 : "native function B();"
7741 : "native function C();"
7742 : "function Foo(i) {"
7743 : " if (i == 0) return A();"
7744 : " if (i == 1) return B();"
7745 : " if (i == 2) return C();"
7746 : "}";
7747 :
7748 :
7749 198 : static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7750 198 : ApiTestFuzzer::Fuzz();
7751 198 : if (args.IsConstructCall()) {
7752 720 : CHECK(args.This()
7753 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7754 : args.Data())
7755 : .FromJust());
7756 : args.GetReturnValue().SetNull();
7757 180 : return;
7758 : }
7759 : args.GetReturnValue().Set(args.Data());
7760 : }
7761 :
7762 :
7763 24 : class FunctionExtension : public Extension {
7764 : public:
7765 12 : FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7766 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7767 : v8::Isolate* isolate, v8::Local<String> name) override;
7768 : };
7769 :
7770 :
7771 : static int lookup_count = 0;
7772 33 : v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7773 : v8::Isolate* isolate, v8::Local<String> name) {
7774 33 : lookup_count++;
7775 66 : if (name->StrictEquals(v8_str("A"))) {
7776 : return v8::FunctionTemplate::New(isolate, CallFun,
7777 22 : v8::Integer::New(isolate, 8));
7778 44 : } else if (name->StrictEquals(v8_str("B"))) {
7779 : return v8::FunctionTemplate::New(isolate, CallFun,
7780 22 : v8::Integer::New(isolate, 7));
7781 22 : } else if (name->StrictEquals(v8_str("C"))) {
7782 : return v8::FunctionTemplate::New(isolate, CallFun,
7783 22 : v8::Integer::New(isolate, 6));
7784 : } else {
7785 0 : return v8::Local<v8::FunctionTemplate>();
7786 : }
7787 : }
7788 :
7789 :
7790 26645 : THREADED_TEST(FunctionLookup) {
7791 24 : v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7792 12 : v8::HandleScope handle_scope(CcTest::isolate());
7793 : static const char* exts[1] = {"functiontest"};
7794 : v8::ExtensionConfiguration config(1, exts);
7795 6 : LocalContext context(&config);
7796 6 : CHECK_EQ(3, lookup_count);
7797 18 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7798 : ->Equals(context.local(), CompileRun("Foo(0)"))
7799 : .FromJust());
7800 18 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7801 : ->Equals(context.local(), CompileRun("Foo(1)"))
7802 : .FromJust());
7803 18 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7804 : ->Equals(context.local(), CompileRun("Foo(2)"))
7805 : .FromJust());
7806 6 : }
7807 :
7808 :
7809 26645 : THREADED_TEST(NativeFunctionConstructCall) {
7810 24 : v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7811 12 : v8::HandleScope handle_scope(CcTest::isolate());
7812 : static const char* exts[1] = {"functiontest"};
7813 : v8::ExtensionConfiguration config(1, exts);
7814 6 : LocalContext context(&config);
7815 126 : for (int i = 0; i < 10; i++) {
7816 : // Run a few times to ensure that allocation of objects doesn't
7817 : // change behavior of a constructor function.
7818 180 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7819 : ->Equals(context.local(), CompileRun("(new A()).data"))
7820 : .FromJust());
7821 180 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7822 : ->Equals(context.local(), CompileRun("(new B()).data"))
7823 : .FromJust());
7824 180 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7825 : ->Equals(context.local(), CompileRun("(new C()).data"))
7826 : .FromJust());
7827 : }
7828 6 : }
7829 :
7830 :
7831 : static const char* last_location;
7832 : static const char* last_message;
7833 10 : void StoringErrorCallback(const char* location, const char* message) {
7834 10 : if (last_location == nullptr) {
7835 10 : last_location = location;
7836 10 : last_message = message;
7837 : }
7838 10 : }
7839 :
7840 :
7841 : // ErrorReporting creates a circular extensions configuration and
7842 : // tests that the fatal error handler gets called. This renders V8
7843 : // unusable and therefore this test cannot be run in parallel.
7844 26644 : TEST(ErrorReporting) {
7845 5 : CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7846 : static const char* aDeps[] = {"B"};
7847 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("A", "", 1, aDeps));
7848 : static const char* bDeps[] = {"A"};
7849 10 : v8::RegisterExtension(v8::base::make_unique<Extension>("B", "", 1, bDeps));
7850 5 : last_location = nullptr;
7851 : v8::ExtensionConfiguration config(1, bDeps);
7852 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7853 5 : CHECK(context.IsEmpty());
7854 5 : CHECK(last_location);
7855 5 : }
7856 :
7857 : static size_t dcheck_count;
7858 0 : void DcheckErrorCallback(const char* file, int line, const char* message) {
7859 0 : last_message = message;
7860 0 : ++dcheck_count;
7861 0 : }
7862 :
7863 26644 : TEST(DcheckErrorHandler) {
7864 5 : V8::SetDcheckErrorHandler(DcheckErrorCallback);
7865 :
7866 5 : last_message = nullptr;
7867 5 : dcheck_count = 0;
7868 :
7869 : DCHECK(false && "w00t");
7870 : #ifdef DEBUG
7871 : CHECK_EQ(dcheck_count, 1);
7872 : CHECK(last_message);
7873 : CHECK(std::string(last_message).find("w00t") != std::string::npos);
7874 : #else
7875 : // The DCHECK should be a noop in non-DEBUG builds.
7876 : CHECK_EQ(dcheck_count, 0);
7877 : #endif
7878 5 : }
7879 :
7880 6 : static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7881 : v8::Local<Value> data) {
7882 6 : v8::Isolate* isolate = CcTest::isolate();
7883 6 : Local<Context> context = isolate->GetCurrentContext();
7884 12 : CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7885 18 : CHECK(v8::Undefined(isolate)
7886 : ->Equals(context, message->GetScriptOrigin().ResourceName())
7887 : .FromJust());
7888 12 : message->GetLineNumber(context).FromJust();
7889 6 : message->GetSourceLine(context).ToLocalChecked();
7890 6 : }
7891 :
7892 :
7893 26645 : THREADED_TEST(ErrorWithMissingScriptInfo) {
7894 6 : LocalContext context;
7895 12 : v8::HandleScope scope(context->GetIsolate());
7896 6 : context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7897 : CompileRun("throw Error()");
7898 6 : context->GetIsolate()->RemoveMessageListeners(
7899 6 : MissingScriptInfoMessageListener);
7900 6 : }
7901 :
7902 :
7903 88 : struct FlagAndPersistent {
7904 : bool flag;
7905 : v8::Global<v8::Object> handle;
7906 : };
7907 :
7908 40 : static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7909 40 : data.GetParameter()->flag = true;
7910 : data.GetParameter()->handle.Reset();
7911 40 : }
7912 :
7913 20 : static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7914 20 : i::FLAG_stress_incremental_marking = false;
7915 : // Parallel scavenge introduces too much fragmentation.
7916 20 : i::FLAG_parallel_scavenge = false;
7917 20 : v8::Isolate* iso = CcTest::isolate();
7918 40 : v8::HandleScope scope(iso);
7919 20 : v8::Local<Context> context = Context::New(iso);
7920 : Context::Scope context_scope(context);
7921 :
7922 : FlagAndPersistent object_a, object_b;
7923 :
7924 : size_t big_heap_size = 0;
7925 : size_t big_array_size = 0;
7926 :
7927 : {
7928 40 : v8::HandleScope handle_scope(iso);
7929 20 : Local<Object> a(v8::Object::New(iso));
7930 20 : Local<Object> b(v8::Object::New(iso));
7931 : object_a.handle.Reset(iso, a);
7932 : object_b.handle.Reset(iso, b);
7933 20 : if (interlinked) {
7934 30 : a->Set(context, v8_str("x"), b).FromJust();
7935 30 : b->Set(context, v8_str("x"), a).FromJust();
7936 : }
7937 20 : if (global_gc) {
7938 10 : CcTest::CollectAllGarbage();
7939 : } else {
7940 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7941 : }
7942 20 : v8::Local<Value> big_array = v8::Array::New(CcTest::isolate(), 5000);
7943 : // Verify that we created an array where the space was reserved up front.
7944 : big_array_size =
7945 : v8::internal::JSArray::cast(*v8::Utils::OpenHandle(*big_array))
7946 40 : ->elements()
7947 20 : ->Size();
7948 20 : CHECK_LE(20000, big_array_size);
7949 60 : a->Set(context, v8_str("y"), big_array).FromJust();
7950 20 : big_heap_size = CcTest::heap()->SizeOfObjects();
7951 : }
7952 :
7953 20 : object_a.flag = false;
7954 20 : object_b.flag = false;
7955 : object_a.handle.SetWeak(&object_a, &SetFlag,
7956 : v8::WeakCallbackType::kParameter);
7957 : object_b.handle.SetWeak(&object_b, &SetFlag,
7958 : v8::WeakCallbackType::kParameter);
7959 : #if __clang__
7960 : #pragma clang diagnostic push
7961 : #pragma clang diagnostic ignored "-Wdeprecated"
7962 : #endif
7963 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
7964 20 : CHECK(!object_b.handle.IsIndependent());
7965 : object_a.handle.MarkIndependent();
7966 : object_b.handle.MarkIndependent();
7967 20 : CHECK(object_b.handle.IsIndependent());
7968 : #if __clang__
7969 : #pragma clang diagnostic pop
7970 : #endif
7971 20 : if (global_gc) {
7972 10 : CcTest::CollectAllGarbage();
7973 : } else {
7974 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7975 : }
7976 : // A single GC should be enough to reclaim the memory, since we are using
7977 : // phantom handles.
7978 20 : CHECK_GT(big_heap_size - big_array_size, CcTest::heap()->SizeOfObjects());
7979 20 : CHECK(object_a.flag);
7980 20 : CHECK(object_b.flag);
7981 20 : }
7982 :
7983 26644 : TEST(IndependentWeakHandle) {
7984 5 : IndependentWeakHandle(false, false);
7985 5 : IndependentWeakHandle(false, true);
7986 5 : IndependentWeakHandle(true, false);
7987 5 : IndependentWeakHandle(true, true);
7988 5 : }
7989 :
7990 : class Trivial {
7991 : public:
7992 12 : explicit Trivial(int x) : x_(x) {}
7993 :
7994 36 : int x() { return x_; }
7995 12 : void set_x(int x) { x_ = x; }
7996 :
7997 : private:
7998 : int x_;
7999 : };
8000 :
8001 :
8002 : class Trivial2 {
8003 : public:
8004 12 : Trivial2(int x, int y) : y_(y), x_(x) {}
8005 :
8006 : int x() { return x_; }
8007 12 : void set_x(int x) { x_ = x; }
8008 :
8009 : int y() { return y_; }
8010 : void set_y(int y) { y_ = y; }
8011 :
8012 : private:
8013 : int y_;
8014 : int x_;
8015 : };
8016 :
8017 12 : void CheckInternalFields(
8018 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
8019 : v8::Persistent<v8::Object>* handle = data.GetParameter();
8020 : handle->Reset();
8021 : Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
8022 : Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
8023 12 : CHECK_EQ(42, t1->x());
8024 12 : CHECK_EQ(103, t2->x());
8025 : t1->set_x(1729);
8026 : t2->set_x(33550336);
8027 12 : }
8028 :
8029 12 : void InternalFieldCallback(bool global_gc) {
8030 12 : LocalContext env;
8031 12 : v8::Isolate* isolate = env->GetIsolate();
8032 24 : v8::HandleScope scope(isolate);
8033 :
8034 12 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
8035 12 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
8036 : Trivial* t1;
8037 : Trivial2* t2;
8038 12 : instance_templ->SetInternalFieldCount(2);
8039 : v8::Persistent<v8::Object> handle;
8040 : {
8041 24 : v8::HandleScope scope(isolate);
8042 12 : Local<v8::Object> obj = templ->GetFunction(env.local())
8043 : .ToLocalChecked()
8044 : ->NewInstance(env.local())
8045 : .ToLocalChecked();
8046 : handle.Reset(isolate, obj);
8047 12 : CHECK_EQ(2, obj->InternalFieldCount());
8048 12 : CHECK(obj->GetInternalField(0)->IsUndefined());
8049 12 : t1 = new Trivial(42);
8050 12 : t2 = new Trivial2(103, 9);
8051 :
8052 12 : obj->SetAlignedPointerInInternalField(0, t1);
8053 : t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
8054 12 : CHECK_EQ(42, t1->x());
8055 :
8056 12 : obj->SetAlignedPointerInInternalField(1, t2);
8057 : t2 =
8058 : reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
8059 12 : CHECK_EQ(103, t2->x());
8060 :
8061 : handle.SetWeak<v8::Persistent<v8::Object>>(
8062 : &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
8063 : }
8064 12 : if (global_gc) {
8065 6 : CcTest::CollectAllGarbage();
8066 : } else {
8067 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8068 : }
8069 :
8070 12 : CHECK_EQ(1729, t1->x());
8071 12 : CHECK_EQ(33550336, t2->x());
8072 :
8073 12 : delete t1;
8074 12 : delete t2;
8075 12 : }
8076 :
8077 26645 : THREADED_TEST(InternalFieldCallback) {
8078 6 : InternalFieldCallback(false);
8079 6 : InternalFieldCallback(true);
8080 6 : }
8081 :
8082 24 : static void ResetUseValueAndSetFlag(
8083 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8084 : // Blink will reset the handle, and then use the other handle, so they
8085 : // can't use the same backing slot.
8086 : data.GetParameter()->handle.Reset();
8087 24 : data.GetParameter()->flag = true;
8088 24 : }
8089 :
8090 12 : void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) {
8091 : using v8::Context;
8092 : using v8::Local;
8093 : using v8::Object;
8094 :
8095 12 : v8::Isolate* iso = CcTest::isolate();
8096 24 : v8::HandleScope scope(iso);
8097 12 : v8::Local<Context> context = Context::New(iso);
8098 : Context::Scope context_scope(context);
8099 :
8100 : FlagAndPersistent object_a, object_b;
8101 :
8102 : {
8103 24 : v8::HandleScope handle_scope(iso);
8104 12 : Local<Object> a(v8::Object::New(iso));
8105 12 : Local<Object> b(v8::Object::New(iso));
8106 : object_a.handle.Reset(iso, a);
8107 : object_b.handle.Reset(iso, b);
8108 12 : if (global_gc) {
8109 6 : CcTest::PreciseCollectAllGarbage();
8110 : } else {
8111 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8112 : }
8113 : }
8114 :
8115 12 : object_a.flag = false;
8116 12 : object_b.flag = false;
8117 : object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
8118 : v8::WeakCallbackType::kParameter);
8119 : object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
8120 : v8::WeakCallbackType::kParameter);
8121 12 : if (!global_gc) {
8122 : #if __clang__
8123 : #pragma clang diagnostic push
8124 : #pragma clang diagnostic ignored "-Wdeprecated"
8125 : #endif
8126 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
8127 : object_a.handle.MarkIndependent();
8128 : object_b.handle.MarkIndependent();
8129 6 : CHECK(object_b.handle.IsIndependent());
8130 : #if __clang__
8131 : #pragma clang diagnostic pop
8132 : #endif
8133 : }
8134 12 : if (global_gc) {
8135 6 : CcTest::PreciseCollectAllGarbage();
8136 : } else {
8137 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8138 : }
8139 12 : CHECK(object_a.flag);
8140 12 : CHECK(object_b.flag);
8141 12 : }
8142 :
8143 26645 : THREADED_HEAP_TEST(ResetWeakHandle) {
8144 6 : v8::internal::heap::HeapTester::ResetWeakHandle(false);
8145 6 : v8::internal::heap::HeapTester::ResetWeakHandle(true);
8146 6 : }
8147 :
8148 24 : static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
8149 :
8150 24 : static void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
8151 :
8152 12 : static void ForceScavenge2(
8153 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8154 12 : data.GetParameter()->flag = true;
8155 : InvokeScavenge();
8156 12 : }
8157 :
8158 12 : static void ForceScavenge1(
8159 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8160 : data.GetParameter()->handle.Reset();
8161 : data.SetSecondPassCallback(ForceScavenge2);
8162 12 : }
8163 :
8164 12 : static void ForceMarkSweep2(
8165 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8166 12 : data.GetParameter()->flag = true;
8167 : InvokeMarkSweep();
8168 12 : }
8169 :
8170 12 : static void ForceMarkSweep1(
8171 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8172 : data.GetParameter()->handle.Reset();
8173 : data.SetSecondPassCallback(ForceMarkSweep2);
8174 12 : }
8175 :
8176 26645 : THREADED_TEST(GCFromWeakCallbacks) {
8177 6 : v8::Isolate* isolate = CcTest::isolate();
8178 12 : v8::Locker locker(CcTest::isolate());
8179 12 : v8::HandleScope scope(isolate);
8180 6 : v8::Local<Context> context = Context::New(isolate);
8181 : Context::Scope context_scope(context);
8182 :
8183 : static const int kNumberOfGCTypes = 2;
8184 : typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
8185 : Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
8186 6 : &ForceMarkSweep1};
8187 :
8188 : typedef void (*GCInvoker)();
8189 6 : GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
8190 :
8191 30 : for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
8192 60 : for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
8193 : FlagAndPersistent object;
8194 : {
8195 48 : v8::HandleScope handle_scope(isolate);
8196 48 : object.handle.Reset(isolate, v8::Object::New(isolate));
8197 : }
8198 24 : object.flag = false;
8199 24 : object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
8200 : v8::WeakCallbackType::kParameter);
8201 : #if __clang__
8202 : #pragma clang diagnostic push
8203 : #pragma clang diagnostic ignored "-Wdeprecated"
8204 : #endif
8205 : // MarkIndependent is marked deprecated but we still rely on it
8206 : // temporarily.
8207 : object.handle.MarkIndependent();
8208 : #if __clang__
8209 : #pragma clang diagnostic pop
8210 : #endif
8211 24 : invoke_gc[outer_gc]();
8212 24 : EmptyMessageQueues(isolate);
8213 24 : CHECK(object.flag);
8214 : }
8215 : }
8216 6 : }
8217 :
8218 : v8::Local<Function> args_fun;
8219 :
8220 :
8221 6 : static void ArgumentsTestCallback(
8222 : const v8::FunctionCallbackInfo<v8::Value>& args) {
8223 6 : ApiTestFuzzer::Fuzz();
8224 : v8::Isolate* isolate = args.GetIsolate();
8225 6 : Local<Context> context = isolate->GetCurrentContext();
8226 6 : CHECK_EQ(3, args.Length());
8227 18 : CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
8228 18 : CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
8229 18 : CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
8230 12 : CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
8231 12 : v8::HandleScope scope(args.GetIsolate());
8232 6 : CcTest::CollectAllGarbage();
8233 6 : }
8234 :
8235 :
8236 26645 : THREADED_TEST(Arguments) {
8237 6 : v8::Isolate* isolate = CcTest::isolate();
8238 12 : v8::HandleScope scope(isolate);
8239 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8240 18 : global->Set(v8_str("f"),
8241 6 : v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8242 6 : LocalContext context(nullptr, global);
8243 12 : args_fun = context->Global()
8244 18 : ->Get(context.local(), v8_str("f"))
8245 : .ToLocalChecked()
8246 6 : .As<Function>();
8247 6 : v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
8248 6 : }
8249 :
8250 :
8251 : static int p_getter_count;
8252 : static int p_getter_count2;
8253 :
8254 :
8255 240 : static void PGetter(Local<Name> name,
8256 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8257 240 : ApiTestFuzzer::Fuzz();
8258 240 : p_getter_count++;
8259 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8260 240 : v8::Local<v8::Object> global = context->Global();
8261 960 : CHECK(
8262 : info.Holder()
8263 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8264 : .FromJust());
8265 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8266 240 : CHECK(info.This()
8267 : ->Equals(context,
8268 : global->Get(context, v8_str("o1")).ToLocalChecked())
8269 : .FromJust());
8270 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8271 240 : CHECK(info.This()
8272 : ->Equals(context,
8273 : global->Get(context, v8_str("o2")).ToLocalChecked())
8274 : .FromJust());
8275 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8276 240 : CHECK(info.This()
8277 : ->Equals(context,
8278 : global->Get(context, v8_str("o3")).ToLocalChecked())
8279 : .FromJust());
8280 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8281 240 : CHECK(info.This()
8282 : ->Equals(context,
8283 : global->Get(context, v8_str("o4")).ToLocalChecked())
8284 : .FromJust());
8285 : }
8286 240 : }
8287 :
8288 :
8289 12 : static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8290 12 : ApiTestFuzzer::Fuzz();
8291 12 : LocalContext context;
8292 60 : CHECK(context->Global()
8293 : ->Set(context.local(), v8_str("o1"),
8294 : obj->NewInstance(context.local()).ToLocalChecked())
8295 : .FromJust());
8296 : CompileRun(
8297 : "o1.__proto__ = { };"
8298 : "var o2 = { __proto__: o1 };"
8299 : "var o3 = { __proto__: o2 };"
8300 : "var o4 = { __proto__: o3 };"
8301 : "for (var i = 0; i < 10; i++) o4.p4;"
8302 : "for (var i = 0; i < 10; i++) o3.p3;"
8303 : "for (var i = 0; i < 10; i++) o2.p2;"
8304 : "for (var i = 0; i < 10; i++) o1.p1;");
8305 12 : }
8306 :
8307 :
8308 240 : static void PGetter2(Local<Name> name,
8309 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8310 240 : ApiTestFuzzer::Fuzz();
8311 240 : p_getter_count2++;
8312 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8313 240 : v8::Local<v8::Object> global = context->Global();
8314 960 : CHECK(
8315 : info.Holder()
8316 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8317 : .FromJust());
8318 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8319 240 : CHECK(info.This()
8320 : ->Equals(context,
8321 : global->Get(context, v8_str("o1")).ToLocalChecked())
8322 : .FromJust());
8323 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8324 240 : CHECK(info.This()
8325 : ->Equals(context,
8326 : global->Get(context, v8_str("o2")).ToLocalChecked())
8327 : .FromJust());
8328 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8329 240 : CHECK(info.This()
8330 : ->Equals(context,
8331 : global->Get(context, v8_str("o3")).ToLocalChecked())
8332 : .FromJust());
8333 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8334 240 : CHECK(info.This()
8335 : ->Equals(context,
8336 : global->Get(context, v8_str("o4")).ToLocalChecked())
8337 : .FromJust());
8338 : }
8339 240 : }
8340 :
8341 :
8342 26645 : THREADED_TEST(GetterHolders) {
8343 6 : v8::Isolate* isolate = CcTest::isolate();
8344 12 : v8::HandleScope scope(isolate);
8345 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8346 12 : obj->SetAccessor(v8_str("p1"), PGetter);
8347 12 : obj->SetAccessor(v8_str("p2"), PGetter);
8348 12 : obj->SetAccessor(v8_str("p3"), PGetter);
8349 12 : obj->SetAccessor(v8_str("p4"), PGetter);
8350 6 : p_getter_count = 0;
8351 6 : RunHolderTest(obj);
8352 6 : CHECK_EQ(40, p_getter_count);
8353 6 : }
8354 :
8355 :
8356 26645 : THREADED_TEST(PreInterceptorHolders) {
8357 6 : v8::Isolate* isolate = CcTest::isolate();
8358 12 : v8::HandleScope scope(isolate);
8359 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8360 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8361 6 : p_getter_count2 = 0;
8362 6 : RunHolderTest(obj);
8363 6 : CHECK_EQ(40, p_getter_count2);
8364 6 : }
8365 :
8366 :
8367 26645 : THREADED_TEST(ObjectInstantiation) {
8368 6 : v8::Isolate* isolate = CcTest::isolate();
8369 12 : v8::HandleScope scope(isolate);
8370 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8371 12 : templ->SetAccessor(v8_str("t"), PGetter2);
8372 6 : LocalContext context;
8373 30 : CHECK(context->Global()
8374 : ->Set(context.local(), v8_str("o"),
8375 : templ->NewInstance(context.local()).ToLocalChecked())
8376 : .FromJust());
8377 1206 : for (int i = 0; i < 100; i++) {
8378 1200 : v8::HandleScope inner_scope(CcTest::isolate());
8379 : v8::Local<v8::Object> obj =
8380 600 : templ->NewInstance(context.local()).ToLocalChecked();
8381 3000 : CHECK(!obj->Equals(context.local(), context->Global()
8382 : ->Get(context.local(), v8_str("o"))
8383 : .ToLocalChecked())
8384 : .FromJust());
8385 2400 : CHECK(
8386 : context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8387 600 : v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8388 1200 : CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8389 2400 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8390 : }
8391 6 : }
8392 :
8393 :
8394 : static int StrCmp16(uint16_t* a, uint16_t* b) {
8395 : while (true) {
8396 168 : if (*a == 0 && *b == 0) return 0;
8397 138 : if (*a != *b) return 0 + *a - *b;
8398 132 : a++;
8399 132 : b++;
8400 : }
8401 : }
8402 :
8403 :
8404 : static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8405 : while (true) {
8406 150 : if (n-- == 0) return 0;
8407 120 : if (*a == 0 && *b == 0) return 0;
8408 120 : if (*a != *b) return 0 + *a - *b;
8409 120 : a++;
8410 120 : b++;
8411 : }
8412 : }
8413 :
8414 552 : int GetUtf8Length(v8::Isolate* isolate, Local<String> str) {
8415 552 : int len = str->Utf8Length(isolate);
8416 552 : if (len < 0) {
8417 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8418 0 : i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8419 0 : i::String::Flatten(i_isolate, istr);
8420 0 : len = str->Utf8Length(isolate);
8421 : }
8422 552 : return len;
8423 : }
8424 :
8425 :
8426 26645 : THREADED_TEST(StringWrite) {
8427 6 : LocalContext context;
8428 6 : v8::Isolate* isolate = context->GetIsolate();
8429 12 : v8::HandleScope scope(isolate);
8430 6 : v8::Local<String> str = v8_str("abcde");
8431 : // abc<Icelandic eth><Unicode snowman>.
8432 6 : v8::Local<String> str2 = v8_str("abc\xC3\xB0\xE2\x98\x83");
8433 : v8::Local<String> str3 =
8434 6 : v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8435 6 : v8::NewStringType::kNormal, 7)
8436 : .ToLocalChecked();
8437 : // "ab" + lead surrogate + "wx" + trail surrogate + "yz"
8438 6 : uint16_t orphans[8] = {0x61, 0x62, 0xD800, 0x77, 0x78, 0xDC00, 0x79, 0x7A};
8439 : v8::Local<String> orphans_str =
8440 6 : v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8441 6 : v8::NewStringType::kNormal, 8)
8442 : .ToLocalChecked();
8443 : // single lead surrogate
8444 6 : uint16_t lead[1] = {0xD800};
8445 : v8::Local<String> lead_str =
8446 6 : v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8447 6 : v8::NewStringType::kNormal, 1)
8448 : .ToLocalChecked();
8449 : // single trail surrogate
8450 6 : uint16_t trail[1] = {0xDC00};
8451 : v8::Local<String> trail_str =
8452 6 : v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8453 6 : v8::NewStringType::kNormal, 1)
8454 : .ToLocalChecked();
8455 : // surrogate pair
8456 6 : uint16_t pair[2] = {0xD800, 0xDC00};
8457 : v8::Local<String> pair_str =
8458 6 : v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8459 6 : v8::NewStringType::kNormal, 2)
8460 : .ToLocalChecked();
8461 : const int kStride = 4; // Must match stride in for loops in JS below.
8462 : CompileRun(
8463 : "var left = '';"
8464 : "for (var i = 0; i < 0xD800; i += 4) {"
8465 : " left = left + String.fromCharCode(i);"
8466 : "}");
8467 : CompileRun(
8468 : "var right = '';"
8469 : "for (var i = 0; i < 0xD800; i += 4) {"
8470 : " right = String.fromCharCode(i) + right;"
8471 : "}");
8472 6 : v8::Local<v8::Object> global = context->Global();
8473 18 : Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8474 : .ToLocalChecked()
8475 : .As<String>();
8476 18 : Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8477 : .ToLocalChecked()
8478 : .As<String>();
8479 :
8480 6 : CHECK_EQ(5, str2->Length());
8481 6 : CHECK_EQ(0xD800 / kStride, left_tree->Length());
8482 6 : CHECK_EQ(0xD800 / kStride, right_tree->Length());
8483 :
8484 : char buf[100];
8485 : char utf8buf[0xD800 * 3];
8486 : uint16_t wbuf[100];
8487 : int len;
8488 : int charlen;
8489 :
8490 : memset(utf8buf, 0x1, 1000);
8491 : len = v8::String::Empty(isolate)->WriteUtf8(isolate, utf8buf, sizeof(utf8buf),
8492 6 : &charlen);
8493 6 : CHECK_EQ(1, len);
8494 6 : CHECK_EQ(0, charlen);
8495 6 : CHECK_EQ(0, strcmp(utf8buf, ""));
8496 :
8497 : memset(utf8buf, 0x1, 1000);
8498 6 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8499 6 : CHECK_EQ(9, len);
8500 6 : CHECK_EQ(5, charlen);
8501 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8502 :
8503 : memset(utf8buf, 0x1, 1000);
8504 6 : len = str2->WriteUtf8(isolate, utf8buf, 8, &charlen);
8505 6 : CHECK_EQ(8, len);
8506 6 : CHECK_EQ(5, charlen);
8507 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83\x01", 9));
8508 :
8509 : memset(utf8buf, 0x1, 1000);
8510 6 : len = str2->WriteUtf8(isolate, utf8buf, 7, &charlen);
8511 6 : CHECK_EQ(5, len);
8512 6 : CHECK_EQ(4, charlen);
8513 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8514 :
8515 : memset(utf8buf, 0x1, 1000);
8516 6 : len = str2->WriteUtf8(isolate, utf8buf, 6, &charlen);
8517 6 : CHECK_EQ(5, len);
8518 6 : CHECK_EQ(4, charlen);
8519 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8520 :
8521 : memset(utf8buf, 0x1, 1000);
8522 6 : len = str2->WriteUtf8(isolate, utf8buf, 5, &charlen);
8523 6 : CHECK_EQ(5, len);
8524 6 : CHECK_EQ(4, charlen);
8525 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8526 :
8527 : memset(utf8buf, 0x1, 1000);
8528 6 : len = str2->WriteUtf8(isolate, utf8buf, 4, &charlen);
8529 6 : CHECK_EQ(3, len);
8530 6 : CHECK_EQ(3, charlen);
8531 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8532 :
8533 : memset(utf8buf, 0x1, 1000);
8534 6 : len = str2->WriteUtf8(isolate, utf8buf, 3, &charlen);
8535 6 : CHECK_EQ(3, len);
8536 6 : CHECK_EQ(3, charlen);
8537 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8538 :
8539 : memset(utf8buf, 0x1, 1000);
8540 6 : len = str2->WriteUtf8(isolate, utf8buf, 2, &charlen);
8541 6 : CHECK_EQ(2, len);
8542 6 : CHECK_EQ(2, charlen);
8543 6 : CHECK_EQ(0, strncmp(utf8buf, "ab\x01", 3));
8544 :
8545 : // allow orphan surrogates by default
8546 : memset(utf8buf, 0x1, 1000);
8547 6 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8548 6 : CHECK_EQ(13, len);
8549 6 : CHECK_EQ(8, charlen);
8550 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xED\xA0\x80wx\xED\xB0\x80yz"));
8551 :
8552 : // replace orphan surrogates with Unicode replacement character
8553 : memset(utf8buf, 0x1, 1000);
8554 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8555 6 : String::REPLACE_INVALID_UTF8);
8556 6 : CHECK_EQ(13, len);
8557 6 : CHECK_EQ(8, charlen);
8558 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xEF\xBF\xBDwx\xEF\xBF\xBDyz"));
8559 :
8560 : // replace single lead surrogate with Unicode replacement character
8561 : memset(utf8buf, 0x1, 1000);
8562 : len = lead_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8563 6 : String::REPLACE_INVALID_UTF8);
8564 6 : CHECK_EQ(4, len);
8565 6 : CHECK_EQ(1, charlen);
8566 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8567 :
8568 : // replace single trail surrogate with Unicode replacement character
8569 : memset(utf8buf, 0x1, 1000);
8570 : len = trail_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8571 6 : String::REPLACE_INVALID_UTF8);
8572 6 : CHECK_EQ(4, len);
8573 6 : CHECK_EQ(1, charlen);
8574 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8575 :
8576 : // do not replace / write anything if surrogate pair does not fit the buffer
8577 : // space
8578 : memset(utf8buf, 0x1, 1000);
8579 : len = pair_str->WriteUtf8(isolate, utf8buf, 3, &charlen,
8580 6 : String::REPLACE_INVALID_UTF8);
8581 6 : CHECK_EQ(0, len);
8582 6 : CHECK_EQ(0, charlen);
8583 :
8584 : memset(utf8buf, 0x1, sizeof(utf8buf));
8585 6 : len = GetUtf8Length(isolate, left_tree);
8586 : int utf8_expected =
8587 : (0x80 + (0x800 - 0x80) * 2 + (0xD800 - 0x800) * 3) / kStride;
8588 6 : CHECK_EQ(utf8_expected, len);
8589 6 : len = left_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8590 6 : CHECK_EQ(utf8_expected, len);
8591 6 : CHECK_EQ(0xD800 / kStride, charlen);
8592 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8593 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8594 12 : CHECK_EQ(0xC0 - kStride,
8595 : static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8596 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8597 :
8598 : memset(utf8buf, 0x1, sizeof(utf8buf));
8599 6 : len = GetUtf8Length(isolate, right_tree);
8600 6 : CHECK_EQ(utf8_expected, len);
8601 6 : len = right_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8602 6 : CHECK_EQ(utf8_expected, len);
8603 6 : CHECK_EQ(0xD800 / kStride, charlen);
8604 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[0]));
8605 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[1]));
8606 12 : CHECK_EQ(0xC0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8607 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8608 :
8609 : memset(buf, 0x1, sizeof(buf));
8610 : memset(wbuf, 0x1, sizeof(wbuf));
8611 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8612 6 : CHECK_EQ(5, len);
8613 6 : len = str->Write(isolate, wbuf);
8614 6 : CHECK_EQ(5, len);
8615 6 : CHECK_EQ(0, strcmp("abcde", buf));
8616 6 : uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8617 6 : CHECK_EQ(0, StrCmp16(answer1, wbuf));
8618 :
8619 : memset(buf, 0x1, sizeof(buf));
8620 : memset(wbuf, 0x1, sizeof(wbuf));
8621 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 4);
8622 6 : CHECK_EQ(4, len);
8623 6 : len = str->Write(isolate, wbuf, 0, 4);
8624 6 : CHECK_EQ(4, len);
8625 6 : CHECK_EQ(0, strncmp("abcd\x01", buf, 5));
8626 6 : uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8627 6 : CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8628 :
8629 : memset(buf, 0x1, sizeof(buf));
8630 : memset(wbuf, 0x1, sizeof(wbuf));
8631 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 5);
8632 6 : CHECK_EQ(5, len);
8633 6 : len = str->Write(isolate, wbuf, 0, 5);
8634 6 : CHECK_EQ(5, len);
8635 6 : CHECK_EQ(0, strncmp("abcde\x01", buf, 6));
8636 6 : uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8637 6 : CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8638 :
8639 : memset(buf, 0x1, sizeof(buf));
8640 : memset(wbuf, 0x1, sizeof(wbuf));
8641 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6);
8642 6 : CHECK_EQ(5, len);
8643 6 : len = str->Write(isolate, wbuf, 0, 6);
8644 6 : CHECK_EQ(5, len);
8645 6 : CHECK_EQ(0, strcmp("abcde", buf));
8646 6 : uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8647 6 : CHECK_EQ(0, StrCmp16(answer4, wbuf));
8648 :
8649 : memset(buf, 0x1, sizeof(buf));
8650 : memset(wbuf, 0x1, sizeof(wbuf));
8651 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, -1);
8652 6 : CHECK_EQ(1, len);
8653 6 : len = str->Write(isolate, wbuf, 4, -1);
8654 6 : CHECK_EQ(1, len);
8655 6 : CHECK_EQ(0, strcmp("e", buf));
8656 6 : uint16_t answer5[] = {'e', '\0'};
8657 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8658 :
8659 : memset(buf, 0x1, sizeof(buf));
8660 : memset(wbuf, 0x1, sizeof(wbuf));
8661 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 6);
8662 6 : CHECK_EQ(1, len);
8663 6 : len = str->Write(isolate, wbuf, 4, 6);
8664 6 : CHECK_EQ(1, len);
8665 6 : CHECK_EQ(0, strcmp("e", buf));
8666 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8667 :
8668 : memset(buf, 0x1, sizeof(buf));
8669 : memset(wbuf, 0x1, sizeof(wbuf));
8670 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 1);
8671 6 : CHECK_EQ(1, len);
8672 6 : len = str->Write(isolate, wbuf, 4, 1);
8673 6 : CHECK_EQ(1, len);
8674 6 : CHECK_EQ(0, strncmp("e\x01", buf, 2));
8675 6 : uint16_t answer6[] = {'e', 0x101};
8676 6 : CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8677 :
8678 : memset(buf, 0x1, sizeof(buf));
8679 : memset(wbuf, 0x1, sizeof(wbuf));
8680 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 3, 1);
8681 6 : CHECK_EQ(1, len);
8682 6 : len = str->Write(isolate, wbuf, 3, 1);
8683 6 : CHECK_EQ(1, len);
8684 6 : CHECK_EQ(0, strncmp("d\x01", buf, 2));
8685 6 : uint16_t answer7[] = {'d', 0x101};
8686 6 : CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8687 :
8688 : memset(wbuf, 0x1, sizeof(wbuf));
8689 6 : wbuf[5] = 'X';
8690 6 : len = str->Write(isolate, wbuf, 0, 6, String::NO_NULL_TERMINATION);
8691 6 : CHECK_EQ(5, len);
8692 12 : CHECK_EQ('X', wbuf[5]);
8693 6 : uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8694 6 : uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8695 6 : CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8696 6 : CHECK_NE(0, StrCmp16(answer8b, wbuf));
8697 6 : wbuf[5] = '\0';
8698 6 : CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8699 :
8700 : memset(buf, 0x1, sizeof(buf));
8701 6 : buf[5] = 'X';
8702 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6,
8703 6 : String::NO_NULL_TERMINATION);
8704 6 : CHECK_EQ(5, len);
8705 6 : CHECK_EQ('X', buf[5]);
8706 6 : CHECK_EQ(0, strncmp("abcde", buf, 5));
8707 6 : CHECK_NE(0, strcmp("abcde", buf));
8708 6 : buf[5] = '\0';
8709 6 : CHECK_EQ(0, strcmp("abcde", buf));
8710 :
8711 : memset(utf8buf, 0x1, sizeof(utf8buf));
8712 6 : utf8buf[8] = 'X';
8713 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8714 6 : String::NO_NULL_TERMINATION);
8715 6 : CHECK_EQ(8, len);
8716 6 : CHECK_EQ('X', utf8buf[8]);
8717 6 : CHECK_EQ(5, charlen);
8718 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83", 8));
8719 6 : CHECK_NE(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8720 6 : utf8buf[8] = '\0';
8721 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8722 :
8723 : memset(utf8buf, 0x1, sizeof(utf8buf));
8724 6 : utf8buf[5] = 'X';
8725 : len = str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8726 6 : String::NO_NULL_TERMINATION);
8727 6 : CHECK_EQ(5, len);
8728 6 : CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8729 6 : CHECK_EQ(5, charlen);
8730 6 : utf8buf[5] = '\0';
8731 6 : CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8732 :
8733 : memset(buf, 0x1, sizeof(buf));
8734 6 : len = str3->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8735 6 : CHECK_EQ(7, len);
8736 6 : CHECK_EQ(0, strcmp("abc", buf));
8737 6 : CHECK_EQ(0, buf[3]);
8738 6 : CHECK_EQ(0, strcmp("def", buf + 4));
8739 :
8740 6 : CHECK_EQ(0, str->WriteOneByte(isolate, nullptr, 0, 0,
8741 : String::NO_NULL_TERMINATION));
8742 6 : CHECK_EQ(0, str->WriteUtf8(isolate, nullptr, 0, nullptr,
8743 : String::NO_NULL_TERMINATION));
8744 6 : CHECK_EQ(0, str->Write(isolate, nullptr, 0, 0, String::NO_NULL_TERMINATION));
8745 6 : }
8746 :
8747 :
8748 12 : static void Utf16Helper(
8749 : LocalContext& context, // NOLINT
8750 : const char* name,
8751 : const char* lengths_name,
8752 : int len) {
8753 : Local<v8::Array> a = Local<v8::Array>::Cast(
8754 48 : context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8755 : Local<v8::Array> alens =
8756 24 : Local<v8::Array>::Cast(context->Global()
8757 36 : ->Get(context.local(), v8_str(lengths_name))
8758 : .ToLocalChecked());
8759 1092 : for (int i = 0; i < len; i++) {
8760 : Local<v8::String> string =
8761 1620 : Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8762 : Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8763 540 : alens->Get(context.local(), i).ToLocalChecked());
8764 540 : int length = GetUtf8Length(context->GetIsolate(), string);
8765 540 : CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8766 : }
8767 12 : }
8768 :
8769 6 : void TestUtf8DecodingAgainstReference(
8770 : v8::Isolate* isolate, const char* cases[],
8771 : const std::vector<std::vector<uint16_t>>& unicode_expected) {
8772 126 : for (size_t test_ix = 0; test_ix < unicode_expected.size(); ++test_ix) {
8773 60 : v8::Local<String> str = v8_str(cases[test_ix]);
8774 120 : CHECK_EQ(unicode_expected[test_ix].size(), str->Length());
8775 :
8776 60 : std::unique_ptr<uint16_t[]> buffer(new uint16_t[str->Length()]);
8777 60 : str->Write(isolate, buffer.get(), 0, -1, String::NO_NULL_TERMINATION);
8778 :
8779 636 : for (size_t i = 0; i < unicode_expected[test_ix].size(); ++i) {
8780 576 : CHECK_EQ(unicode_expected[test_ix][i], buffer[i]);
8781 : }
8782 : }
8783 6 : }
8784 :
8785 26645 : THREADED_TEST(OverlongSequencesAndSurrogates) {
8786 6 : LocalContext context;
8787 12 : v8::HandleScope scope(context->GetIsolate());
8788 :
8789 : const char* cases[] = {
8790 : // Overlong 2-byte sequence.
8791 : "X\xc0\xbfY\0",
8792 : // Another overlong 2-byte sequence.
8793 : "X\xc1\xbfY\0",
8794 : // Overlong 3-byte sequence.
8795 : "X\xe0\x9f\xbfY\0",
8796 : // Overlong 4-byte sequence.
8797 : "X\xf0\x89\xbf\xbfY\0",
8798 : // Invalid 3-byte sequence (reserved for surrogates).
8799 : "X\xed\xa0\x80Y\0",
8800 : // Invalid 4-bytes sequence (value out of range).
8801 : "X\xf4\x90\x80\x80Y\0",
8802 :
8803 : // Start of an overlong 3-byte sequence but not enough continuation bytes.
8804 : "X\xe0\x9fY\0",
8805 : // Start of an overlong 4-byte sequence but not enough continuation bytes.
8806 : "X\xf0\x89\xbfY\0",
8807 : // Start of an invalid 3-byte sequence (reserved for surrogates) but not
8808 : // enough continuation bytes.
8809 : "X\xed\xa0Y\0",
8810 : // Start of an invalid 4-bytes sequence (value out of range) but not
8811 : // enough continuation bytes.
8812 : "X\xf4\x90\x80Y\0",
8813 6 : };
8814 : const std::vector<std::vector<uint16_t>> unicode_expected = {
8815 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8816 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8817 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8818 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8819 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8820 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8821 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8822 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8823 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8824 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8825 12 : };
8826 6 : CHECK_EQ(unicode_expected.size(), arraysize(cases));
8827 6 : TestUtf8DecodingAgainstReference(context->GetIsolate(), cases,
8828 6 : unicode_expected);
8829 6 : }
8830 :
8831 26645 : THREADED_TEST(Utf16) {
8832 6 : LocalContext context;
8833 12 : v8::HandleScope scope(context->GetIsolate());
8834 : CompileRun(
8835 : "var pad = '01234567890123456789';"
8836 : "var p = [];"
8837 : "var plens = [20, 3, 3];"
8838 : "p.push('01234567890123456789');"
8839 : "var lead = 0xD800;"
8840 : "var trail = 0xDC00;"
8841 : "p.push(String.fromCharCode(0xD800));"
8842 : "p.push(String.fromCharCode(0xDC00));"
8843 : "var a = [];"
8844 : "var b = [];"
8845 : "var c = [];"
8846 : "var alens = [];"
8847 : "for (var i = 0; i < 3; i++) {"
8848 : " p[1] = String.fromCharCode(lead++);"
8849 : " for (var j = 0; j < 3; j++) {"
8850 : " p[2] = String.fromCharCode(trail++);"
8851 : " a.push(p[i] + p[j]);"
8852 : " b.push(p[i] + p[j]);"
8853 : " c.push(p[i] + p[j]);"
8854 : " alens.push(plens[i] + plens[j]);"
8855 : " }"
8856 : "}"
8857 : "alens[5] -= 2;" // Here the surrogate pairs match up.
8858 : "var a2 = [];"
8859 : "var b2 = [];"
8860 : "var c2 = [];"
8861 : "var a2lens = [];"
8862 : "for (var m = 0; m < 9; m++) {"
8863 : " for (var n = 0; n < 9; n++) {"
8864 : " a2.push(a[m] + a[n]);"
8865 : " b2.push(b[m] + b[n]);"
8866 : " var newc = 'x' + c[m] + c[n] + 'y';"
8867 : " c2.push(newc.substring(1, newc.length - 1));"
8868 : " var utf = alens[m] + alens[n];" // And here.
8869 : // The 'n's that start with 0xDC..
8870 : // are 6-8 The 'm's that end with
8871 : // 0xD8.. are 1, 4 and 7
8872 : " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8873 : " a2lens.push(utf);"
8874 : " }"
8875 : "}");
8876 6 : Utf16Helper(context, "a", "alens", 9);
8877 6 : Utf16Helper(context, "a2", "a2lens", 81);
8878 6 : }
8879 :
8880 :
8881 : static bool SameSymbol(Local<String> s1, Local<String> s2) {
8882 : i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8883 : i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8884 : return *is1 == *is2;
8885 : }
8886 :
8887 :
8888 26645 : THREADED_TEST(Utf16Symbol) {
8889 6 : LocalContext context;
8890 12 : v8::HandleScope scope(context->GetIsolate());
8891 :
8892 : Local<String> symbol1 =
8893 6 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8894 6 : v8::NewStringType::kInternalized)
8895 : .ToLocalChecked();
8896 : Local<String> symbol2 =
8897 6 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8898 6 : v8::NewStringType::kInternalized)
8899 : .ToLocalChecked();
8900 6 : CHECK(SameSymbol(symbol1, symbol2));
8901 :
8902 : CompileRun(
8903 : "var sym0 = 'benedictus';"
8904 : "var sym0b = 'S\xC3\xB8ren';"
8905 : "var sym1 = '\xED\xA0\x81\xED\xB0\x87';"
8906 : "var sym2 = '\xF0\x90\x90\x88';"
8907 : "var sym3 = 'x\xED\xA0\x81\xED\xB0\x87';"
8908 : "var sym4 = 'x\xF0\x90\x90\x88';"
8909 : "if (sym1.length != 2) throw sym1;"
8910 : "if (sym1.charCodeAt(1) != 0xDC07) throw sym1.charCodeAt(1);"
8911 : "if (sym2.length != 2) throw sym2;"
8912 : "if (sym2.charCodeAt(1) != 0xDC08) throw sym2.charCodeAt(2);"
8913 : "if (sym3.length != 3) throw sym3;"
8914 : "if (sym3.charCodeAt(2) != 0xDC07) throw sym1.charCodeAt(2);"
8915 : "if (sym4.length != 3) throw sym4;"
8916 : "if (sym4.charCodeAt(2) != 0xDC08) throw sym2.charCodeAt(2);");
8917 : Local<String> sym0 =
8918 6 : v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8919 6 : v8::NewStringType::kInternalized)
8920 : .ToLocalChecked();
8921 : Local<String> sym0b =
8922 6 : v8::String::NewFromUtf8(context->GetIsolate(), "S\xC3\xB8ren",
8923 6 : v8::NewStringType::kInternalized)
8924 : .ToLocalChecked();
8925 : Local<String> sym1 =
8926 6 : v8::String::NewFromUtf8(context->GetIsolate(), "\xED\xA0\x81\xED\xB0\x87",
8927 6 : v8::NewStringType::kInternalized)
8928 : .ToLocalChecked();
8929 : Local<String> sym2 =
8930 6 : v8::String::NewFromUtf8(context->GetIsolate(), "\xF0\x90\x90\x88",
8931 6 : v8::NewStringType::kInternalized)
8932 : .ToLocalChecked();
8933 6 : Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8934 : "x\xED\xA0\x81\xED\xB0\x87",
8935 6 : v8::NewStringType::kInternalized)
8936 : .ToLocalChecked();
8937 : Local<String> sym4 =
8938 6 : v8::String::NewFromUtf8(context->GetIsolate(), "x\xF0\x90\x90\x88",
8939 6 : v8::NewStringType::kInternalized)
8940 : .ToLocalChecked();
8941 6 : v8::Local<v8::Object> global = context->Global();
8942 : Local<Value> s0 =
8943 18 : global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8944 : Local<Value> s0b =
8945 18 : global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8946 : Local<Value> s1 =
8947 18 : global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8948 : Local<Value> s2 =
8949 18 : global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8950 : Local<Value> s3 =
8951 18 : global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8952 : Local<Value> s4 =
8953 18 : global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8954 6 : CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8955 6 : CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8956 6 : CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8957 6 : CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8958 6 : CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8959 6 : CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8960 6 : }
8961 :
8962 :
8963 26645 : THREADED_TEST(Utf16MissingTrailing) {
8964 6 : LocalContext context;
8965 12 : v8::HandleScope scope(context->GetIsolate());
8966 :
8967 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8968 : int size = 1024 * 64;
8969 6 : uint8_t* buffer = new uint8_t[size];
8970 196614 : for (int i = 0; i < size; i += 4) {
8971 98304 : buffer[i] = 0xF0;
8972 98304 : buffer[i + 1] = 0x9D;
8973 98304 : buffer[i + 2] = 0x80;
8974 98304 : buffer[i + 3] = 0x9E;
8975 : }
8976 :
8977 : // Now invoke the decoder without last 3 bytes
8978 : v8::Local<v8::String> str =
8979 6 : v8::String::NewFromUtf8(
8980 : context->GetIsolate(), reinterpret_cast<char*>(buffer),
8981 6 : v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8982 : USE(str);
8983 6 : delete[] buffer;
8984 6 : }
8985 :
8986 :
8987 26645 : THREADED_TEST(Utf16Trailing3Byte) {
8988 6 : LocalContext context;
8989 6 : v8::Isolate* isolate = context->GetIsolate();
8990 12 : v8::HandleScope scope(isolate);
8991 :
8992 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8993 : int size = 1024 * 63;
8994 6 : uint8_t* buffer = new uint8_t[size];
8995 258054 : for (int i = 0; i < size; i += 3) {
8996 129024 : buffer[i] = 0xE2;
8997 129024 : buffer[i + 1] = 0x80;
8998 129024 : buffer[i + 2] = 0xA6;
8999 : }
9000 :
9001 : // Now invoke the decoder without last 3 bytes
9002 : v8::Local<v8::String> str =
9003 6 : v8::String::NewFromUtf8(isolate, reinterpret_cast<char*>(buffer),
9004 : v8::NewStringType::kNormal, size)
9005 : .ToLocalChecked();
9006 :
9007 12 : v8::String::Value value(isolate, str);
9008 6 : CHECK_EQ(value.length(), size / 3);
9009 12 : CHECK_EQ((*value)[value.length() - 1], 0x2026);
9010 :
9011 6 : delete[] buffer;
9012 6 : }
9013 :
9014 :
9015 26645 : THREADED_TEST(ToArrayIndex) {
9016 6 : LocalContext context;
9017 6 : v8::Isolate* isolate = context->GetIsolate();
9018 12 : v8::HandleScope scope(isolate);
9019 :
9020 6 : v8::Local<String> str = v8_str("42");
9021 6 : v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
9022 6 : CHECK(!index.IsEmpty());
9023 12 : CHECK_EQ(42.0,
9024 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9025 6 : str = v8_str("42asdf");
9026 6 : index = str->ToArrayIndex(context.local());
9027 6 : CHECK(index.IsEmpty());
9028 6 : str = v8_str("-42");
9029 6 : index = str->ToArrayIndex(context.local());
9030 6 : CHECK(index.IsEmpty());
9031 6 : str = v8_str("4294967294");
9032 6 : index = str->ToArrayIndex(context.local());
9033 6 : CHECK(!index.IsEmpty());
9034 12 : CHECK_EQ(4294967294.0,
9035 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9036 6 : v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
9037 6 : index = num->ToArrayIndex(context.local());
9038 6 : CHECK(!index.IsEmpty());
9039 12 : CHECK_EQ(1.0,
9040 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9041 6 : num = v8::Number::New(isolate, -1);
9042 6 : index = num->ToArrayIndex(context.local());
9043 6 : CHECK(index.IsEmpty());
9044 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
9045 6 : index = obj->ToArrayIndex(context.local());
9046 6 : CHECK(index.IsEmpty());
9047 6 : }
9048 :
9049 6 : static v8::MaybeLocal<Value> PrepareStackTrace42(v8::Local<Context> context,
9050 : v8::Local<Value> error,
9051 : v8::Local<Array> trace) {
9052 6 : return v8::Number::New(context->GetIsolate(), 42);
9053 : }
9054 :
9055 6 : static v8::MaybeLocal<Value> PrepareStackTraceThrow(v8::Local<Context> context,
9056 : v8::Local<Value> error,
9057 : v8::Local<Array> trace) {
9058 6 : v8::Isolate* isolate = context->GetIsolate();
9059 6 : v8::Local<String> message = v8_str("42");
9060 6 : isolate->ThrowException(v8::Exception::Error(message));
9061 6 : return v8::MaybeLocal<Value>();
9062 : }
9063 :
9064 26645 : THREADED_TEST(IsolatePrepareStackTrace) {
9065 6 : LocalContext context;
9066 6 : v8::Isolate* isolate = context->GetIsolate();
9067 12 : v8::HandleScope scope(isolate);
9068 :
9069 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTrace42);
9070 :
9071 : v8::Local<Value> v = CompileRun("new Error().stack");
9072 :
9073 6 : CHECK(v->IsNumber());
9074 12 : CHECK_EQ(v.As<v8::Number>()->Int32Value(context.local()).FromJust(), 42);
9075 6 : }
9076 :
9077 26645 : THREADED_TEST(IsolatePrepareStackTraceThrow) {
9078 6 : LocalContext context;
9079 6 : v8::Isolate* isolate = context->GetIsolate();
9080 12 : v8::HandleScope scope(isolate);
9081 :
9082 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTraceThrow);
9083 :
9084 : v8::Local<Value> v = CompileRun("try { new Error().stack } catch (e) { e }");
9085 :
9086 6 : CHECK(v->IsNativeError());
9087 :
9088 12 : v8::Local<String> message = v8::Exception::CreateMessage(isolate, v)->Get();
9089 :
9090 12 : CHECK(message->StrictEquals(v8_str("Uncaught Error: 42")));
9091 6 : }
9092 :
9093 26645 : THREADED_TEST(ErrorConstruction) {
9094 6 : LocalContext context;
9095 12 : v8::HandleScope scope(context->GetIsolate());
9096 :
9097 6 : v8::Local<String> foo = v8_str("foo");
9098 6 : v8::Local<String> message = v8_str("message");
9099 6 : v8::Local<Value> range_error = v8::Exception::RangeError(foo);
9100 6 : CHECK(range_error->IsObject());
9101 18 : CHECK(range_error.As<v8::Object>()
9102 : ->Get(context.local(), message)
9103 : .ToLocalChecked()
9104 : ->Equals(context.local(), foo)
9105 : .FromJust());
9106 6 : v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
9107 6 : CHECK(reference_error->IsObject());
9108 18 : CHECK(reference_error.As<v8::Object>()
9109 : ->Get(context.local(), message)
9110 : .ToLocalChecked()
9111 : ->Equals(context.local(), foo)
9112 : .FromJust());
9113 6 : v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
9114 6 : CHECK(syntax_error->IsObject());
9115 18 : CHECK(syntax_error.As<v8::Object>()
9116 : ->Get(context.local(), message)
9117 : .ToLocalChecked()
9118 : ->Equals(context.local(), foo)
9119 : .FromJust());
9120 6 : v8::Local<Value> type_error = v8::Exception::TypeError(foo);
9121 6 : CHECK(type_error->IsObject());
9122 18 : CHECK(type_error.As<v8::Object>()
9123 : ->Get(context.local(), message)
9124 : .ToLocalChecked()
9125 : ->Equals(context.local(), foo)
9126 : .FromJust());
9127 6 : v8::Local<Value> error = v8::Exception::Error(foo);
9128 6 : CHECK(error->IsObject());
9129 18 : CHECK(error.As<v8::Object>()
9130 : ->Get(context.local(), message)
9131 : .ToLocalChecked()
9132 : ->Equals(context.local(), foo)
9133 : .FromJust());
9134 6 : }
9135 :
9136 :
9137 12 : static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
9138 12 : ApiTestFuzzer::Fuzz();
9139 12 : v8::Local<String> foo = v8_str("foo");
9140 12 : v8::Local<String> message = v8_str("message");
9141 12 : v8::Local<Value> error = v8::Exception::Error(foo);
9142 12 : CHECK(error->IsObject());
9143 12 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9144 36 : CHECK(error.As<v8::Object>()
9145 : ->Get(context, message)
9146 : .ToLocalChecked()
9147 : ->Equals(context, foo)
9148 : .FromJust());
9149 12 : info.GetIsolate()->ThrowException(error);
9150 : info.GetReturnValue().SetUndefined();
9151 12 : }
9152 :
9153 :
9154 26645 : THREADED_TEST(ExceptionCreateMessage) {
9155 6 : LocalContext context;
9156 12 : v8::HandleScope scope(context->GetIsolate());
9157 6 : v8::Local<String> foo_str = v8_str("foo");
9158 6 : v8::Local<String> message_str = v8_str("message");
9159 :
9160 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
9161 :
9162 : Local<v8::FunctionTemplate> fun =
9163 6 : v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
9164 6 : v8::Local<v8::Object> global = context->Global();
9165 24 : CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
9166 : fun->GetFunction(context.local()).ToLocalChecked())
9167 : .FromJust());
9168 :
9169 12 : TryCatch try_catch(context->GetIsolate());
9170 : CompileRun(
9171 : "function f1() {\n"
9172 : " throwV8Exception();\n"
9173 : "};\n"
9174 : "f1();");
9175 6 : CHECK(try_catch.HasCaught());
9176 :
9177 6 : v8::Local<v8::Value> error = try_catch.Exception();
9178 6 : CHECK(error->IsObject());
9179 18 : CHECK(error.As<v8::Object>()
9180 : ->Get(context.local(), message_str)
9181 : .ToLocalChecked()
9182 : ->Equals(context.local(), foo_str)
9183 : .FromJust());
9184 :
9185 : v8::Local<v8::Message> message =
9186 6 : v8::Exception::CreateMessage(context->GetIsolate(), error);
9187 6 : CHECK(!message.IsEmpty());
9188 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9189 12 : CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
9190 :
9191 6 : v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
9192 6 : CHECK(!stackTrace.IsEmpty());
9193 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9194 :
9195 6 : stackTrace = v8::Exception::GetStackTrace(error);
9196 6 : CHECK(!stackTrace.IsEmpty());
9197 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9198 :
9199 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
9200 :
9201 : // Now check message location when SetCaptureStackTraceForUncaughtExceptions
9202 : // is false.
9203 6 : try_catch.Reset();
9204 :
9205 : CompileRun(
9206 : "function f2() {\n"
9207 : " return throwV8Exception();\n"
9208 : "};\n"
9209 : "f2();");
9210 6 : CHECK(try_catch.HasCaught());
9211 :
9212 6 : error = try_catch.Exception();
9213 6 : CHECK(error->IsObject());
9214 18 : CHECK(error.As<v8::Object>()
9215 : ->Get(context.local(), message_str)
9216 : .ToLocalChecked()
9217 : ->Equals(context.local(), foo_str)
9218 : .FromJust());
9219 :
9220 6 : message = v8::Exception::CreateMessage(context->GetIsolate(), error);
9221 6 : CHECK(!message.IsEmpty());
9222 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9223 12 : CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust());
9224 :
9225 : // Should be empty stack trace.
9226 6 : stackTrace = message->GetStackTrace();
9227 6 : CHECK(stackTrace.IsEmpty());
9228 12 : CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9229 6 : }
9230 :
9231 :
9232 26645 : THREADED_TEST(ExceptionCreateMessageLength) {
9233 6 : LocalContext context;
9234 12 : v8::HandleScope scope(context->GetIsolate());
9235 :
9236 : // Test that the message is not truncated.
9237 12 : TryCatch try_catch(context->GetIsolate());
9238 : CompileRun(
9239 : "var message = 'm';"
9240 : "while (message.length < 1000) message += message;"
9241 : "throw message;");
9242 6 : CHECK(try_catch.HasCaught());
9243 :
9244 18 : CHECK_LT(1000, try_catch.Message()->Get()->Length());
9245 6 : }
9246 :
9247 :
9248 0 : static void YGetter(Local<String> name,
9249 : const v8::PropertyCallbackInfo<v8::Value>& info) {
9250 0 : ApiTestFuzzer::Fuzz();
9251 0 : info.GetReturnValue().Set(v8_num(10));
9252 0 : }
9253 :
9254 :
9255 6 : static void YSetter(Local<String> name,
9256 : Local<Value> value,
9257 : const v8::PropertyCallbackInfo<void>& info) {
9258 : Local<Object> this_obj = Local<Object>::Cast(info.This());
9259 6 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9260 12 : if (this_obj->Has(context, name).FromJust())
9261 12 : this_obj->Delete(context, name).FromJust();
9262 12 : CHECK(this_obj->Set(context, name, value).FromJust());
9263 6 : }
9264 :
9265 :
9266 26645 : THREADED_TEST(DeleteAccessor) {
9267 6 : v8::Isolate* isolate = CcTest::isolate();
9268 12 : v8::HandleScope scope(isolate);
9269 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9270 6 : obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9271 6 : LocalContext context;
9272 : v8::Local<v8::Object> holder =
9273 6 : obj->NewInstance(context.local()).ToLocalChecked();
9274 24 : CHECK(context->Global()
9275 : ->Set(context.local(), v8_str("holder"), holder)
9276 : .FromJust());
9277 : v8::Local<Value> result =
9278 : CompileRun("holder.y = 11; holder.y = 12; holder.y");
9279 12 : CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
9280 6 : }
9281 :
9282 :
9283 : static int trouble_nesting = 0;
9284 15 : static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9285 15 : ApiTestFuzzer::Fuzz();
9286 15 : trouble_nesting++;
9287 :
9288 : // Call a JS function that throws an uncaught exception.
9289 15 : Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
9290 15 : Local<v8::Object> arg_this = context->Global();
9291 : Local<Value> trouble_callee =
9292 15 : (trouble_nesting == 3)
9293 10 : ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
9294 35 : : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
9295 15 : CHECK(trouble_callee->IsFunction());
9296 : args.GetReturnValue().Set(Function::Cast(*trouble_callee)
9297 30 : ->Call(context, arg_this, 0, nullptr)
9298 : .FromMaybe(v8::Local<v8::Value>()));
9299 15 : }
9300 :
9301 :
9302 : static int report_count = 0;
9303 5 : static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
9304 : v8::Local<Value>) {
9305 5 : report_count++;
9306 5 : }
9307 :
9308 :
9309 : // Counts uncaught exceptions, but other tests running in parallel
9310 : // also have uncaught exceptions.
9311 26644 : TEST(ApiUncaughtException) {
9312 5 : report_count = 0;
9313 5 : LocalContext env;
9314 5 : v8::Isolate* isolate = env->GetIsolate();
9315 10 : v8::HandleScope scope(isolate);
9316 5 : isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
9317 :
9318 : Local<v8::FunctionTemplate> fun =
9319 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9320 5 : v8::Local<v8::Object> global = env->Global();
9321 20 : CHECK(global->Set(env.local(), v8_str("trouble"),
9322 : fun->GetFunction(env.local()).ToLocalChecked())
9323 : .FromJust());
9324 :
9325 : CompileRun(
9326 : "function trouble_callee() {"
9327 : " var x = null;"
9328 : " return x.foo;"
9329 : "};"
9330 : "function trouble_caller() {"
9331 : " trouble();"
9332 : "};");
9333 : Local<Value> trouble =
9334 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9335 5 : CHECK(trouble->IsFunction());
9336 : Local<Value> trouble_callee =
9337 15 : global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9338 5 : CHECK(trouble_callee->IsFunction());
9339 : Local<Value> trouble_caller =
9340 15 : global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9341 5 : CHECK(trouble_caller->IsFunction());
9342 : Function::Cast(*trouble_caller)
9343 5 : ->Call(env.local(), global, 0, nullptr)
9344 : .FromMaybe(v8::Local<v8::Value>());
9345 5 : CHECK_EQ(1, report_count);
9346 5 : isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9347 5 : }
9348 :
9349 :
9350 : static const char* script_resource_name = "ExceptionInNativeScript.js";
9351 5 : static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9352 : v8::Local<Value>) {
9353 10 : v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9354 10 : CHECK(!name_val.IsEmpty() && name_val->IsString());
9355 : v8::String::Utf8Value name(v8::Isolate::GetCurrent(),
9356 15 : message->GetScriptOrigin().ResourceName());
9357 5 : CHECK_EQ(0, strcmp(script_resource_name, *name));
9358 : v8::Local<v8::Context> context =
9359 5 : v8::Isolate::GetCurrent()->GetCurrentContext();
9360 10 : CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9361 : v8::String::Utf8Value source_line(
9362 : v8::Isolate::GetCurrent(),
9363 15 : message->GetSourceLine(context).ToLocalChecked());
9364 5 : CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9365 5 : }
9366 :
9367 :
9368 26644 : TEST(ExceptionInNativeScript) {
9369 5 : LocalContext env;
9370 5 : v8::Isolate* isolate = env->GetIsolate();
9371 10 : v8::HandleScope scope(isolate);
9372 5 : isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9373 :
9374 : Local<v8::FunctionTemplate> fun =
9375 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9376 5 : v8::Local<v8::Object> global = env->Global();
9377 20 : CHECK(global->Set(env.local(), v8_str("trouble"),
9378 : fun->GetFunction(env.local()).ToLocalChecked())
9379 : .FromJust());
9380 :
9381 : CompileRunWithOrigin(
9382 : "function trouble() {\n"
9383 : " var o = {};\n"
9384 : " new o.foo();\n"
9385 : "};",
9386 5 : script_resource_name);
9387 : Local<Value> trouble =
9388 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9389 5 : CHECK(trouble->IsFunction());
9390 10 : CHECK(Function::Cast(*trouble)
9391 : ->Call(env.local(), global, 0, nullptr)
9392 : .IsEmpty());
9393 5 : isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9394 5 : }
9395 :
9396 :
9397 26644 : TEST(CompilationErrorUsingTryCatchHandler) {
9398 5 : LocalContext env;
9399 10 : v8::HandleScope scope(env->GetIsolate());
9400 10 : v8::TryCatch try_catch(env->GetIsolate());
9401 : v8_compile("This doesn't &*&@#$&*^ compile.");
9402 10 : CHECK(*try_catch.Exception());
9403 5 : CHECK(try_catch.HasCaught());
9404 5 : }
9405 :
9406 :
9407 26644 : TEST(TryCatchFinallyUsingTryCatchHandler) {
9408 5 : LocalContext env;
9409 10 : v8::HandleScope scope(env->GetIsolate());
9410 10 : v8::TryCatch try_catch(env->GetIsolate());
9411 : CompileRun("try { throw ''; } catch (e) {}");
9412 5 : CHECK(!try_catch.HasCaught());
9413 : CompileRun("try { throw ''; } finally {}");
9414 5 : CHECK(try_catch.HasCaught());
9415 5 : try_catch.Reset();
9416 : CompileRun(
9417 : "(function() {"
9418 : "try { throw ''; } finally { return; }"
9419 : "})()");
9420 5 : CHECK(!try_catch.HasCaught());
9421 : CompileRun(
9422 : "(function()"
9423 : " { try { throw ''; } finally { throw 0; }"
9424 : "})()");
9425 5 : CHECK(try_catch.HasCaught());
9426 5 : }
9427 :
9428 :
9429 10 : void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9430 20 : v8::HandleScope scope(args.GetIsolate());
9431 : CompileRun(args[0]
9432 20 : ->ToString(args.GetIsolate()->GetCurrentContext())
9433 10 : .ToLocalChecked());
9434 10 : }
9435 :
9436 :
9437 26644 : TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9438 5 : v8::Isolate* isolate = CcTest::isolate();
9439 10 : v8::HandleScope scope(isolate);
9440 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9441 15 : templ->Set(v8_str("CEvaluate"),
9442 5 : v8::FunctionTemplate::New(isolate, CEvaluate));
9443 5 : LocalContext context(nullptr, templ);
9444 10 : v8::TryCatch try_catch(isolate);
9445 : CompileRun("try {"
9446 : " CEvaluate('throw 1;');"
9447 : "} finally {"
9448 : "}");
9449 5 : CHECK(try_catch.HasCaught());
9450 10 : CHECK(!try_catch.Message().IsEmpty());
9451 10 : String::Utf8Value exception_value(isolate, try_catch.Exception());
9452 5 : CHECK_EQ(0, strcmp(*exception_value, "1"));
9453 5 : try_catch.Reset();
9454 : CompileRun("try {"
9455 : " CEvaluate('throw 1;');"
9456 : "} finally {"
9457 : " throw 2;"
9458 : "}");
9459 5 : CHECK(try_catch.HasCaught());
9460 10 : CHECK(!try_catch.Message().IsEmpty());
9461 10 : String::Utf8Value finally_exception_value(isolate, try_catch.Exception());
9462 5 : CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9463 5 : }
9464 :
9465 :
9466 : // For use within the TestSecurityHandler() test.
9467 : static bool g_security_callback_result = false;
9468 35 : static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9469 : Local<v8::Object> accessed_object,
9470 : Local<v8::Value> data) {
9471 : printf("a\n");
9472 35 : CHECK(!data.IsEmpty() && data->IsInt32());
9473 70 : CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9474 35 : return g_security_callback_result;
9475 : }
9476 :
9477 :
9478 : // SecurityHandler can't be run twice
9479 26644 : TEST(SecurityHandler) {
9480 5 : v8::Isolate* isolate = CcTest::isolate();
9481 10 : v8::HandleScope scope0(isolate);
9482 : v8::Local<v8::ObjectTemplate> global_template =
9483 5 : v8::ObjectTemplate::New(isolate);
9484 10 : global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9485 : // Create an environment
9486 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9487 5 : context0->Enter();
9488 :
9489 5 : v8::Local<v8::Object> global0 = context0->Global();
9490 : v8::Local<Script> script0 = v8_compile("foo = 111");
9491 5 : script0->Run(context0).ToLocalChecked();
9492 15 : CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9493 : v8::Local<Value> foo0 =
9494 15 : global0->Get(context0, v8_str("foo")).ToLocalChecked();
9495 10 : CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9496 15 : v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9497 10 : CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9498 :
9499 : // Create another environment, should fail security checks.
9500 10 : v8::HandleScope scope1(isolate);
9501 :
9502 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, global_template);
9503 5 : context1->Enter();
9504 :
9505 5 : v8::Local<v8::Object> global1 = context1->Global();
9506 15 : global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9507 : // This set will fail the security check.
9508 : v8::Local<Script> script1 =
9509 : v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9510 10 : CHECK(script1->Run(context1).IsEmpty());
9511 5 : g_security_callback_result = true;
9512 : // This read will pass the security check.
9513 : v8::Local<Value> foo1 =
9514 15 : global0->Get(context1, v8_str("foo")).ToLocalChecked();
9515 10 : CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9516 : // This read will pass the security check.
9517 15 : v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9518 10 : CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9519 :
9520 : // Create another environment, should pass security checks.
9521 : {
9522 10 : v8::HandleScope scope2(isolate);
9523 5 : LocalContext context2;
9524 5 : v8::Local<v8::Object> global2 = context2->Global();
9525 15 : CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9526 : .FromJust());
9527 : v8::Local<Script> script2 =
9528 : v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9529 5 : script2->Run(context2.local()).ToLocalChecked();
9530 : v8::Local<Value> foo2 =
9531 15 : global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9532 10 : CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9533 : v8::Local<Value> z2 =
9534 15 : global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9535 10 : CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9536 : }
9537 :
9538 5 : context1->Exit();
9539 5 : context0->Exit();
9540 5 : }
9541 :
9542 :
9543 26645 : THREADED_TEST(SecurityChecks) {
9544 6 : LocalContext env1;
9545 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9546 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9547 :
9548 6 : Local<Value> foo = v8_str("foo");
9549 6 : Local<Value> bar = v8_str("bar");
9550 :
9551 : // Set to the same domain.
9552 6 : env1->SetSecurityToken(foo);
9553 :
9554 : // Create a function in env1.
9555 : CompileRun("spy=function(){return spy;}");
9556 : Local<Value> spy =
9557 24 : env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9558 6 : CHECK(spy->IsFunction());
9559 :
9560 : // Create another function accessing global objects.
9561 : CompileRun("spy2=function(){return new this.Array();}");
9562 : Local<Value> spy2 =
9563 24 : env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9564 6 : CHECK(spy2->IsFunction());
9565 :
9566 : // Switch to env2 in the same domain and invoke spy on env2.
9567 : {
9568 6 : env2->SetSecurityToken(foo);
9569 : // Enter env2
9570 : Context::Scope scope_env2(env2);
9571 : Local<Value> result = Function::Cast(*spy)
9572 18 : ->Call(env2, env2->Global(), 0, nullptr)
9573 : .ToLocalChecked();
9574 6 : CHECK(result->IsFunction());
9575 : }
9576 :
9577 : {
9578 6 : env2->SetSecurityToken(bar);
9579 : Context::Scope scope_env2(env2);
9580 :
9581 : // Call cross_domain_call, it should throw an exception
9582 12 : v8::TryCatch try_catch(env1->GetIsolate());
9583 18 : CHECK(Function::Cast(*spy2)
9584 : ->Call(env2, env2->Global(), 0, nullptr)
9585 : .IsEmpty());
9586 6 : CHECK(try_catch.HasCaught());
9587 : }
9588 6 : }
9589 :
9590 :
9591 : // Regression test case for issue 1183439.
9592 26645 : THREADED_TEST(SecurityChecksForPrototypeChain) {
9593 6 : LocalContext current;
9594 12 : v8::HandleScope scope(current->GetIsolate());
9595 6 : v8::Local<Context> other = Context::New(current->GetIsolate());
9596 :
9597 : // Change context to be able to get to the Object function in the
9598 : // other context without hitting the security checks.
9599 : v8::Local<Value> other_object;
9600 : { Context::Scope scope(other);
9601 : other_object =
9602 24 : other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9603 18 : CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9604 : }
9605 :
9606 30 : CHECK(current->Global()
9607 : ->Set(current.local(), v8_str("other"), other->Global())
9608 : .FromJust());
9609 24 : CHECK(v8_compile("other")
9610 : ->Run(current.local())
9611 : .ToLocalChecked()
9612 : ->Equals(current.local(), other->Global())
9613 : .FromJust());
9614 :
9615 : // Make sure the security check fails here and we get an undefined
9616 : // result instead of getting the Object function. Repeat in a loop
9617 : // to make sure to exercise the IC code.
9618 : v8::Local<Script> access_other0 = v8_compile("other.Object");
9619 : v8::Local<Script> access_other1 = v8_compile("other[42]");
9620 66 : for (int i = 0; i < 5; i++) {
9621 60 : CHECK(access_other0->Run(current.local()).IsEmpty());
9622 60 : CHECK(access_other1->Run(current.local()).IsEmpty());
9623 : }
9624 :
9625 : // Create an object that has 'other' in its prototype chain and make
9626 : // sure we cannot access the Object function indirectly through
9627 : // that. Repeat in a loop to make sure to exercise the IC code.
9628 : v8_compile(
9629 : "function F() { };"
9630 : "F.prototype = other;"
9631 : "var f = new F();")
9632 6 : ->Run(current.local())
9633 : .ToLocalChecked();
9634 : v8::Local<Script> access_f0 = v8_compile("f.Object");
9635 : v8::Local<Script> access_f1 = v8_compile("f[42]");
9636 66 : for (int j = 0; j < 5; j++) {
9637 60 : CHECK(access_f0->Run(current.local()).IsEmpty());
9638 60 : CHECK(access_f1->Run(current.local()).IsEmpty());
9639 : }
9640 :
9641 : // Now it gets hairy: Set the prototype for the other global object
9642 : // to be the current global object. The prototype chain for 'f' now
9643 : // goes through 'other' but ends up in the current global object.
9644 : { Context::Scope scope(other);
9645 30 : CHECK(other->Global()
9646 : ->Set(other, v8_str("__proto__"), current->Global())
9647 : .FromJust());
9648 : }
9649 : // Set a named and an index property on the current global
9650 : // object. To force the lookup to go through the other global object,
9651 : // the properties must not exist in the other global object.
9652 24 : CHECK(current->Global()
9653 : ->Set(current.local(), v8_str("foo"), v8_num(100))
9654 : .FromJust());
9655 24 : CHECK(current->Global()
9656 : ->Set(current.local(), v8_num(99), v8_num(101))
9657 : .FromJust());
9658 : // Try to read the properties from f and make sure that the access
9659 : // gets stopped by the security checks on the other global object.
9660 : Local<Script> access_f2 = v8_compile("f.foo");
9661 : Local<Script> access_f3 = v8_compile("f[99]");
9662 66 : for (int k = 0; k < 5; k++) {
9663 60 : CHECK(access_f2->Run(current.local()).IsEmpty());
9664 60 : CHECK(access_f3->Run(current.local()).IsEmpty());
9665 : }
9666 6 : }
9667 :
9668 :
9669 : static bool security_check_with_gc_called;
9670 :
9671 10 : static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9672 : Local<v8::Object> accessed_object,
9673 : Local<v8::Value> data) {
9674 10 : CcTest::CollectAllGarbage();
9675 10 : security_check_with_gc_called = true;
9676 10 : return true;
9677 : }
9678 :
9679 :
9680 26644 : TEST(SecurityTestGCAllowed) {
9681 5 : v8::Isolate* isolate = CcTest::isolate();
9682 10 : v8::HandleScope handle_scope(isolate);
9683 : v8::Local<v8::ObjectTemplate> object_template =
9684 5 : v8::ObjectTemplate::New(isolate);
9685 5 : object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9686 :
9687 5 : v8::Local<Context> context = Context::New(isolate);
9688 : v8::Context::Scope context_scope(context);
9689 :
9690 25 : CHECK(context->Global()
9691 : ->Set(context, v8_str("obj"),
9692 : object_template->NewInstance(context).ToLocalChecked())
9693 : .FromJust());
9694 :
9695 5 : security_check_with_gc_called = false;
9696 : CompileRun("obj[0] = new String(1002);");
9697 5 : CHECK(security_check_with_gc_called);
9698 :
9699 5 : security_check_with_gc_called = false;
9700 20 : CHECK(CompileRun("obj[0]")
9701 : ->ToString(context)
9702 : .ToLocalChecked()
9703 : ->Equals(context, v8_str("1002"))
9704 : .FromJust());
9705 5 : CHECK(security_check_with_gc_called);
9706 5 : }
9707 :
9708 :
9709 26645 : THREADED_TEST(CrossDomainDelete) {
9710 6 : LocalContext env1;
9711 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9712 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9713 :
9714 6 : Local<Value> foo = v8_str("foo");
9715 6 : Local<Value> bar = v8_str("bar");
9716 :
9717 : // Set to the same domain.
9718 6 : env1->SetSecurityToken(foo);
9719 6 : env2->SetSecurityToken(foo);
9720 :
9721 24 : CHECK(
9722 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9723 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9724 :
9725 : // Change env2 to a different domain and delete env1.prop.
9726 6 : env2->SetSecurityToken(bar);
9727 : {
9728 : Context::Scope scope_env2(env2);
9729 : Local<Value> result =
9730 : CompileRun("delete env1.prop");
9731 6 : CHECK(result.IsEmpty());
9732 : }
9733 :
9734 : // Check that env1.prop still exists.
9735 : Local<Value> v =
9736 24 : env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9737 6 : CHECK(v->IsNumber());
9738 12 : CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9739 6 : }
9740 :
9741 :
9742 26645 : THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9743 6 : LocalContext env1;
9744 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9745 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9746 :
9747 6 : Local<Value> foo = v8_str("foo");
9748 6 : Local<Value> bar = v8_str("bar");
9749 :
9750 : // Set to the same domain.
9751 6 : env1->SetSecurityToken(foo);
9752 6 : env2->SetSecurityToken(foo);
9753 :
9754 24 : CHECK(
9755 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9756 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9757 :
9758 : // env1.prop is enumerable in env2.
9759 6 : Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9760 : {
9761 : Context::Scope scope_env2(env2);
9762 6 : Local<Value> result = CompileRun(test);
9763 6 : CHECK(result->IsTrue());
9764 : }
9765 :
9766 : // Change env2 to a different domain and test again.
9767 6 : env2->SetSecurityToken(bar);
9768 : {
9769 : Context::Scope scope_env2(env2);
9770 6 : Local<Value> result = CompileRun(test);
9771 6 : CHECK(result.IsEmpty());
9772 : }
9773 6 : }
9774 :
9775 :
9776 26645 : THREADED_TEST(CrossDomainFor) {
9777 6 : LocalContext env1;
9778 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9779 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9780 :
9781 6 : Local<Value> foo = v8_str("foo");
9782 6 : Local<Value> bar = v8_str("bar");
9783 :
9784 : // Set to the same domain.
9785 6 : env1->SetSecurityToken(foo);
9786 6 : env2->SetSecurityToken(foo);
9787 :
9788 24 : CHECK(
9789 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9790 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9791 :
9792 : // Change env2 to a different domain and set env1's global object
9793 : // as the __proto__ of an object in env2 and enumerate properties
9794 : // in for-in. It shouldn't enumerate properties on env1's global
9795 : // object. It shouldn't throw either, just silently ignore them.
9796 6 : env2->SetSecurityToken(bar);
9797 : {
9798 : Context::Scope scope_env2(env2);
9799 : Local<Value> result = CompileRun(
9800 : "(function() {"
9801 : " try {"
9802 : " for (var p in env1) {"
9803 : " if (p == 'prop') return false;"
9804 : " }"
9805 : " return true;"
9806 : " } catch (e) {"
9807 : " return false;"
9808 : " }"
9809 : "})()");
9810 6 : CHECK(result->IsTrue());
9811 : }
9812 6 : }
9813 :
9814 :
9815 26645 : THREADED_TEST(CrossDomainForInOnPrototype) {
9816 6 : LocalContext env1;
9817 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9818 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9819 :
9820 6 : Local<Value> foo = v8_str("foo");
9821 6 : Local<Value> bar = v8_str("bar");
9822 :
9823 : // Set to the same domain.
9824 6 : env1->SetSecurityToken(foo);
9825 6 : env2->SetSecurityToken(foo);
9826 :
9827 24 : CHECK(
9828 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9829 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9830 :
9831 : // Change env2 to a different domain and set env1's global object
9832 : // as the __proto__ of an object in env2 and enumerate properties
9833 : // in for-in. It shouldn't enumerate properties on env1's global
9834 : // object.
9835 6 : env2->SetSecurityToken(bar);
9836 : {
9837 : Context::Scope scope_env2(env2);
9838 : Local<Value> result = CompileRun(
9839 : "(function() {"
9840 : " var obj = { '__proto__': env1 };"
9841 : " try {"
9842 : " for (var p in obj) {"
9843 : " if (p == 'prop') return false;"
9844 : " }"
9845 : " return true;"
9846 : " } catch (e) {"
9847 : " return false;"
9848 : " }"
9849 : "})()");
9850 6 : CHECK(result->IsTrue());
9851 : }
9852 6 : }
9853 :
9854 :
9855 26644 : TEST(ContextDetachGlobal) {
9856 5 : LocalContext env1;
9857 10 : v8::HandleScope handle_scope(env1->GetIsolate());
9858 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9859 :
9860 :
9861 5 : Local<Value> foo = v8_str("foo");
9862 :
9863 : // Set to the same domain.
9864 5 : env1->SetSecurityToken(foo);
9865 5 : env2->SetSecurityToken(foo);
9866 :
9867 : // Enter env2
9868 5 : env2->Enter();
9869 :
9870 : // Create a function in env2 and add a reference to it in env1.
9871 5 : Local<v8::Object> global2 = env2->Global();
9872 20 : CHECK(global2->Set(env2, v8_str("prop"),
9873 : v8::Integer::New(env2->GetIsolate(), 1))
9874 : .FromJust());
9875 : CompileRun("function getProp() {return prop;}");
9876 :
9877 30 : CHECK(env1->Global()
9878 : ->Set(env1.local(), v8_str("getProp"),
9879 : global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9880 : .FromJust());
9881 :
9882 : // Detach env2's global, and reuse the global object of env2
9883 5 : env2->Exit();
9884 5 : env2->DetachGlobal();
9885 :
9886 : v8::Local<Context> env3 = Context::New(
9887 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9888 10 : env3->SetSecurityToken(v8_str("bar"));
9889 :
9890 5 : env3->Enter();
9891 5 : Local<v8::Object> global3 = env3->Global();
9892 10 : CHECK(global2->Equals(env3, global3).FromJust());
9893 15 : CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9894 15 : CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9895 20 : CHECK(global3->Set(env3, v8_str("prop"),
9896 : v8::Integer::New(env3->GetIsolate(), -1))
9897 : .FromJust());
9898 20 : CHECK(global3->Set(env3, v8_str("prop2"),
9899 : v8::Integer::New(env3->GetIsolate(), 2))
9900 : .FromJust());
9901 5 : env3->Exit();
9902 :
9903 : // Call getProp in env1, and it should return the value 1
9904 : {
9905 5 : Local<v8::Object> global1 = env1->Global();
9906 : Local<Value> get_prop =
9907 15 : global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9908 5 : CHECK(get_prop->IsFunction());
9909 10 : v8::TryCatch try_catch(env1->GetIsolate());
9910 : Local<Value> r = Function::Cast(*get_prop)
9911 10 : ->Call(env1.local(), global1, 0, nullptr)
9912 : .ToLocalChecked();
9913 5 : CHECK(!try_catch.HasCaught());
9914 10 : CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9915 : }
9916 :
9917 : // Check that env3 is not accessible from env1
9918 : {
9919 10 : v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9920 5 : CHECK(r.IsEmpty());
9921 : }
9922 5 : }
9923 :
9924 :
9925 26644 : TEST(DetachGlobal) {
9926 5 : LocalContext env1;
9927 10 : v8::HandleScope scope(env1->GetIsolate());
9928 :
9929 : // Create second environment.
9930 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9931 :
9932 5 : Local<Value> foo = v8_str("foo");
9933 :
9934 : // Set same security token for env1 and env2.
9935 5 : env1->SetSecurityToken(foo);
9936 5 : env2->SetSecurityToken(foo);
9937 :
9938 : // Create a property on the global object in env2.
9939 : {
9940 : v8::Context::Scope scope(env2);
9941 25 : CHECK(env2->Global()
9942 : ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9943 : .FromJust());
9944 : }
9945 :
9946 : // Create a reference to env2 global from env1 global.
9947 25 : CHECK(env1->Global()
9948 : ->Set(env1.local(), v8_str("other"), env2->Global())
9949 : .FromJust());
9950 :
9951 : // Check that we have access to other.p in env2 from env1.
9952 : Local<Value> result = CompileRun("other.p");
9953 5 : CHECK(result->IsInt32());
9954 10 : CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9955 :
9956 : // Hold on to global from env2 and detach global from env2.
9957 5 : Local<v8::Object> global2 = env2->Global();
9958 5 : env2->DetachGlobal();
9959 :
9960 : // Check that the global has been detached. No other.p property can
9961 : // be found.
9962 : result = CompileRun("other.p");
9963 5 : CHECK(result.IsEmpty());
9964 :
9965 : // Reuse global2 for env3.
9966 : v8::Local<Context> env3 = Context::New(
9967 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9968 15 : CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9969 :
9970 : // Start by using the same security token for env3 as for env1 and env2.
9971 5 : env3->SetSecurityToken(foo);
9972 :
9973 : // Create a property on the global object in env3.
9974 : {
9975 : v8::Context::Scope scope(env3);
9976 25 : CHECK(env3->Global()
9977 : ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9978 : .FromJust());
9979 : }
9980 :
9981 : // Check that other.p is now the property in env3 and that we have access.
9982 : result = CompileRun("other.p");
9983 5 : CHECK(result->IsInt32());
9984 10 : CHECK_EQ(24, result->Int32Value(env3).FromJust());
9985 5 : }
9986 :
9987 :
9988 65 : void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9989 65 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9990 : info.GetReturnValue().Set(
9991 260 : context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9992 65 : }
9993 :
9994 :
9995 26644 : TEST(DetachedAccesses) {
9996 5 : LocalContext env1;
9997 10 : v8::HandleScope scope(env1->GetIsolate());
9998 :
9999 : // Create second environment.
10000 : Local<ObjectTemplate> inner_global_template =
10001 10 : FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
10002 10 : inner_global_template ->SetAccessorProperty(
10003 5 : v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
10004 : v8::Local<Context> env2 =
10005 5 : Context::New(env1->GetIsolate(), nullptr, inner_global_template);
10006 :
10007 5 : Local<Value> foo = v8_str("foo");
10008 :
10009 : // Set same security token for env1 and env2.
10010 5 : env1->SetSecurityToken(foo);
10011 5 : env2->SetSecurityToken(foo);
10012 :
10013 25 : CHECK(env1->Global()
10014 : ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
10015 : .FromJust());
10016 :
10017 : {
10018 : v8::Context::Scope scope(env2);
10019 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
10020 : CompileRun(
10021 : "function bound_x() { return x; }"
10022 : "function get_x() { return this.x; }"
10023 : "function get_x_w() { return (function() {return this.x;})(); }");
10024 20 : CHECK(env1->Global()
10025 : ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
10026 : .FromJust());
10027 20 : CHECK(env1->Global()
10028 : ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
10029 : .FromJust());
10030 20 : CHECK(env1->Global()
10031 : ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
10032 : .FromJust());
10033 10 : env1->Global()
10034 10 : ->Set(env1.local(), v8_str("this_x"),
10035 10 : CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
10036 : .FromJust();
10037 : }
10038 :
10039 5 : Local<Object> env2_global = env2->Global();
10040 5 : env2->DetachGlobal();
10041 :
10042 : Local<Value> result;
10043 : result = CompileRun("bound_x()");
10044 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10045 : result = CompileRun("get_x()");
10046 5 : CHECK(result.IsEmpty());
10047 : result = CompileRun("get_x_w()");
10048 5 : CHECK(result.IsEmpty());
10049 : result = CompileRun("this_x()");
10050 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10051 :
10052 : // Reattach env2's proxy
10053 : env2 = Context::New(env1->GetIsolate(), nullptr,
10054 5 : v8::Local<v8::ObjectTemplate>(), env2_global);
10055 5 : env2->SetSecurityToken(foo);
10056 : {
10057 : v8::Context::Scope scope(env2);
10058 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
10059 25 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
10060 : result = CompileRun(
10061 : "results = [];"
10062 : "for (var i = 0; i < 4; i++ ) {"
10063 : " results.push(env1.bound_x());"
10064 : " results.push(env1.get_x());"
10065 : " results.push(env1.get_x_w());"
10066 : " results.push(env1.this_x());"
10067 : "}"
10068 : "results");
10069 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10070 5 : CHECK_EQ(16u, results->Length());
10071 45 : for (int i = 0; i < 16; i += 4) {
10072 80 : CHECK(v8_str("env2_x")
10073 : ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
10074 : .FromJust());
10075 80 : CHECK(v8_str("env1_x")
10076 : ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
10077 : .FromJust());
10078 80 : CHECK(v8_str("env3_x")
10079 : ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
10080 : .FromJust());
10081 80 : CHECK(v8_str("env2_x")
10082 : ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
10083 : .FromJust());
10084 : }
10085 : }
10086 :
10087 : result = CompileRun(
10088 : "results = [];"
10089 : "for (var i = 0; i < 4; i++ ) {"
10090 : " results.push(bound_x());"
10091 : " results.push(get_x());"
10092 : " results.push(get_x_w());"
10093 : " results.push(this_x());"
10094 : "}"
10095 : "results");
10096 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10097 5 : CHECK_EQ(16u, results->Length());
10098 45 : for (int i = 0; i < 16; i += 4) {
10099 100 : CHECK(v8_str("env2_x")
10100 : ->Equals(env1.local(),
10101 : results->Get(env1.local(), i + 0).ToLocalChecked())
10102 : .FromJust());
10103 100 : CHECK(v8_str("env3_x")
10104 : ->Equals(env1.local(),
10105 : results->Get(env1.local(), i + 1).ToLocalChecked())
10106 : .FromJust());
10107 100 : CHECK(v8_str("env3_x")
10108 : ->Equals(env1.local(),
10109 : results->Get(env1.local(), i + 2).ToLocalChecked())
10110 : .FromJust());
10111 100 : CHECK(v8_str("env2_x")
10112 : ->Equals(env1.local(),
10113 : results->Get(env1.local(), i + 3).ToLocalChecked())
10114 : .FromJust());
10115 : }
10116 :
10117 : result = CompileRun(
10118 : "results = [];"
10119 : "for (var i = 0; i < 4; i++ ) {"
10120 : " results.push(this.bound_x());"
10121 : " results.push(this.get_x());"
10122 : " results.push(this.get_x_w());"
10123 : " results.push(this.this_x());"
10124 : "}"
10125 : "results");
10126 : results = Local<v8::Array>::Cast(result);
10127 5 : CHECK_EQ(16u, results->Length());
10128 45 : for (int i = 0; i < 16; i += 4) {
10129 100 : CHECK(v8_str("env2_x")
10130 : ->Equals(env1.local(),
10131 : results->Get(env1.local(), i + 0).ToLocalChecked())
10132 : .FromJust());
10133 100 : CHECK(v8_str("env1_x")
10134 : ->Equals(env1.local(),
10135 : results->Get(env1.local(), i + 1).ToLocalChecked())
10136 : .FromJust());
10137 100 : CHECK(v8_str("env3_x")
10138 : ->Equals(env1.local(),
10139 : results->Get(env1.local(), i + 2).ToLocalChecked())
10140 : .FromJust());
10141 100 : CHECK(v8_str("env2_x")
10142 : ->Equals(env1.local(),
10143 : results->Get(env1.local(), i + 3).ToLocalChecked())
10144 : .FromJust());
10145 : }
10146 5 : }
10147 :
10148 :
10149 : static bool allowed_access = false;
10150 370 : static bool AccessBlocker(Local<v8::Context> accessing_context,
10151 : Local<v8::Object> accessed_object,
10152 : Local<v8::Value> data) {
10153 370 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
10154 1110 : return context->Global()->Equals(context, accessed_object).FromJust() ||
10155 370 : allowed_access;
10156 : }
10157 :
10158 :
10159 : static int g_echo_value = -1;
10160 :
10161 :
10162 15 : static void EchoGetter(
10163 : Local<String> name,
10164 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10165 15 : info.GetReturnValue().Set(v8_num(g_echo_value));
10166 15 : }
10167 :
10168 :
10169 10 : static void EchoSetter(Local<String> name, Local<Value> value,
10170 : const v8::PropertyCallbackInfo<void>& args) {
10171 10 : if (value->IsNumber())
10172 : g_echo_value =
10173 20 : value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
10174 10 : }
10175 :
10176 :
10177 0 : static void UnreachableGetter(
10178 : Local<String> name,
10179 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10180 0 : UNREACHABLE(); // This function should not be called..
10181 : }
10182 :
10183 :
10184 0 : static void UnreachableSetter(Local<String>,
10185 : Local<Value>,
10186 : const v8::PropertyCallbackInfo<void>&) {
10187 0 : UNREACHABLE(); // This function should not be called.
10188 : }
10189 :
10190 :
10191 0 : static void UnreachableFunction(
10192 : const v8::FunctionCallbackInfo<v8::Value>& info) {
10193 0 : UNREACHABLE(); // This function should not be called..
10194 : }
10195 :
10196 :
10197 26644 : TEST(AccessControl) {
10198 5 : v8::Isolate* isolate = CcTest::isolate();
10199 10 : v8::HandleScope handle_scope(isolate);
10200 : v8::Local<v8::ObjectTemplate> global_template =
10201 5 : v8::ObjectTemplate::New(isolate);
10202 :
10203 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10204 :
10205 : // Add an accessor accessible by cross-domain JS code.
10206 10 : global_template->SetAccessor(
10207 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10208 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10209 :
10210 :
10211 : // Add an accessor that is not accessible by cross-domain JS code.
10212 10 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10213 : UnreachableSetter, v8::Local<Value>(),
10214 5 : v8::DEFAULT);
10215 :
10216 15 : global_template->SetAccessorProperty(
10217 : v8_str("blocked_js_prop"),
10218 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10219 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10220 : v8::None,
10221 5 : v8::DEFAULT);
10222 :
10223 : // Create an environment
10224 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10225 5 : context0->Enter();
10226 :
10227 5 : v8::Local<v8::Object> global0 = context0->Global();
10228 :
10229 : // Define a property with JS getter and setter.
10230 : CompileRun(
10231 : "function getter() { return 'getter'; };\n"
10232 : "function setter() { return 'setter'; }\n"
10233 : "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
10234 :
10235 : Local<Value> getter =
10236 15 : global0->Get(context0, v8_str("getter")).ToLocalChecked();
10237 : Local<Value> setter =
10238 15 : global0->Get(context0, v8_str("setter")).ToLocalChecked();
10239 :
10240 : // And define normal element.
10241 15 : CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
10242 :
10243 : // Define an element with JS getter and setter.
10244 : CompileRun(
10245 : "function el_getter() { return 'el_getter'; };\n"
10246 : "function el_setter() { return 'el_setter'; };\n"
10247 : "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
10248 :
10249 : Local<Value> el_getter =
10250 15 : global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
10251 : Local<Value> el_setter =
10252 15 : global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
10253 :
10254 10 : v8::HandleScope scope1(isolate);
10255 :
10256 5 : v8::Local<Context> context1 = Context::New(isolate);
10257 5 : context1->Enter();
10258 :
10259 5 : v8::Local<v8::Object> global1 = context1->Global();
10260 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10261 :
10262 : // Access blocked property.
10263 : CompileRun("other.blocked_prop = 1");
10264 :
10265 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10266 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10267 : .IsEmpty());
10268 5 : CHECK(
10269 : CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
10270 :
10271 : // Access blocked element.
10272 5 : CHECK(CompileRun("other[239] = 1").IsEmpty());
10273 :
10274 5 : CHECK(CompileRun("other[239]").IsEmpty());
10275 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10276 5 : CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10277 :
10278 5 : allowed_access = true;
10279 : // Now we can enumerate the property.
10280 : ExpectTrue("propertyIsEnumerable.call(other, '239')");
10281 5 : allowed_access = false;
10282 :
10283 : // Access a property with JS accessor.
10284 5 : CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10285 :
10286 5 : CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10287 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10288 : .IsEmpty());
10289 :
10290 5 : allowed_access = true;
10291 :
10292 5 : ExpectString("other.js_accessor_p", "getter");
10293 : ExpectObject(
10294 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10295 : ExpectObject(
10296 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10297 : ExpectUndefined(
10298 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10299 :
10300 5 : allowed_access = false;
10301 :
10302 : // Access an element with JS accessor.
10303 5 : CHECK(CompileRun("other[42] = 2").IsEmpty());
10304 :
10305 5 : CHECK(CompileRun("other[42]").IsEmpty());
10306 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10307 :
10308 5 : allowed_access = true;
10309 :
10310 5 : ExpectString("other[42]", "el_getter");
10311 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10312 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10313 5 : ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10314 :
10315 5 : allowed_access = false;
10316 :
10317 : v8::Local<Value> value;
10318 :
10319 : // Access accessible property
10320 : value = CompileRun("other.accessible_prop = 3");
10321 5 : CHECK(value->IsNumber());
10322 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10323 5 : CHECK_EQ(3, g_echo_value);
10324 :
10325 : value = CompileRun("other.accessible_prop");
10326 5 : CHECK(value->IsNumber());
10327 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10328 :
10329 : value = CompileRun(
10330 : "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10331 5 : CHECK(value->IsNumber());
10332 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10333 :
10334 : value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10335 5 : CHECK(value->IsTrue());
10336 :
10337 : // Enumeration doesn't enumerate accessors from inaccessible objects in
10338 : // the prototype chain even if the accessors are in themselves accessible.
10339 : // Enumeration doesn't throw, it silently ignores what it can't access.
10340 : value = CompileRun(
10341 : "(function() {"
10342 : " var obj = { '__proto__': other };"
10343 : " try {"
10344 : " for (var p in obj) {"
10345 : " if (p == 'accessible_prop' ||"
10346 : " p == 'blocked_js_prop' ||"
10347 : " p == 'blocked_js_prop') {"
10348 : " return false;"
10349 : " }"
10350 : " }"
10351 : " return true;"
10352 : " } catch (e) {"
10353 : " return false;"
10354 : " }"
10355 : "})()");
10356 5 : CHECK(value->IsTrue());
10357 :
10358 : // Test that preventExtensions fails on a non-accessible object even if that
10359 : // object is already non-extensible.
10360 20 : CHECK(global1->Set(context1, v8_str("checked_object"),
10361 : global_template->NewInstance(context1).ToLocalChecked())
10362 : .FromJust());
10363 5 : allowed_access = true;
10364 : CompileRun("Object.preventExtensions(checked_object)");
10365 : ExpectFalse("Object.isExtensible(checked_object)");
10366 5 : allowed_access = false;
10367 5 : CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10368 :
10369 5 : context1->Exit();
10370 5 : context0->Exit();
10371 5 : }
10372 :
10373 :
10374 26644 : TEST(AccessControlES5) {
10375 5 : v8::Isolate* isolate = CcTest::isolate();
10376 10 : v8::HandleScope handle_scope(isolate);
10377 : v8::Local<v8::ObjectTemplate> global_template =
10378 5 : v8::ObjectTemplate::New(isolate);
10379 :
10380 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10381 :
10382 : // Add accessible accessor.
10383 10 : global_template->SetAccessor(
10384 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10385 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10386 :
10387 :
10388 : // Add an accessor that is not accessible by cross-domain JS code.
10389 10 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10390 : UnreachableSetter, v8::Local<Value>(),
10391 5 : v8::DEFAULT);
10392 :
10393 : // Create an environment
10394 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10395 5 : context0->Enter();
10396 :
10397 5 : v8::Local<v8::Object> global0 = context0->Global();
10398 :
10399 5 : v8::Local<Context> context1 = Context::New(isolate);
10400 5 : context1->Enter();
10401 5 : v8::Local<v8::Object> global1 = context1->Global();
10402 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10403 :
10404 : // Regression test for issue 1154.
10405 5 : CHECK(CompileRun("Object.keys(other).length == 1")->BooleanValue(isolate));
10406 5 : CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10407 : ->BooleanValue(isolate));
10408 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10409 :
10410 : // Regression test for issue 1027.
10411 : CompileRun("Object.defineProperty(\n"
10412 : " other, 'blocked_prop', {configurable: false})");
10413 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10414 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10415 : .IsEmpty());
10416 :
10417 : // Regression test for issue 1171.
10418 : ExpectTrue("Object.isExtensible(other)");
10419 : CompileRun("Object.preventExtensions(other)");
10420 : ExpectTrue("Object.isExtensible(other)");
10421 :
10422 : // Object.seal and Object.freeze.
10423 : CompileRun("Object.freeze(other)");
10424 : ExpectTrue("Object.isExtensible(other)");
10425 :
10426 : CompileRun("Object.seal(other)");
10427 : ExpectTrue("Object.isExtensible(other)");
10428 :
10429 : // Regression test for issue 1250.
10430 : // Make sure that we can set the accessible accessors value using normal
10431 : // assignment.
10432 : CompileRun("other.accessible_prop = 42");
10433 5 : CHECK_EQ(42, g_echo_value);
10434 :
10435 : // [[DefineOwnProperty]] always throws for access-checked objects.
10436 5 : CHECK(
10437 : CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10438 : .IsEmpty());
10439 5 : CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10440 5 : CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10441 5 : }
10442 :
10443 233 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10444 : Local<v8::Object> global,
10445 : Local<v8::Value> data) {
10446 233 : i::PrintF("Access blocked.\n");
10447 233 : return false;
10448 : }
10449 :
10450 5 : static bool AccessAlwaysAllowed(Local<v8::Context> accessing_context,
10451 : Local<v8::Object> global,
10452 : Local<v8::Value> data) {
10453 5 : i::PrintF("Access allowed.\n");
10454 5 : return true;
10455 : }
10456 :
10457 26645 : THREADED_TEST(AccessControlGetOwnPropertyNames) {
10458 6 : v8::Isolate* isolate = CcTest::isolate();
10459 12 : v8::HandleScope handle_scope(isolate);
10460 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10461 :
10462 18 : obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10463 6 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10464 :
10465 : // Add an accessor accessible by cross-domain JS code.
10466 12 : obj_template->SetAccessor(
10467 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10468 6 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10469 :
10470 : // Create an environment
10471 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
10472 6 : context0->Enter();
10473 :
10474 6 : v8::Local<v8::Object> global0 = context0->Global();
10475 :
10476 12 : v8::HandleScope scope1(CcTest::isolate());
10477 :
10478 6 : v8::Local<Context> context1 = Context::New(isolate);
10479 6 : context1->Enter();
10480 :
10481 6 : v8::Local<v8::Object> global1 = context1->Global();
10482 18 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10483 24 : CHECK(global1->Set(context1, v8_str("object"),
10484 : obj_template->NewInstance(context1).ToLocalChecked())
10485 : .FromJust());
10486 :
10487 : v8::Local<Value> value;
10488 :
10489 : // Attempt to get the property names of the other global object and
10490 : // of an object that requires access checks. Accessing the other
10491 : // global object should be blocked by access checks on the global
10492 : // proxy object. Accessing the object that requires access checks
10493 : // is blocked by the access checks on the object itself.
10494 : value = CompileRun(
10495 : "var names = Object.getOwnPropertyNames(other);"
10496 : "names.length == 1 && names[0] == 'accessible_prop';");
10497 6 : CHECK(value->BooleanValue(isolate));
10498 :
10499 : value = CompileRun(
10500 : "var names = Object.getOwnPropertyNames(object);"
10501 : "names.length == 1 && names[0] == 'accessible_prop';");
10502 6 : CHECK(value->BooleanValue(isolate));
10503 :
10504 6 : context1->Exit();
10505 6 : context0->Exit();
10506 6 : }
10507 :
10508 :
10509 26644 : TEST(Regress470113) {
10510 5 : v8::Isolate* isolate = CcTest::isolate();
10511 10 : v8::HandleScope handle_scope(isolate);
10512 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10513 5 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10514 5 : LocalContext env;
10515 25 : CHECK(env->Global()
10516 : ->Set(env.local(), v8_str("prohibited"),
10517 : obj_template->NewInstance(env.local()).ToLocalChecked())
10518 : .FromJust());
10519 :
10520 : {
10521 10 : v8::TryCatch try_catch(isolate);
10522 : CompileRun(
10523 : "'use strict';\n"
10524 : "class C extends Object {\n"
10525 : " m() { super.powned = 'Powned!'; }\n"
10526 : "}\n"
10527 : "let c = new C();\n"
10528 : "c.m.call(prohibited)");
10529 :
10530 5 : CHECK(try_catch.HasCaught());
10531 : }
10532 5 : }
10533 :
10534 :
10535 6 : static void ConstTenGetter(Local<String> name,
10536 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10537 6 : info.GetReturnValue().Set(v8_num(10));
10538 6 : }
10539 :
10540 :
10541 26645 : THREADED_TEST(CrossDomainAccessors) {
10542 6 : v8::Isolate* isolate = CcTest::isolate();
10543 12 : v8::HandleScope handle_scope(isolate);
10544 :
10545 : v8::Local<v8::FunctionTemplate> func_template =
10546 6 : v8::FunctionTemplate::New(isolate);
10547 :
10548 : v8::Local<v8::ObjectTemplate> global_template =
10549 6 : func_template->InstanceTemplate();
10550 :
10551 : v8::Local<v8::ObjectTemplate> proto_template =
10552 6 : func_template->PrototypeTemplate();
10553 :
10554 : // Add an accessor to proto that's accessible by cross-domain JS code.
10555 12 : proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, nullptr,
10556 6 : v8::Local<Value>(), v8::ALL_CAN_READ);
10557 :
10558 : // Add an accessor that is not accessible by cross-domain JS code.
10559 12 : global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter,
10560 6 : nullptr, v8::Local<Value>(), v8::DEFAULT);
10561 :
10562 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10563 6 : context0->Enter();
10564 :
10565 6 : Local<v8::Object> global = context0->Global();
10566 : // Add a normal property that shadows 'accessible'
10567 18 : CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10568 :
10569 : // Enter a new context.
10570 12 : v8::HandleScope scope1(CcTest::isolate());
10571 6 : v8::Local<Context> context1 = Context::New(isolate);
10572 6 : context1->Enter();
10573 :
10574 6 : v8::Local<v8::Object> global1 = context1->Global();
10575 18 : CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10576 :
10577 : // Should return 10, instead of 11
10578 : v8::Local<Value> value =
10579 6 : v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10580 6 : CHECK(value->IsNumber());
10581 12 : CHECK_EQ(10, value->Int32Value(context1).FromJust());
10582 :
10583 : v8::MaybeLocal<v8::Value> maybe_value =
10584 6 : v8_compile("other.unreachable")->Run(context1);
10585 6 : CHECK(maybe_value.IsEmpty());
10586 :
10587 6 : context1->Exit();
10588 6 : context0->Exit();
10589 6 : }
10590 :
10591 :
10592 : static int access_count = 0;
10593 :
10594 820 : static bool AccessCounter(Local<v8::Context> accessing_context,
10595 : Local<v8::Object> accessed_object,
10596 : Local<v8::Value> data) {
10597 820 : access_count++;
10598 820 : return true;
10599 : }
10600 :
10601 :
10602 : // This one is too easily disturbed by other tests.
10603 26644 : TEST(AccessControlIC) {
10604 5 : access_count = 0;
10605 :
10606 5 : v8::Isolate* isolate = CcTest::isolate();
10607 10 : v8::HandleScope handle_scope(isolate);
10608 :
10609 : // Create an environment.
10610 5 : v8::Local<Context> context0 = Context::New(isolate);
10611 5 : context0->Enter();
10612 :
10613 : // Create an object that requires access-check functions to be
10614 : // called for cross-domain access.
10615 : v8::Local<v8::ObjectTemplate> object_template =
10616 5 : v8::ObjectTemplate::New(isolate);
10617 5 : object_template->SetAccessCheckCallback(AccessCounter);
10618 : Local<v8::Object> object =
10619 5 : object_template->NewInstance(context0).ToLocalChecked();
10620 :
10621 10 : v8::HandleScope scope1(isolate);
10622 :
10623 : // Create another environment.
10624 5 : v8::Local<Context> context1 = Context::New(isolate);
10625 5 : context1->Enter();
10626 :
10627 : // Make easy access to the object from the other environment.
10628 5 : v8::Local<v8::Object> global1 = context1->Global();
10629 15 : CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10630 :
10631 : v8::Local<Value> value;
10632 :
10633 : // Check that the named access-control function is called every time.
10634 : CompileRun("function testProp(obj) {"
10635 : " for (var i = 0; i < 10; i++) obj.prop = 1;"
10636 : " for (var j = 0; j < 10; j++) obj.prop;"
10637 : " return obj.prop"
10638 : "}");
10639 : value = CompileRun("testProp(obj)");
10640 5 : CHECK(value->IsNumber());
10641 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10642 5 : CHECK_EQ(21, access_count);
10643 :
10644 : // Check that the named access-control function is called every time.
10645 : CompileRun("var p = 'prop';"
10646 : "function testKeyed(obj) {"
10647 : " for (var i = 0; i < 10; i++) obj[p] = 1;"
10648 : " for (var j = 0; j < 10; j++) obj[p];"
10649 : " return obj[p];"
10650 : "}");
10651 : // Use obj which requires access checks. No inline caching is used
10652 : // in that case.
10653 : value = CompileRun("testKeyed(obj)");
10654 5 : CHECK(value->IsNumber());
10655 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10656 5 : CHECK_EQ(42, access_count);
10657 : // Force the inline caches into generic state and try again.
10658 : CompileRun("testKeyed({ a: 0 })");
10659 : CompileRun("testKeyed({ b: 0 })");
10660 : value = CompileRun("testKeyed(obj)");
10661 5 : CHECK(value->IsNumber());
10662 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10663 5 : CHECK_EQ(63, access_count);
10664 :
10665 : // Check that the indexed access-control function is called every time.
10666 5 : access_count = 0;
10667 :
10668 : CompileRun("function testIndexed(obj) {"
10669 : " for (var i = 0; i < 10; i++) obj[0] = 1;"
10670 : " for (var j = 0; j < 10; j++) obj[0];"
10671 : " return obj[0]"
10672 : "}");
10673 : value = CompileRun("testIndexed(obj)");
10674 5 : CHECK(value->IsNumber());
10675 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10676 5 : CHECK_EQ(21, access_count);
10677 : // Force the inline caches into generic state.
10678 : CompileRun("testIndexed(new Array(1))");
10679 : // Test that the indexed access check is called.
10680 : value = CompileRun("testIndexed(obj)");
10681 5 : CHECK(value->IsNumber());
10682 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10683 5 : CHECK_EQ(42, access_count);
10684 :
10685 5 : access_count = 0;
10686 : // Check that the named access check is called when invoking
10687 : // functions on an object that requires access checks.
10688 : CompileRun("obj.f = function() {}");
10689 : CompileRun("function testCallNormal(obj) {"
10690 : " for (var i = 0; i < 10; i++) obj.f();"
10691 : "}");
10692 : CompileRun("testCallNormal(obj)");
10693 5 : printf("%i\n", access_count);
10694 5 : CHECK_EQ(11, access_count);
10695 :
10696 : // Force obj into slow case.
10697 : value = CompileRun("delete obj.prop");
10698 5 : CHECK(value->BooleanValue(isolate));
10699 : // Force inline caches into dictionary probing mode.
10700 : CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10701 : // Test that the named access check is called.
10702 : value = CompileRun("testProp(obj);");
10703 5 : CHECK(value->IsNumber());
10704 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10705 5 : CHECK_EQ(33, access_count);
10706 :
10707 : // Force the call inline cache into dictionary probing mode.
10708 : CompileRun("o.f = function() {}; testCallNormal(o)");
10709 : // Test that the named access check is still called for each
10710 : // invocation of the function.
10711 : value = CompileRun("testCallNormal(obj)");
10712 5 : CHECK_EQ(43, access_count);
10713 :
10714 5 : context1->Exit();
10715 5 : context0->Exit();
10716 5 : }
10717 :
10718 :
10719 26645 : THREADED_TEST(Version) { v8::V8::GetVersion(); }
10720 :
10721 :
10722 18 : static void InstanceFunctionCallback(
10723 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10724 18 : ApiTestFuzzer::Fuzz();
10725 18 : args.GetReturnValue().Set(v8_num(12));
10726 18 : }
10727 :
10728 :
10729 26645 : THREADED_TEST(InstanceProperties) {
10730 6 : LocalContext context;
10731 6 : v8::Isolate* isolate = context->GetIsolate();
10732 12 : v8::HandleScope handle_scope(isolate);
10733 :
10734 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10735 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10736 :
10737 18 : instance->Set(v8_str("x"), v8_num(42));
10738 18 : instance->Set(v8_str("f"),
10739 6 : v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10740 :
10741 6 : Local<Value> o = t->GetFunction(context.local())
10742 : .ToLocalChecked()
10743 : ->NewInstance(context.local())
10744 : .ToLocalChecked();
10745 :
10746 24 : CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10747 : Local<Value> value = CompileRun("i.x");
10748 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10749 :
10750 : value = CompileRun("i.f()");
10751 12 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10752 6 : }
10753 :
10754 :
10755 696 : static void GlobalObjectInstancePropertiesGet(
10756 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10757 696 : ApiTestFuzzer::Fuzz();
10758 696 : }
10759 :
10760 :
10761 26645 : THREADED_TEST(GlobalObjectInstanceProperties) {
10762 6 : v8::Isolate* isolate = CcTest::isolate();
10763 12 : v8::HandleScope handle_scope(isolate);
10764 :
10765 : Local<Value> global_object;
10766 :
10767 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10768 12 : t->InstanceTemplate()->SetHandler(
10769 6 : v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10770 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10771 18 : instance_template->Set(v8_str("x"), v8_num(42));
10772 18 : instance_template->Set(v8_str("f"),
10773 : v8::FunctionTemplate::New(isolate,
10774 6 : InstanceFunctionCallback));
10775 :
10776 : // The script to check how TurboFan compiles missing global function
10777 : // invocations. function g is not defined and should throw on call.
10778 : const char* script =
10779 : "function wrapper(call) {"
10780 : " var x = 0, y = 1;"
10781 : " for (var i = 0; i < 1000; i++) {"
10782 : " x += i * 100;"
10783 : " y += i * 100;"
10784 : " }"
10785 : " if (call) g();"
10786 : "}"
10787 : "for (var i = 0; i < 17; i++) wrapper(false);"
10788 : "var thrown = 0;"
10789 : "try { wrapper(true); } catch (e) { thrown = 1; };"
10790 : "thrown";
10791 :
10792 : {
10793 6 : LocalContext env(nullptr, instance_template);
10794 : // Hold on to the global object so it can be used again in another
10795 : // environment initialization.
10796 6 : global_object = env->Global();
10797 :
10798 : Local<Value> value = CompileRun("x");
10799 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10800 : value = CompileRun("f()");
10801 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10802 : value = CompileRun(script);
10803 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10804 : }
10805 :
10806 : {
10807 : // Create new environment reusing the global object.
10808 6 : LocalContext env(nullptr, instance_template, global_object);
10809 : Local<Value> value = CompileRun("x");
10810 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10811 : value = CompileRun("f()");
10812 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10813 : value = CompileRun(script);
10814 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10815 : }
10816 6 : }
10817 :
10818 26645 : THREADED_TEST(ObjectGetOwnPropertyNames) {
10819 6 : LocalContext context;
10820 6 : v8::Isolate* isolate = context->GetIsolate();
10821 12 : v8::HandleScope handle_scope(isolate);
10822 :
10823 : v8::Local<v8::Object> value = v8::Local<v8::Object>::Cast(
10824 6 : v8::StringObject::New(CcTest::isolate(), v8_str("test")));
10825 : v8::Local<v8::Array> properties;
10826 :
10827 12 : CHECK(value
10828 : ->GetOwnPropertyNames(context.local(),
10829 : static_cast<v8::PropertyFilter>(
10830 : v8::PropertyFilter::ALL_PROPERTIES |
10831 : v8::PropertyFilter::SKIP_SYMBOLS),
10832 : v8::KeyConversionMode::kKeepNumbers)
10833 : .ToLocal(&properties));
10834 6 : CHECK_EQ(5u, properties->Length());
10835 : v8::Local<v8::Value> property;
10836 18 : CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10837 : property->IsString());
10838 18 : CHECK(property.As<v8::String>()
10839 : ->Equals(context.local(), v8_str("length"))
10840 : .FromMaybe(false));
10841 54 : for (int i = 0; i < 4; ++i) {
10842 : v8::Local<v8::Value> property;
10843 72 : CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10844 : property->IsInt32());
10845 24 : CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10846 : }
10847 :
10848 12 : CHECK(value
10849 : ->GetOwnPropertyNames(context.local(),
10850 : v8::PropertyFilter::ONLY_ENUMERABLE,
10851 : v8::KeyConversionMode::kKeepNumbers)
10852 : .ToLocal(&properties));
10853 : v8::Local<v8::Array> number_properties;
10854 12 : CHECK(value
10855 : ->GetOwnPropertyNames(context.local(),
10856 : v8::PropertyFilter::ONLY_ENUMERABLE,
10857 : v8::KeyConversionMode::kConvertToString)
10858 : .ToLocal(&number_properties));
10859 6 : CHECK_EQ(4u, properties->Length());
10860 54 : for (int i = 0; i < 4; ++i) {
10861 : v8::Local<v8::Value> property_index;
10862 : v8::Local<v8::Value> property_name;
10863 :
10864 72 : CHECK(number_properties->Get(context.local(), i).ToLocal(&property_name));
10865 24 : CHECK(property_name->IsString());
10866 :
10867 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property_index));
10868 24 : CHECK(property_index->IsInt32());
10869 :
10870 24 : CHECK_EQ(property_index.As<v8::Int32>()->Value(), i);
10871 48 : CHECK_EQ(property_name->ToNumber(context.local())
10872 : .ToLocalChecked()
10873 : .As<v8::Int32>()
10874 : ->Value(),
10875 : i);
10876 : }
10877 :
10878 6 : value = value->GetPrototype().As<v8::Object>();
10879 12 : CHECK(value
10880 : ->GetOwnPropertyNames(context.local(),
10881 : static_cast<v8::PropertyFilter>(
10882 : v8::PropertyFilter::ALL_PROPERTIES |
10883 : v8::PropertyFilter::SKIP_SYMBOLS))
10884 : .ToLocal(&properties));
10885 : bool concat_found = false;
10886 : bool starts_with_found = false;
10887 582 : for (uint32_t i = 0; i < properties->Length(); ++i) {
10888 : v8::Local<v8::Value> property;
10889 576 : CHECK(properties->Get(context.local(), i).ToLocal(&property));
10890 288 : if (!property->IsString()) continue;
10891 288 : if (!concat_found)
10892 : concat_found = property.As<v8::String>()
10893 180 : ->Equals(context.local(), v8_str("concat"))
10894 : .FromMaybe(false);
10895 288 : if (!starts_with_found)
10896 : starts_with_found = property.As<v8::String>()
10897 648 : ->Equals(context.local(), v8_str("startsWith"))
10898 : .FromMaybe(false);
10899 : }
10900 6 : CHECK(concat_found && starts_with_found);
10901 6 : }
10902 :
10903 26645 : THREADED_TEST(CallKnownGlobalReceiver) {
10904 6 : v8::Isolate* isolate = CcTest::isolate();
10905 12 : v8::HandleScope handle_scope(isolate);
10906 :
10907 : Local<Value> global_object;
10908 :
10909 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10910 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10911 :
10912 : // The script to check that we leave global object not
10913 : // global object proxy on stack when we deoptimize from inside
10914 : // arguments evaluation.
10915 : // To provoke error we need to both force deoptimization
10916 : // from arguments evaluation and to force CallIC to take
10917 : // CallIC_Miss code path that can't cope with global proxy.
10918 : const char* script =
10919 : "function bar(x, y) { try { } finally { } }"
10920 : "function baz(x) { try { } finally { } }"
10921 : "function bom(x) { try { } finally { } }"
10922 : "function foo(x) { bar([x], bom(2)); }"
10923 : "for (var i = 0; i < 10000; i++) foo(1);"
10924 : "foo";
10925 :
10926 : Local<Value> foo;
10927 : {
10928 6 : LocalContext env(nullptr, instance_template);
10929 : // Hold on to the global object so it can be used again in another
10930 : // environment initialization.
10931 6 : global_object = env->Global();
10932 6 : foo = CompileRun(script);
10933 : }
10934 :
10935 : {
10936 : // Create new environment reusing the global object.
10937 6 : LocalContext env(nullptr, instance_template, global_object);
10938 24 : CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10939 : CompileRun("foo()");
10940 : }
10941 6 : }
10942 :
10943 :
10944 6 : static void ShadowFunctionCallback(
10945 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10946 6 : ApiTestFuzzer::Fuzz();
10947 6 : args.GetReturnValue().Set(v8_num(42));
10948 6 : }
10949 :
10950 :
10951 : static int shadow_y;
10952 : static int shadow_y_setter_call_count;
10953 : static int shadow_y_getter_call_count;
10954 :
10955 :
10956 6 : static void ShadowYSetter(Local<String>,
10957 : Local<Value>,
10958 : const v8::PropertyCallbackInfo<void>&) {
10959 6 : shadow_y_setter_call_count++;
10960 6 : shadow_y = 42;
10961 6 : }
10962 :
10963 :
10964 6 : static void ShadowYGetter(Local<String> name,
10965 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10966 6 : ApiTestFuzzer::Fuzz();
10967 6 : shadow_y_getter_call_count++;
10968 6 : info.GetReturnValue().Set(v8_num(shadow_y));
10969 6 : }
10970 :
10971 :
10972 0 : static void ShadowIndexedGet(uint32_t index,
10973 : const v8::PropertyCallbackInfo<v8::Value>&) {
10974 0 : }
10975 :
10976 :
10977 42 : static void ShadowNamedGet(Local<Name> key,
10978 42 : const v8::PropertyCallbackInfo<v8::Value>&) {}
10979 :
10980 26645 : THREADED_TEST(ShadowObject) {
10981 6 : shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10982 6 : v8::Isolate* isolate = CcTest::isolate();
10983 12 : v8::HandleScope handle_scope(isolate);
10984 :
10985 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10986 6 : LocalContext context(nullptr, global_template);
10987 :
10988 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10989 12 : t->InstanceTemplate()->SetHandler(
10990 6 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10991 12 : t->InstanceTemplate()->SetHandler(
10992 6 : v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10993 6 : Local<ObjectTemplate> proto = t->PrototypeTemplate();
10994 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10995 :
10996 18 : proto->Set(v8_str("f"),
10997 : v8::FunctionTemplate::New(isolate,
10998 : ShadowFunctionCallback,
10999 6 : Local<Value>()));
11000 18 : proto->Set(v8_str("x"), v8_num(12));
11001 :
11002 12 : instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
11003 :
11004 6 : Local<Value> o = t->GetFunction(context.local())
11005 : .ToLocalChecked()
11006 : ->NewInstance(context.local())
11007 : .ToLocalChecked();
11008 24 : CHECK(context->Global()
11009 : ->Set(context.local(), v8_str("__proto__"), o)
11010 : .FromJust());
11011 :
11012 : Local<Value> value =
11013 : CompileRun("this.propertyIsEnumerable(0)");
11014 6 : CHECK(value->IsBoolean());
11015 6 : CHECK(!value->BooleanValue(isolate));
11016 :
11017 : value = CompileRun("x");
11018 12 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
11019 :
11020 : value = CompileRun("f()");
11021 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11022 :
11023 : CompileRun("y = 43");
11024 6 : CHECK_EQ(1, shadow_y_setter_call_count);
11025 : value = CompileRun("y");
11026 6 : CHECK_EQ(1, shadow_y_getter_call_count);
11027 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11028 6 : }
11029 :
11030 26645 : THREADED_TEST(ShadowObjectAndDataProperty) {
11031 : // Lite mode doesn't make use of feedback vectors, which is what we
11032 : // want to ensure has the correct form.
11033 : if (i::FLAG_lite_mode) return;
11034 : // This test mimics the kind of shadow property the Chromium embedder
11035 : // uses for undeclared globals. The IC subsystem has special handling
11036 : // for this case, using a PREMONOMORPHIC state to delay entering
11037 : // MONOMORPHIC state until enough information is available to support
11038 : // efficient access and good feedback for optimization.
11039 6 : v8::Isolate* isolate = CcTest::isolate();
11040 12 : v8::HandleScope handle_scope(isolate);
11041 :
11042 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11043 6 : LocalContext context(nullptr, global_template);
11044 :
11045 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11046 12 : t->InstanceTemplate()->SetHandler(
11047 6 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11048 :
11049 6 : Local<Value> o = t->GetFunction(context.local())
11050 : .ToLocalChecked()
11051 : ->NewInstance(context.local())
11052 : .ToLocalChecked();
11053 24 : CHECK(context->Global()
11054 : ->Set(context.local(), v8_str("__proto__"), o)
11055 : .FromJust());
11056 :
11057 : CompileRun(
11058 : "function foo(x) { i = x; }"
11059 : "foo(0)");
11060 :
11061 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11062 12 : v8::Utils::OpenHandle(*context->Global()
11063 18 : ->Get(context.local(), v8_str("foo"))
11064 : .ToLocalChecked())));
11065 6 : CHECK(foo->has_feedback_vector());
11066 : i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11067 : i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11068 6 : CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11069 6 : CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11070 : CompileRun("foo(1)");
11071 6 : CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11072 : // We go a bit further, checking that the form of monomorphism is
11073 : // a PropertyCell in the vector. This is because we want to make sure
11074 : // we didn't settle for a "poor man's monomorphism," such as a
11075 : // slow_stub bailout which would mean a trip to the runtime on all
11076 : // subsequent stores, and a lack of feedback for the optimizing
11077 : // compiler downstream.
11078 : i::HeapObject heap_object;
11079 12 : CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11080 6 : CHECK(heap_object->IsPropertyCell());
11081 : }
11082 :
11083 26645 : THREADED_TEST(ShadowObjectAndDataPropertyTurbo) {
11084 : // This test is the same as the previous one except that it triggers
11085 : // optimization of {foo} after its first invocation.
11086 6 : i::FLAG_allow_natives_syntax = true;
11087 :
11088 : if (i::FLAG_lite_mode) return;
11089 6 : v8::Isolate* isolate = CcTest::isolate();
11090 12 : v8::HandleScope handle_scope(isolate);
11091 :
11092 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11093 6 : LocalContext context(nullptr, global_template);
11094 :
11095 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11096 12 : t->InstanceTemplate()->SetHandler(
11097 6 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11098 :
11099 6 : Local<Value> o = t->GetFunction(context.local())
11100 : .ToLocalChecked()
11101 : ->NewInstance(context.local())
11102 : .ToLocalChecked();
11103 24 : CHECK(context->Global()
11104 : ->Set(context.local(), v8_str("__proto__"), o)
11105 : .FromJust());
11106 :
11107 : CompileRun(
11108 : "function foo(x) { i = x; }"
11109 : "foo(0)");
11110 :
11111 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11112 12 : v8::Utils::OpenHandle(*context->Global()
11113 18 : ->Get(context.local(), v8_str("foo"))
11114 : .ToLocalChecked())));
11115 6 : CHECK(foo->has_feedback_vector());
11116 : i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11117 : i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11118 6 : CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11119 6 : CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11120 : CompileRun("%OptimizeFunctionOnNextCall(foo); foo(1)");
11121 6 : CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11122 : i::HeapObject heap_object;
11123 12 : CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11124 6 : CHECK(heap_object->IsPropertyCell());
11125 : }
11126 :
11127 26645 : THREADED_TEST(SetPrototype) {
11128 6 : LocalContext context;
11129 6 : v8::Isolate* isolate = context->GetIsolate();
11130 12 : v8::HandleScope handle_scope(isolate);
11131 :
11132 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11133 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11134 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11135 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11136 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11137 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11138 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11139 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11140 :
11141 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
11142 : .ToLocalChecked()
11143 : ->NewInstance(context.local())
11144 : .ToLocalChecked();
11145 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11146 : .ToLocalChecked()
11147 : ->NewInstance(context.local())
11148 : .ToLocalChecked();
11149 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11150 : .ToLocalChecked()
11151 : ->NewInstance(context.local())
11152 : .ToLocalChecked();
11153 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11154 : .ToLocalChecked()
11155 : ->NewInstance(context.local())
11156 : .ToLocalChecked();
11157 :
11158 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11159 : .ToLocalChecked()
11160 : ->Int32Value(context.local())
11161 : .FromJust());
11162 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11163 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11164 : .ToLocalChecked()
11165 : ->Int32Value(context.local())
11166 : .FromJust());
11167 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11168 : .ToLocalChecked()
11169 : ->Int32Value(context.local())
11170 : .FromJust());
11171 12 : CHECK(o1->SetPrototype(context.local(), o2).FromJust());
11172 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11173 : .ToLocalChecked()
11174 : ->Int32Value(context.local())
11175 : .FromJust());
11176 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11177 : .ToLocalChecked()
11178 : ->Int32Value(context.local())
11179 : .FromJust());
11180 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11181 : .ToLocalChecked()
11182 : ->Int32Value(context.local())
11183 : .FromJust());
11184 12 : CHECK(o2->SetPrototype(context.local(), o3).FromJust());
11185 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11186 : .ToLocalChecked()
11187 : ->Int32Value(context.local())
11188 : .FromJust());
11189 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11190 : .ToLocalChecked()
11191 : ->Int32Value(context.local())
11192 : .FromJust());
11193 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11194 : .ToLocalChecked()
11195 : ->Int32Value(context.local())
11196 : .FromJust());
11197 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
11198 : .ToLocalChecked()
11199 : ->Int32Value(context.local())
11200 : .FromJust());
11201 :
11202 : Local<Value> proto =
11203 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
11204 6 : CHECK(proto->IsObject());
11205 12 : CHECK(proto.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11206 :
11207 6 : Local<Value> proto0 = o0->GetPrototype();
11208 6 : CHECK(proto0->IsObject());
11209 12 : CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11210 :
11211 6 : Local<Value> proto1 = o1->GetPrototype();
11212 6 : CHECK(proto1->IsObject());
11213 12 : CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
11214 :
11215 6 : Local<Value> proto2 = o2->GetPrototype();
11216 6 : CHECK(proto2->IsObject());
11217 12 : CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
11218 6 : }
11219 :
11220 :
11221 : // Getting property names of an object with a prototype chain that
11222 : // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11223 : // crash the runtime.
11224 26645 : THREADED_TEST(Regress91517) {
11225 6 : i::FLAG_allow_natives_syntax = true;
11226 6 : LocalContext context;
11227 6 : v8::Isolate* isolate = context->GetIsolate();
11228 12 : v8::HandleScope handle_scope(isolate);
11229 :
11230 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11231 24 : t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11232 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11233 24 : t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11234 24 : t2->InstanceTemplate()->Set(v8_str("objects"),
11235 6 : v8::ObjectTemplate::New(isolate));
11236 24 : t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11237 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11238 24 : t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11239 6 : Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11240 24 : t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11241 :
11242 : // Force dictionary-based properties.
11243 : i::ScopedVector<char> name_buf(1024);
11244 12006 : for (int i = 1; i <= 1000; i++) {
11245 6000 : i::SNPrintF(name_buf, "sdf%d", i);
11246 24000 : t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11247 : }
11248 :
11249 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11250 : .ToLocalChecked()
11251 : ->NewInstance(context.local())
11252 : .ToLocalChecked();
11253 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11254 : .ToLocalChecked()
11255 : ->NewInstance(context.local())
11256 : .ToLocalChecked();
11257 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11258 : .ToLocalChecked()
11259 : ->NewInstance(context.local())
11260 : .ToLocalChecked();
11261 6 : Local<v8::Object> o4 = t4->GetFunction(context.local())
11262 : .ToLocalChecked()
11263 : ->NewInstance(context.local())
11264 : .ToLocalChecked();
11265 :
11266 12 : CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11267 12 : CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11268 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11269 :
11270 : // Call the runtime version of GetOwnPropertyNames() on the natively
11271 : // created object through JavaScript.
11272 24 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11273 : // PROPERTY_FILTER_NONE = 0
11274 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11275 :
11276 6 : ExpectInt32("names.length", 1);
11277 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11278 : ExpectFalse("names.indexOf(\"boo\") >= 0");
11279 : ExpectFalse("names.indexOf(\"foo\") >= 0");
11280 : ExpectFalse("names.indexOf(\"fuz1\") >= 0");
11281 : ExpectFalse("names.indexOf(\"objects\") >= 0");
11282 : ExpectFalse("names.indexOf(\"fuz2\") >= 0");
11283 : ExpectTrue("names[1005] == undefined");
11284 6 : }
11285 :
11286 :
11287 26645 : THREADED_TEST(FunctionReadOnlyPrototype) {
11288 6 : LocalContext context;
11289 6 : v8::Isolate* isolate = context->GetIsolate();
11290 12 : v8::HandleScope handle_scope(isolate);
11291 :
11292 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11293 24 : t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11294 6 : t1->ReadOnlyPrototype();
11295 30 : CHECK(context->Global()
11296 : ->Set(context.local(), v8_str("func1"),
11297 : t1->GetFunction(context.local()).ToLocalChecked())
11298 : .FromJust());
11299 : // Configured value of ReadOnly flag.
11300 6 : CHECK(
11301 : CompileRun(
11302 : "(function() {"
11303 : " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11304 : " return (descriptor['writable'] == false);"
11305 : "})()")
11306 : ->BooleanValue(isolate));
11307 12 : CHECK_EQ(
11308 : 42,
11309 : CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11310 12 : CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11311 : ->Int32Value(context.local())
11312 : .FromJust());
11313 :
11314 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11315 24 : t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11316 30 : CHECK(context->Global()
11317 : ->Set(context.local(), v8_str("func2"),
11318 : t2->GetFunction(context.local()).ToLocalChecked())
11319 : .FromJust());
11320 : // Default value of ReadOnly flag.
11321 6 : CHECK(
11322 : CompileRun(
11323 : "(function() {"
11324 : " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11325 : " return (descriptor['writable'] == true);"
11326 : "})()")
11327 : ->BooleanValue(isolate));
11328 12 : CHECK_EQ(
11329 : 42,
11330 : CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11331 6 : }
11332 :
11333 :
11334 26645 : THREADED_TEST(SetPrototypeThrows) {
11335 6 : LocalContext context;
11336 6 : v8::Isolate* isolate = context->GetIsolate();
11337 12 : v8::HandleScope handle_scope(isolate);
11338 :
11339 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11340 :
11341 6 : Local<v8::Object> o0 = t->GetFunction(context.local())
11342 : .ToLocalChecked()
11343 : ->NewInstance(context.local())
11344 : .ToLocalChecked();
11345 6 : Local<v8::Object> o1 = t->GetFunction(context.local())
11346 : .ToLocalChecked()
11347 : ->NewInstance(context.local())
11348 : .ToLocalChecked();
11349 :
11350 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11351 : // If setting the prototype leads to the cycle, SetPrototype should
11352 : // return false and keep VM in sane state.
11353 12 : v8::TryCatch try_catch(isolate);
11354 12 : CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11355 6 : CHECK(!try_catch.HasCaught());
11356 6 : CHECK(!CcTest::i_isolate()->has_pending_exception());
11357 :
11358 12 : CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11359 : ->Int32Value(context.local())
11360 : .FromJust());
11361 6 : }
11362 :
11363 :
11364 26645 : THREADED_TEST(FunctionRemovePrototype) {
11365 6 : LocalContext context;
11366 6 : v8::Isolate* isolate = context->GetIsolate();
11367 12 : v8::HandleScope handle_scope(isolate);
11368 :
11369 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11370 6 : t1->RemovePrototype();
11371 6 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11372 6 : CHECK(!fun->IsConstructor());
11373 24 : CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11374 6 : CHECK(!CompileRun("'prototype' in fun")->BooleanValue(isolate));
11375 :
11376 12 : v8::TryCatch try_catch(isolate);
11377 : CompileRun("new fun()");
11378 6 : CHECK(try_catch.HasCaught());
11379 :
11380 6 : try_catch.Reset();
11381 6 : CHECK(fun->NewInstance(context.local()).IsEmpty());
11382 6 : CHECK(try_catch.HasCaught());
11383 6 : }
11384 :
11385 :
11386 26645 : THREADED_TEST(GetterSetterExceptions) {
11387 6 : LocalContext context;
11388 6 : v8::Isolate* isolate = context->GetIsolate();
11389 12 : v8::HandleScope handle_scope(isolate);
11390 : CompileRun(
11391 : "function Foo() { };"
11392 : "function Throw() { throw 5; };"
11393 : "var x = { };"
11394 : "x.__defineSetter__('set', Throw);"
11395 : "x.__defineGetter__('get', Throw);");
11396 : Local<v8::Object> x = Local<v8::Object>::Cast(
11397 24 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11398 12 : v8::TryCatch try_catch(isolate);
11399 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11400 : .IsNothing());
11401 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11402 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11403 : .IsNothing());
11404 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11405 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11406 : .IsNothing());
11407 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11408 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11409 : .IsNothing());
11410 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11411 6 : }
11412 :
11413 :
11414 26645 : THREADED_TEST(Constructor) {
11415 6 : LocalContext context;
11416 6 : v8::Isolate* isolate = context->GetIsolate();
11417 12 : v8::HandleScope handle_scope(isolate);
11418 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11419 6 : templ->SetClassName(v8_str("Fun"));
11420 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11421 24 : CHECK(
11422 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11423 : Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11424 : i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11425 6 : CHECK(obj->IsJSObject());
11426 : Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11427 6 : CHECK(value->BooleanValue(isolate));
11428 6 : }
11429 :
11430 :
11431 26645 : THREADED_TEST(FunctionDescriptorException) {
11432 6 : LocalContext context;
11433 6 : v8::Isolate* isolate = context->GetIsolate();
11434 12 : v8::HandleScope handle_scope(isolate);
11435 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11436 6 : templ->SetClassName(v8_str("Fun"));
11437 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11438 24 : CHECK(
11439 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11440 : Local<Value> value = CompileRun(
11441 : "function test() {"
11442 : " try {"
11443 : " (new Fun()).blah()"
11444 : " } catch (e) {"
11445 : " var str = String(e);"
11446 : // " if (str.indexOf('TypeError') == -1) return 1;"
11447 : // " if (str.indexOf('[object Fun]') != -1) return 2;"
11448 : // " if (str.indexOf('#<Fun>') == -1) return 3;"
11449 : " return 0;"
11450 : " }"
11451 : " return 4;"
11452 : "}"
11453 : "test();");
11454 12 : CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11455 6 : }
11456 :
11457 :
11458 26645 : THREADED_TEST(EvalAliasedDynamic) {
11459 6 : LocalContext current;
11460 12 : v8::HandleScope scope(current->GetIsolate());
11461 :
11462 : // Tests where aliased eval can only be resolved dynamically.
11463 : Local<Script> script = v8_compile(
11464 : "function f(x) { "
11465 : " var foo = 2;"
11466 : " with (x) { return eval('foo'); }"
11467 : "}"
11468 : "foo = 0;"
11469 : "result1 = f(new Object());"
11470 : "result2 = f(this);"
11471 : "var x = new Object();"
11472 : "x.eval = function(x) { return 1; };"
11473 : "result3 = f(x);");
11474 6 : script->Run(current.local()).ToLocalChecked();
11475 30 : CHECK_EQ(2, current->Global()
11476 : ->Get(current.local(), v8_str("result1"))
11477 : .ToLocalChecked()
11478 : ->Int32Value(current.local())
11479 : .FromJust());
11480 30 : CHECK_EQ(0, current->Global()
11481 : ->Get(current.local(), v8_str("result2"))
11482 : .ToLocalChecked()
11483 : ->Int32Value(current.local())
11484 : .FromJust());
11485 30 : CHECK_EQ(1, current->Global()
11486 : ->Get(current.local(), v8_str("result3"))
11487 : .ToLocalChecked()
11488 : ->Int32Value(current.local())
11489 : .FromJust());
11490 :
11491 12 : v8::TryCatch try_catch(current->GetIsolate());
11492 : script = v8_compile(
11493 : "function f(x) { "
11494 : " var bar = 2;"
11495 : " with (x) { return eval('bar'); }"
11496 : "}"
11497 : "result4 = f(this)");
11498 6 : script->Run(current.local()).ToLocalChecked();
11499 6 : CHECK(!try_catch.HasCaught());
11500 30 : CHECK_EQ(2, current->Global()
11501 : ->Get(current.local(), v8_str("result4"))
11502 : .ToLocalChecked()
11503 : ->Int32Value(current.local())
11504 : .FromJust());
11505 :
11506 6 : try_catch.Reset();
11507 6 : }
11508 :
11509 :
11510 26645 : THREADED_TEST(CrossEval) {
11511 12 : v8::HandleScope scope(CcTest::isolate());
11512 6 : LocalContext other;
11513 6 : LocalContext current;
11514 :
11515 6 : Local<String> token = v8_str("<security token>");
11516 6 : other->SetSecurityToken(token);
11517 6 : current->SetSecurityToken(token);
11518 :
11519 : // Set up reference from current to other.
11520 30 : CHECK(current->Global()
11521 : ->Set(current.local(), v8_str("other"), other->Global())
11522 : .FromJust());
11523 :
11524 : // Check that new variables are introduced in other context.
11525 : Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11526 6 : script->Run(current.local()).ToLocalChecked();
11527 : Local<Value> foo =
11528 24 : other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11529 12 : CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11530 24 : CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11531 :
11532 : // Check that writing to non-existing properties introduces them in
11533 : // the other context.
11534 : script = v8_compile("other.eval('na = 1234')");
11535 6 : script->Run(current.local()).ToLocalChecked();
11536 30 : CHECK_EQ(1234, other->Global()
11537 : ->Get(current.local(), v8_str("na"))
11538 : .ToLocalChecked()
11539 : ->Int32Value(other.local())
11540 : .FromJust());
11541 24 : CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11542 :
11543 : // Check that global variables in current context are not visible in other
11544 : // context.
11545 12 : v8::TryCatch try_catch(CcTest::isolate());
11546 : script = v8_compile("var bar = 42; other.eval('bar');");
11547 12 : CHECK(script->Run(current.local()).IsEmpty());
11548 6 : CHECK(try_catch.HasCaught());
11549 6 : try_catch.Reset();
11550 :
11551 : // Check that local variables in current context are not visible in other
11552 : // context.
11553 : script = v8_compile(
11554 : "(function() { "
11555 : " var baz = 87;"
11556 : " return other.eval('baz');"
11557 : "})();");
11558 12 : CHECK(script->Run(current.local()).IsEmpty());
11559 6 : CHECK(try_catch.HasCaught());
11560 6 : try_catch.Reset();
11561 :
11562 : // Check that global variables in the other environment are visible
11563 : // when evaluting code.
11564 24 : CHECK(other->Global()
11565 : ->Set(other.local(), v8_str("bis"), v8_num(1234))
11566 : .FromJust());
11567 : script = v8_compile("other.eval('bis')");
11568 18 : CHECK_EQ(1234, script->Run(current.local())
11569 : .ToLocalChecked()
11570 : ->Int32Value(current.local())
11571 : .FromJust());
11572 6 : CHECK(!try_catch.HasCaught());
11573 :
11574 : // Check that the 'this' pointer points to the global object evaluating
11575 : // code.
11576 30 : CHECK(other->Global()
11577 : ->Set(current.local(), v8_str("t"), other->Global())
11578 : .FromJust());
11579 : script = v8_compile("other.eval('this == t')");
11580 6 : Local<Value> result = script->Run(current.local()).ToLocalChecked();
11581 6 : CHECK(result->IsTrue());
11582 6 : CHECK(!try_catch.HasCaught());
11583 :
11584 : // Check that variables introduced in with-statement are not visible in
11585 : // other context.
11586 : script = v8_compile("with({x:2}){other.eval('x')}");
11587 12 : CHECK(script->Run(current.local()).IsEmpty());
11588 6 : CHECK(try_catch.HasCaught());
11589 6 : try_catch.Reset();
11590 :
11591 : // Check that you cannot use 'eval.call' with another object than the
11592 : // current global object.
11593 : script = v8_compile("other.y = 1; eval.call(other, 'y')");
11594 12 : CHECK(script->Run(current.local()).IsEmpty());
11595 6 : CHECK(try_catch.HasCaught());
11596 6 : }
11597 :
11598 :
11599 : // Test that calling eval in a context which has been detached from
11600 : // its global proxy works.
11601 26645 : THREADED_TEST(EvalInDetachedGlobal) {
11602 6 : v8::Isolate* isolate = CcTest::isolate();
11603 12 : v8::HandleScope scope(isolate);
11604 :
11605 6 : v8::Local<Context> context0 = Context::New(isolate);
11606 6 : v8::Local<Context> context1 = Context::New(isolate);
11607 6 : Local<String> token = v8_str("<security token>");
11608 6 : context0->SetSecurityToken(token);
11609 6 : context1->SetSecurityToken(token);
11610 :
11611 : // Set up function in context0 that uses eval from context0.
11612 6 : context0->Enter();
11613 : v8::Local<v8::Value> fun = CompileRun(
11614 : "var x = 42;"
11615 : "(function() {"
11616 : " var e = eval;"
11617 : " return function(s) { return e(s); }"
11618 6 : "})()");
11619 6 : context0->Exit();
11620 :
11621 : // Put the function into context1 and call it before and after
11622 : // detaching the global. Before detaching, the call succeeds and
11623 : // after detaching undefined is returned.
11624 6 : context1->Enter();
11625 24 : CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11626 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11627 12 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11628 6 : context0->DetachGlobal();
11629 : x_value = CompileRun("fun('x')");
11630 6 : CHECK(x_value->IsUndefined());
11631 6 : context1->Exit();
11632 6 : }
11633 :
11634 :
11635 26645 : THREADED_TEST(CrossLazyLoad) {
11636 12 : v8::HandleScope scope(CcTest::isolate());
11637 6 : LocalContext other;
11638 6 : LocalContext current;
11639 :
11640 6 : Local<String> token = v8_str("<security token>");
11641 6 : other->SetSecurityToken(token);
11642 6 : current->SetSecurityToken(token);
11643 :
11644 : // Set up reference from current to other.
11645 30 : CHECK(current->Global()
11646 : ->Set(current.local(), v8_str("other"), other->Global())
11647 : .FromJust());
11648 :
11649 : // Trigger lazy loading in other context.
11650 : Local<Script> script = v8_compile("other.eval('new Date(42)')");
11651 6 : Local<Value> value = script->Run(current.local()).ToLocalChecked();
11652 12 : CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11653 6 : }
11654 :
11655 :
11656 48 : static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11657 48 : ApiTestFuzzer::Fuzz();
11658 48 : if (args.IsConstructCall()) {
11659 6 : if (args[0]->IsInt32()) {
11660 6 : args.GetReturnValue().Set(
11661 : v8_num(-args[0]
11662 18 : ->Int32Value(args.GetIsolate()->GetCurrentContext())
11663 : .FromJust()));
11664 6 : return;
11665 : }
11666 : }
11667 :
11668 : args.GetReturnValue().Set(args[0]);
11669 : }
11670 :
11671 :
11672 : // Test that a call handler can be set for objects which will allow
11673 : // non-function objects created through the API to be called as
11674 : // functions.
11675 26645 : THREADED_TEST(CallAsFunction) {
11676 6 : LocalContext context;
11677 6 : v8::Isolate* isolate = context->GetIsolate();
11678 12 : v8::HandleScope scope(isolate);
11679 :
11680 : {
11681 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11682 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11683 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11684 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11685 : .ToLocalChecked()
11686 : ->NewInstance(context.local())
11687 : .ToLocalChecked();
11688 24 : CHECK(context->Global()
11689 : ->Set(context.local(), v8_str("obj"), instance)
11690 : .FromJust());
11691 12 : v8::TryCatch try_catch(isolate);
11692 : Local<Value> value;
11693 6 : CHECK(!try_catch.HasCaught());
11694 :
11695 : value = CompileRun("obj(42)");
11696 6 : CHECK(!try_catch.HasCaught());
11697 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11698 :
11699 : value = CompileRun("(function(o){return o(49)})(obj)");
11700 6 : CHECK(!try_catch.HasCaught());
11701 12 : CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11702 :
11703 : // test special case of call as function
11704 : value = CompileRun("[obj]['0'](45)");
11705 6 : CHECK(!try_catch.HasCaught());
11706 12 : CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11707 :
11708 : value = CompileRun(
11709 : "obj.call = Function.prototype.call;"
11710 : "obj.call(null, 87)");
11711 6 : CHECK(!try_catch.HasCaught());
11712 12 : CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11713 :
11714 : // Regression tests for bug #1116356: Calling call through call/apply
11715 : // must work for non-function receivers.
11716 : const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11717 : value = CompileRun(apply_99);
11718 6 : CHECK(!try_catch.HasCaught());
11719 12 : CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11720 :
11721 : const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11722 : value = CompileRun(call_17);
11723 6 : CHECK(!try_catch.HasCaught());
11724 12 : CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11725 :
11726 : // Check that the call-as-function handler can be called through new.
11727 : value = CompileRun("new obj(43)");
11728 6 : CHECK(!try_catch.HasCaught());
11729 12 : CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11730 :
11731 : // Check that the call-as-function handler can be called through
11732 : // the API.
11733 6 : v8::Local<Value> args[] = {v8_num(28)};
11734 12 : value = instance->CallAsFunction(context.local(), instance, 1, args)
11735 : .ToLocalChecked();
11736 6 : CHECK(!try_catch.HasCaught());
11737 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11738 : }
11739 :
11740 : {
11741 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11742 6 : Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11743 : USE(instance_template);
11744 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11745 : .ToLocalChecked()
11746 : ->NewInstance(context.local())
11747 : .ToLocalChecked();
11748 24 : CHECK(context->Global()
11749 : ->Set(context.local(), v8_str("obj2"), instance)
11750 : .FromJust());
11751 12 : v8::TryCatch try_catch(isolate);
11752 : Local<Value> value;
11753 6 : CHECK(!try_catch.HasCaught());
11754 :
11755 : // Call an object without call-as-function handler through the JS
11756 : value = CompileRun("obj2(28)");
11757 6 : CHECK(value.IsEmpty());
11758 6 : CHECK(try_catch.HasCaught());
11759 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11760 : // TODO(verwaest): Better message
11761 6 : CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11762 6 : try_catch.Reset();
11763 :
11764 : // Call an object without call-as-function handler through the API
11765 6 : v8::Local<Value> args[] = {v8_num(28)};
11766 12 : CHECK(
11767 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11768 6 : CHECK(try_catch.HasCaught());
11769 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11770 6 : CHECK_EQ(0,
11771 : strcmp("TypeError: object is not a function", *exception_value2));
11772 6 : try_catch.Reset();
11773 : }
11774 :
11775 : {
11776 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11777 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11778 6 : instance_template->SetCallAsFunctionHandler(ThrowValue);
11779 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11780 : .ToLocalChecked()
11781 : ->NewInstance(context.local())
11782 : .ToLocalChecked();
11783 24 : CHECK(context->Global()
11784 : ->Set(context.local(), v8_str("obj3"), instance)
11785 : .FromJust());
11786 12 : v8::TryCatch try_catch(isolate);
11787 : Local<Value> value;
11788 6 : CHECK(!try_catch.HasCaught());
11789 :
11790 : // Catch the exception which is thrown by call-as-function handler
11791 : value = CompileRun("obj3(22)");
11792 6 : CHECK(try_catch.HasCaught());
11793 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11794 6 : CHECK_EQ(0, strcmp("22", *exception_value1));
11795 6 : try_catch.Reset();
11796 :
11797 6 : v8::Local<Value> args[] = {v8_num(23)};
11798 12 : CHECK(
11799 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11800 6 : CHECK(try_catch.HasCaught());
11801 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11802 6 : CHECK_EQ(0, strcmp("23", *exception_value2));
11803 6 : try_catch.Reset();
11804 : }
11805 :
11806 : {
11807 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11808 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11809 6 : instance_template->SetCallAsFunctionHandler(ReturnThis);
11810 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11811 : .ToLocalChecked()
11812 : ->NewInstance(context.local())
11813 : .ToLocalChecked();
11814 :
11815 : Local<v8::Value> a1 =
11816 : instance
11817 6 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11818 6 : nullptr)
11819 : .ToLocalChecked();
11820 6 : CHECK(a1->StrictEquals(instance));
11821 : Local<v8::Value> a2 =
11822 12 : instance->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11823 : .ToLocalChecked();
11824 6 : CHECK(a2->StrictEquals(instance));
11825 : Local<v8::Value> a3 =
11826 12 : instance->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11827 : .ToLocalChecked();
11828 6 : CHECK(a3->StrictEquals(instance));
11829 : Local<v8::Value> a4 =
11830 18 : instance->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11831 : .ToLocalChecked();
11832 6 : CHECK(a4->StrictEquals(instance));
11833 : Local<v8::Value> a5 =
11834 12 : instance->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11835 : .ToLocalChecked();
11836 6 : CHECK(a5->StrictEquals(instance));
11837 : }
11838 :
11839 : {
11840 : CompileRun(
11841 : "function ReturnThisSloppy() {"
11842 : " return this;"
11843 : "}"
11844 : "function ReturnThisStrict() {"
11845 : " 'use strict';"
11846 : " return this;"
11847 : "}");
11848 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11849 12 : context->Global()
11850 18 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
11851 : .ToLocalChecked());
11852 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
11853 12 : context->Global()
11854 18 : ->Get(context.local(), v8_str("ReturnThisStrict"))
11855 : .ToLocalChecked());
11856 :
11857 : Local<v8::Value> a1 =
11858 : ReturnThisSloppy
11859 6 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11860 6 : nullptr)
11861 : .ToLocalChecked();
11862 12 : CHECK(a1->StrictEquals(context->Global()));
11863 : Local<v8::Value> a2 =
11864 : ReturnThisSloppy
11865 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11866 : .ToLocalChecked();
11867 12 : CHECK(a2->StrictEquals(context->Global()));
11868 : Local<v8::Value> a3 =
11869 : ReturnThisSloppy
11870 12 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11871 : .ToLocalChecked();
11872 6 : CHECK(a3->IsNumberObject());
11873 6 : CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11874 : Local<v8::Value> a4 =
11875 : ReturnThisSloppy
11876 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11877 : .ToLocalChecked();
11878 6 : CHECK(a4->IsStringObject());
11879 18 : CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11880 : Local<v8::Value> a5 =
11881 : ReturnThisSloppy
11882 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11883 : .ToLocalChecked();
11884 6 : CHECK(a5->IsBooleanObject());
11885 6 : CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11886 :
11887 : Local<v8::Value> a6 =
11888 : ReturnThisStrict
11889 6 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11890 6 : nullptr)
11891 : .ToLocalChecked();
11892 6 : CHECK(a6->IsUndefined());
11893 : Local<v8::Value> a7 =
11894 : ReturnThisStrict
11895 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11896 : .ToLocalChecked();
11897 6 : CHECK(a7->IsNull());
11898 : Local<v8::Value> a8 =
11899 : ReturnThisStrict
11900 12 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11901 : .ToLocalChecked();
11902 6 : CHECK(a8->StrictEquals(v8_num(42)));
11903 : Local<v8::Value> a9 =
11904 : ReturnThisStrict
11905 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11906 : .ToLocalChecked();
11907 12 : CHECK(a9->StrictEquals(v8_str("hello")));
11908 : Local<v8::Value> a10 =
11909 : ReturnThisStrict
11910 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11911 : .ToLocalChecked();
11912 6 : CHECK(a10->StrictEquals(v8::True(isolate)));
11913 : }
11914 6 : }
11915 :
11916 :
11917 : // Check whether a non-function object is callable.
11918 26645 : THREADED_TEST(CallableObject) {
11919 6 : LocalContext context;
11920 6 : v8::Isolate* isolate = context->GetIsolate();
11921 12 : v8::HandleScope scope(isolate);
11922 :
11923 : {
11924 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11925 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11926 : Local<Object> instance =
11927 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11928 12 : v8::TryCatch try_catch(isolate);
11929 :
11930 6 : CHECK(instance->IsCallable());
11931 6 : CHECK(!try_catch.HasCaught());
11932 : }
11933 :
11934 : {
11935 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11936 : Local<Object> instance =
11937 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11938 12 : v8::TryCatch try_catch(isolate);
11939 :
11940 6 : CHECK(!instance->IsCallable());
11941 6 : CHECK(!try_catch.HasCaught());
11942 : }
11943 :
11944 : {
11945 : Local<FunctionTemplate> function_template =
11946 6 : FunctionTemplate::New(isolate, call_as_function);
11947 : Local<Function> function =
11948 6 : function_template->GetFunction(context.local()).ToLocalChecked();
11949 : Local<Object> instance = function;
11950 12 : v8::TryCatch try_catch(isolate);
11951 :
11952 6 : CHECK(instance->IsCallable());
11953 6 : CHECK(!try_catch.HasCaught());
11954 : }
11955 :
11956 : {
11957 6 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11958 : Local<Function> function =
11959 6 : function_template->GetFunction(context.local()).ToLocalChecked();
11960 : Local<Object> instance = function;
11961 12 : v8::TryCatch try_catch(isolate);
11962 :
11963 6 : CHECK(instance->IsCallable());
11964 6 : CHECK(!try_catch.HasCaught());
11965 : }
11966 6 : }
11967 :
11968 :
11969 26645 : THREADED_TEST(Regress567998) {
11970 6 : LocalContext env;
11971 12 : v8::HandleScope scope(env->GetIsolate());
11972 :
11973 : Local<v8::FunctionTemplate> desc =
11974 6 : v8::FunctionTemplate::New(env->GetIsolate());
11975 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
11976 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
11977 :
11978 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
11979 : .ToLocalChecked()
11980 : ->NewInstance(env.local())
11981 : .ToLocalChecked();
11982 24 : CHECK(
11983 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
11984 :
11985 6 : ExpectString("undetectable.toString()", "[object Object]");
11986 6 : ExpectString("typeof undetectable", "undefined");
11987 6 : ExpectString("typeof(undetectable)", "undefined");
11988 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
11989 6 : ExpectBoolean("typeof undetectable == 'object'", false);
11990 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
11991 6 : ExpectBoolean("!undetectable", true);
11992 :
11993 6 : ExpectObject("true&&undetectable", obj);
11994 6 : ExpectBoolean("false&&undetectable", false);
11995 6 : ExpectBoolean("true||undetectable", true);
11996 6 : ExpectObject("false||undetectable", obj);
11997 :
11998 6 : ExpectObject("undetectable&&true", obj);
11999 6 : ExpectObject("undetectable&&false", obj);
12000 6 : ExpectBoolean("undetectable||true", true);
12001 6 : ExpectBoolean("undetectable||false", false);
12002 :
12003 6 : ExpectBoolean("undetectable==null", true);
12004 6 : ExpectBoolean("null==undetectable", true);
12005 6 : ExpectBoolean("undetectable==undefined", true);
12006 6 : ExpectBoolean("undefined==undetectable", true);
12007 6 : ExpectBoolean("undetectable==undetectable", true);
12008 :
12009 6 : ExpectBoolean("undetectable===null", false);
12010 6 : ExpectBoolean("null===undetectable", false);
12011 6 : ExpectBoolean("undetectable===undefined", false);
12012 6 : ExpectBoolean("undefined===undetectable", false);
12013 6 : ExpectBoolean("undetectable===undetectable", true);
12014 6 : }
12015 :
12016 :
12017 1206 : static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
12018 2412 : v8::HandleScope scope(isolate);
12019 1206 : if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
12020 1201200 : for (int i = 0; i < iterations; i++) {
12021 600000 : Local<v8::Number> n(v8::Integer::New(isolate, 42));
12022 : }
12023 1200 : return Recurse(isolate, depth - 1, iterations);
12024 : }
12025 :
12026 :
12027 26645 : THREADED_TEST(HandleIteration) {
12028 : static const int kIterations = 500;
12029 : static const int kNesting = 200;
12030 6 : LocalContext context;
12031 6 : v8::Isolate* isolate = context->GetIsolate();
12032 12 : v8::HandleScope scope0(isolate);
12033 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12034 : {
12035 12 : v8::HandleScope scope1(isolate);
12036 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12037 3006 : for (int i = 0; i < kIterations; i++) {
12038 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12039 3000 : CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12040 : }
12041 :
12042 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12043 : {
12044 12 : v8::HandleScope scope2(CcTest::isolate());
12045 6006 : for (int j = 0; j < kIterations; j++) {
12046 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12047 3000 : CHECK_EQ(j + 1 + kIterations,
12048 : v8::HandleScope::NumberOfHandles(isolate));
12049 : }
12050 : }
12051 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12052 : }
12053 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12054 6 : CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12055 6 : }
12056 :
12057 :
12058 1100 : static void InterceptorCallICFastApi(
12059 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12060 1100 : ApiTestFuzzer::Fuzz();
12061 1100 : CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12062 : int* call_count =
12063 1100 : reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12064 1100 : ++(*call_count);
12065 1100 : if ((*call_count) % 20 == 0) {
12066 55 : CcTest::CollectAllGarbage();
12067 : }
12068 1100 : }
12069 :
12070 2200 : static void FastApiCallback_TrivialSignature(
12071 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12072 2200 : ApiTestFuzzer::Fuzz();
12073 2200 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12074 2200 : v8::Isolate* isolate = CcTest::isolate();
12075 2200 : CHECK_EQ(isolate, args.GetIsolate());
12076 6600 : CHECK(args.This()
12077 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12078 : .FromJust());
12079 8800 : CHECK(args.Data()
12080 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12081 : .FromJust());
12082 2200 : args.GetReturnValue().Set(
12083 6600 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12084 2200 : }
12085 :
12086 : static void FastApiCallback_SimpleSignature(
12087 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12088 : ApiTestFuzzer::Fuzz();
12089 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12090 : v8::Isolate* isolate = CcTest::isolate();
12091 : CHECK_EQ(isolate, args.GetIsolate());
12092 : CHECK(args.This()
12093 : ->GetPrototype()
12094 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12095 : .FromJust());
12096 : CHECK(args.Data()
12097 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12098 : .FromJust());
12099 : // Note, we're using HasRealNamedProperty instead of Has to avoid
12100 : // invoking the interceptor again.
12101 : CHECK(args.Holder()
12102 : ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12103 : .FromJust());
12104 : args.GetReturnValue().Set(
12105 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12106 : }
12107 :
12108 :
12109 : // Helper to maximize the odds of object moving.
12110 192 : static void GenerateSomeGarbage() {
12111 : CompileRun(
12112 : "var garbage;"
12113 : "for (var i = 0; i < 1000; i++) {"
12114 : " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12115 : "}"
12116 : "garbage = undefined;");
12117 192 : }
12118 :
12119 :
12120 180 : void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12121 : static int count = 0;
12122 180 : if (count++ % 3 == 0) {
12123 60 : CcTest::CollectAllGarbage();
12124 : // This should move the stub
12125 60 : GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12126 : }
12127 180 : }
12128 :
12129 :
12130 26645 : THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12131 6 : LocalContext context;
12132 6 : v8::Isolate* isolate = context->GetIsolate();
12133 12 : v8::HandleScope scope(isolate);
12134 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12135 6 : v8::ObjectTemplate::New(isolate);
12136 12 : nativeobject_templ->Set(isolate, "callback",
12137 : v8::FunctionTemplate::New(isolate,
12138 : DirectApiCallback));
12139 : v8::Local<v8::Object> nativeobject_obj =
12140 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12141 24 : CHECK(context->Global()
12142 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12143 : .FromJust());
12144 : // call the api function multiple times to ensure direct call stub creation.
12145 : CompileRun(
12146 : "function f() {"
12147 : " for (var i = 1; i <= 30; i++) {"
12148 : " nativeobject.callback();"
12149 : " }"
12150 : "}"
12151 : "f();");
12152 6 : }
12153 :
12154 30 : void ThrowingDirectApiCallback(
12155 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12156 60 : args.GetIsolate()->ThrowException(v8_str("g"));
12157 30 : }
12158 :
12159 26645 : THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12160 6 : LocalContext context;
12161 6 : v8::Isolate* isolate = context->GetIsolate();
12162 12 : v8::HandleScope scope(isolate);
12163 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12164 6 : v8::ObjectTemplate::New(isolate);
12165 12 : nativeobject_templ->Set(
12166 : isolate, "callback",
12167 : v8::FunctionTemplate::New(isolate, ThrowingDirectApiCallback));
12168 : v8::Local<v8::Object> nativeobject_obj =
12169 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12170 24 : CHECK(context->Global()
12171 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12172 : .FromJust());
12173 : // call the api function multiple times to ensure direct call stub creation.
12174 : v8::Local<Value> result = CompileRun(
12175 : "var result = '';"
12176 : "function f() {"
12177 : " for (var i = 1; i <= 5; i++) {"
12178 : " try { nativeobject.callback(); } catch (e) { result += e; }"
12179 : " }"
12180 : "}"
12181 6 : "f(); result;");
12182 18 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12183 6 : }
12184 :
12185 : static int p_getter_count_3;
12186 :
12187 341 : static Local<Value> DoDirectGetter() {
12188 341 : if (++p_getter_count_3 % 3 == 0) {
12189 110 : CcTest::CollectAllGarbage();
12190 110 : GenerateSomeGarbage();
12191 : }
12192 341 : return v8_str("Direct Getter Result");
12193 : }
12194 :
12195 341 : static void DirectGetterCallback(
12196 : Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12197 341 : CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12198 341 : info.GetReturnValue().Set(DoDirectGetter());
12199 341 : }
12200 :
12201 : template <typename Accessor>
12202 11 : static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12203 11 : LocalContext context;
12204 11 : v8::Isolate* isolate = context->GetIsolate();
12205 22 : v8::HandleScope scope(isolate);
12206 11 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12207 11 : obj->SetAccessor(v8_str("p1"), accessor);
12208 55 : CHECK(context->Global()
12209 : ->Set(context.local(), v8_str("o1"),
12210 : obj->NewInstance(context.local()).ToLocalChecked())
12211 : .FromJust());
12212 11 : p_getter_count_3 = 0;
12213 : v8::Local<v8::Value> result = CompileRun(
12214 : "function f() {"
12215 : " for (var i = 0; i < 30; i++) o1.p1;"
12216 : " return o1.p1"
12217 : "}"
12218 11 : "f();");
12219 33 : CHECK(v8_str("Direct Getter Result")
12220 : ->Equals(context.local(), result)
12221 : .FromJust());
12222 11 : CHECK_EQ(31, p_getter_count_3);
12223 11 : }
12224 :
12225 53294 : THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12226 11 : LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12227 11 : }
12228 :
12229 30 : void ThrowingDirectGetterCallback(
12230 : Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12231 60 : info.GetIsolate()->ThrowException(v8_str("g"));
12232 30 : }
12233 :
12234 26645 : THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12235 6 : LocalContext context;
12236 6 : v8::Isolate* isolate = context->GetIsolate();
12237 12 : v8::HandleScope scope(isolate);
12238 6 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12239 6 : obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12240 30 : CHECK(context->Global()
12241 : ->Set(context.local(), v8_str("o1"),
12242 : obj->NewInstance(context.local()).ToLocalChecked())
12243 : .FromJust());
12244 : v8::Local<Value> result = CompileRun(
12245 : "var result = '';"
12246 : "for (var i = 0; i < 5; i++) {"
12247 : " try { o1.p1; } catch (e) { result += e; }"
12248 : "}"
12249 6 : "result;");
12250 18 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12251 6 : }
12252 :
12253 53294 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12254 11 : int interceptor_call_count = 0;
12255 11 : v8::Isolate* isolate = CcTest::isolate();
12256 22 : v8::HandleScope scope(isolate);
12257 : v8::Local<v8::FunctionTemplate> fun_templ =
12258 11 : v8::FunctionTemplate::New(isolate);
12259 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12260 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12261 22 : v8::Local<v8::Signature>());
12262 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12263 22 : proto_templ->Set(v8_str("method"), method_templ);
12264 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12265 22 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12266 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12267 11 : v8::External::New(isolate, &interceptor_call_count)));
12268 11 : LocalContext context;
12269 : v8::Local<v8::Function> fun =
12270 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12271 11 : GenerateSomeGarbage();
12272 44 : CHECK(context->Global()
12273 : ->Set(context.local(), v8_str("o"),
12274 : fun->NewInstance(context.local()).ToLocalChecked())
12275 : .FromJust());
12276 : CompileRun(
12277 : "var result = 0;"
12278 : "for (var i = 0; i < 100; i++) {"
12279 : " result = o.method(41);"
12280 : "}");
12281 55 : CHECK_EQ(42, context->Global()
12282 : ->Get(context.local(), v8_str("result"))
12283 : .ToLocalChecked()
12284 : ->Int32Value(context.local())
12285 : .FromJust());
12286 11 : CHECK_EQ(100, interceptor_call_count);
12287 11 : }
12288 :
12289 53294 : THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12290 11 : v8::Isolate* isolate = CcTest::isolate();
12291 22 : v8::HandleScope scope(isolate);
12292 : v8::Local<v8::FunctionTemplate> fun_templ =
12293 11 : v8::FunctionTemplate::New(isolate);
12294 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12295 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12296 22 : v8::Local<v8::Signature>());
12297 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12298 22 : proto_templ->Set(v8_str("method"), method_templ);
12299 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12300 : USE(templ);
12301 11 : LocalContext context;
12302 : v8::Local<v8::Function> fun =
12303 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12304 11 : GenerateSomeGarbage();
12305 44 : CHECK(context->Global()
12306 : ->Set(context.local(), v8_str("o"),
12307 : fun->NewInstance(context.local()).ToLocalChecked())
12308 : .FromJust());
12309 : CompileRun(
12310 : "var result = 0;"
12311 : "for (var i = 0; i < 100; i++) {"
12312 : " result = o.method(41);"
12313 : "}");
12314 :
12315 55 : CHECK_EQ(42, context->Global()
12316 : ->Get(context.local(), v8_str("result"))
12317 : .ToLocalChecked()
12318 : ->Int32Value(context.local())
12319 : .FromJust());
12320 11 : }
12321 :
12322 24 : static void ThrowingGetter(Local<String> name,
12323 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12324 24 : ApiTestFuzzer::Fuzz();
12325 24 : info.GetIsolate()->ThrowException(Local<Value>());
12326 : info.GetReturnValue().SetUndefined();
12327 24 : }
12328 :
12329 :
12330 26645 : THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12331 6 : LocalContext context;
12332 12 : HandleScope scope(context->GetIsolate());
12333 :
12334 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12335 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12336 12 : instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12337 :
12338 6 : Local<Object> instance = templ->GetFunction(context.local())
12339 : .ToLocalChecked()
12340 : ->NewInstance(context.local())
12341 : .ToLocalChecked();
12342 :
12343 6 : Local<Object> another = Object::New(context->GetIsolate());
12344 12 : CHECK(another->SetPrototype(context.local(), instance).FromJust());
12345 :
12346 : Local<Object> with_js_getter = CompileRun(
12347 : "o = {};\n"
12348 : "o.__defineGetter__('f', function() { throw undefined; });\n"
12349 : "o\n").As<Object>();
12350 6 : CHECK(!with_js_getter.IsEmpty());
12351 :
12352 12 : TryCatch try_catch(context->GetIsolate());
12353 :
12354 : v8::MaybeLocal<Value> result =
12355 12 : instance->GetRealNamedProperty(context.local(), v8_str("f"));
12356 6 : CHECK(try_catch.HasCaught());
12357 6 : try_catch.Reset();
12358 6 : CHECK(result.IsEmpty());
12359 :
12360 : Maybe<PropertyAttribute> attr =
12361 12 : instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12362 6 : CHECK(!try_catch.HasCaught());
12363 6 : CHECK(Just(None) == attr);
12364 :
12365 12 : result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12366 6 : CHECK(try_catch.HasCaught());
12367 6 : try_catch.Reset();
12368 6 : CHECK(result.IsEmpty());
12369 :
12370 12 : attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12371 6 : CHECK(!try_catch.HasCaught());
12372 6 : CHECK(Just(None) == attr);
12373 :
12374 : result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12375 12 : v8_str("f"));
12376 6 : CHECK(try_catch.HasCaught());
12377 6 : try_catch.Reset();
12378 6 : CHECK(result.IsEmpty());
12379 :
12380 : attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12381 12 : context.local(), v8_str("f"));
12382 6 : CHECK(!try_catch.HasCaught());
12383 6 : CHECK(Just(None) == attr);
12384 :
12385 12 : result = another->Get(context.local(), v8_str("f"));
12386 6 : CHECK(try_catch.HasCaught());
12387 6 : try_catch.Reset();
12388 6 : CHECK(result.IsEmpty());
12389 :
12390 12 : result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12391 6 : CHECK(try_catch.HasCaught());
12392 6 : try_catch.Reset();
12393 6 : CHECK(result.IsEmpty());
12394 :
12395 : attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12396 12 : v8_str("f"));
12397 6 : CHECK(!try_catch.HasCaught());
12398 6 : CHECK(Just(None) == attr);
12399 :
12400 12 : result = with_js_getter->Get(context.local(), v8_str("f"));
12401 6 : CHECK(try_catch.HasCaught());
12402 6 : try_catch.Reset();
12403 6 : CHECK(result.IsEmpty());
12404 :
12405 : Local<Object> target = CompileRun("({})").As<Object>();
12406 6 : Local<Object> handler = CompileRun("({})").As<Object>();
12407 : Local<v8::Proxy> proxy =
12408 6 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12409 :
12410 12 : result = target->GetRealNamedProperty(context.local(), v8_str("f"));
12411 6 : CHECK(!try_catch.HasCaught());
12412 6 : CHECK(result.IsEmpty());
12413 :
12414 12 : result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
12415 6 : CHECK(!try_catch.HasCaught());
12416 6 : CHECK(result.IsEmpty());
12417 6 : }
12418 :
12419 :
12420 30 : static void ThrowingCallbackWithTryCatch(
12421 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12422 60 : TryCatch try_catch(args.GetIsolate());
12423 : // Verboseness is important: it triggers message delivery which can call into
12424 : // external code.
12425 30 : try_catch.SetVerbose(true);
12426 : CompileRun("throw 'from JS';");
12427 30 : CHECK(try_catch.HasCaught());
12428 30 : CHECK(!CcTest::i_isolate()->has_pending_exception());
12429 30 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12430 30 : }
12431 :
12432 :
12433 : static int call_depth;
12434 :
12435 :
12436 6 : static void WithTryCatch(Local<Message> message, Local<Value> data) {
12437 6 : TryCatch try_catch(CcTest::isolate());
12438 6 : }
12439 :
12440 :
12441 6 : static void ThrowFromJS(Local<Message> message, Local<Value> data) {
12442 6 : if (--call_depth) CompileRun("throw 'ThrowInJS';");
12443 6 : }
12444 :
12445 :
12446 6 : static void ThrowViaApi(Local<Message> message, Local<Value> data) {
12447 12 : if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12448 6 : }
12449 :
12450 :
12451 6 : static void WebKitLike(Local<Message> message, Local<Value> data) {
12452 6 : Local<String> errorMessageString = message->Get();
12453 6 : CHECK(!errorMessageString.IsEmpty());
12454 6 : message->GetStackTrace();
12455 6 : message->GetScriptOrigin().ResourceName();
12456 6 : }
12457 :
12458 :
12459 26645 : THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12460 6 : LocalContext context;
12461 6 : v8::Isolate* isolate = context->GetIsolate();
12462 12 : HandleScope scope(isolate);
12463 :
12464 : Local<Function> func =
12465 12 : FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
12466 6 : ->GetFunction(context.local())
12467 : .ToLocalChecked();
12468 24 : CHECK(
12469 : context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
12470 :
12471 : MessageCallback callbacks[] = {nullptr, WebKitLike, ThrowViaApi, ThrowFromJS,
12472 6 : WithTryCatch};
12473 66 : for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12474 30 : MessageCallback callback = callbacks[i];
12475 30 : if (callback != nullptr) {
12476 24 : isolate->AddMessageListener(callback);
12477 : }
12478 : // Some small number to control number of times message handler should
12479 : // throw an exception.
12480 30 : call_depth = 5;
12481 : ExpectFalse(
12482 : "var thrown = false;\n"
12483 : "try { func(); } catch(e) { thrown = true; }\n"
12484 : "thrown\n");
12485 30 : if (callback != nullptr) {
12486 24 : isolate->RemoveMessageListeners(callback);
12487 : }
12488 : }
12489 6 : }
12490 :
12491 :
12492 6 : static void ParentGetter(Local<String> name,
12493 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12494 6 : ApiTestFuzzer::Fuzz();
12495 6 : info.GetReturnValue().Set(v8_num(1));
12496 6 : }
12497 :
12498 :
12499 18 : static void ChildGetter(Local<String> name,
12500 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12501 18 : ApiTestFuzzer::Fuzz();
12502 18 : info.GetReturnValue().Set(v8_num(42));
12503 18 : }
12504 :
12505 :
12506 26645 : THREADED_TEST(Overriding) {
12507 6 : LocalContext context;
12508 6 : v8::Isolate* isolate = context->GetIsolate();
12509 12 : v8::HandleScope scope(isolate);
12510 :
12511 : // Parent template.
12512 6 : Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12513 : Local<ObjectTemplate> parent_instance_templ =
12514 6 : parent_templ->InstanceTemplate();
12515 12 : parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12516 :
12517 : // Template that inherits from the parent template.
12518 6 : Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12519 : Local<ObjectTemplate> child_instance_templ =
12520 6 : child_templ->InstanceTemplate();
12521 6 : child_templ->Inherit(parent_templ);
12522 : // Override 'f'. The child version of 'f' should get called for child
12523 : // instances.
12524 6 : child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12525 : // Add 'g' twice. The 'g' added last should get called for instances.
12526 6 : child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12527 6 : child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12528 :
12529 : // Add 'h' as an accessor to the proto template with ReadOnly attributes
12530 : // so 'h' can be shadowed on the instance object.
12531 6 : Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12532 12 : child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, nullptr,
12533 6 : v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
12534 :
12535 : // Add 'i' as an accessor to the instance template with ReadOnly attributes
12536 : // but the attribute does not have effect because it is duplicated with
12537 : // nullptr setter.
12538 12 : child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, nullptr,
12539 : v8::Local<Value>(), v8::DEFAULT,
12540 6 : v8::ReadOnly);
12541 :
12542 : // Instantiate the child template.
12543 6 : Local<v8::Object> instance = child_templ->GetFunction(context.local())
12544 : .ToLocalChecked()
12545 : ->NewInstance(context.local())
12546 : .ToLocalChecked();
12547 :
12548 : // Check that the child function overrides the parent one.
12549 24 : CHECK(context->Global()
12550 : ->Set(context.local(), v8_str("o"), instance)
12551 : .FromJust());
12552 6 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12553 : // Check that the 'g' that was added last is hit.
12554 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12555 6 : value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
12556 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12557 :
12558 : // Check that 'h' cannot be shadowed.
12559 6 : value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
12560 12 : CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
12561 :
12562 : // Check that 'i' cannot be shadowed or changed.
12563 6 : value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
12564 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12565 6 : }
12566 :
12567 :
12568 24 : static void ShouldThrowOnErrorGetter(
12569 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12570 24 : ApiTestFuzzer::Fuzz();
12571 : v8::Isolate* isolate = info.GetIsolate();
12572 : Local<Boolean> should_throw_on_error =
12573 : Boolean::New(isolate, info.ShouldThrowOnError());
12574 : info.GetReturnValue().Set(should_throw_on_error);
12575 24 : }
12576 :
12577 :
12578 : template <typename T>
12579 24 : static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
12580 : const v8::PropertyCallbackInfo<T>& info) {
12581 24 : ApiTestFuzzer::Fuzz();
12582 : v8::Isolate* isolate = info.GetIsolate();
12583 24 : auto context = isolate->GetCurrentContext();
12584 : Local<Boolean> should_throw_on_error_value =
12585 : Boolean::New(isolate, info.ShouldThrowOnError());
12586 120 : CHECK(context->Global()
12587 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
12588 : should_throw_on_error_value)
12589 : .FromJust());
12590 24 : }
12591 :
12592 :
12593 26645 : THREADED_TEST(AccessorShouldThrowOnError) {
12594 6 : LocalContext context;
12595 6 : v8::Isolate* isolate = context->GetIsolate();
12596 12 : v8::HandleScope scope(isolate);
12597 6 : Local<Object> global = context->Global();
12598 :
12599 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12600 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12601 12 : instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
12602 6 : ShouldThrowOnErrorSetter<void>);
12603 :
12604 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
12605 : .ToLocalChecked()
12606 : ->NewInstance(context.local())
12607 : .ToLocalChecked();
12608 :
12609 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12610 :
12611 : // SLOPPY mode
12612 6 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12613 6 : CHECK(value->IsFalse());
12614 6 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12615 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12616 : .ToLocalChecked();
12617 6 : CHECK(value->IsFalse());
12618 :
12619 : // STRICT mode
12620 6 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12621 6 : CHECK(value->IsFalse());
12622 6 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12623 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12624 : .ToLocalChecked();
12625 6 : CHECK(value->IsTrue());
12626 6 : }
12627 :
12628 :
12629 0 : static void ShouldThrowOnErrorQuery(
12630 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
12631 0 : ApiTestFuzzer::Fuzz();
12632 : v8::Isolate* isolate = info.GetIsolate();
12633 : info.GetReturnValue().Set(v8::None);
12634 :
12635 0 : auto context = isolate->GetCurrentContext();
12636 : Local<Boolean> should_throw_on_error_value =
12637 : Boolean::New(isolate, info.ShouldThrowOnError());
12638 0 : CHECK(context->Global()
12639 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
12640 : should_throw_on_error_value)
12641 : .FromJust());
12642 0 : }
12643 :
12644 :
12645 12 : static void ShouldThrowOnErrorDeleter(
12646 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
12647 12 : ApiTestFuzzer::Fuzz();
12648 : v8::Isolate* isolate = info.GetIsolate();
12649 : info.GetReturnValue().Set(v8::True(isolate));
12650 :
12651 12 : auto context = isolate->GetCurrentContext();
12652 : Local<Boolean> should_throw_on_error_value =
12653 : Boolean::New(isolate, info.ShouldThrowOnError());
12654 60 : CHECK(context->Global()
12655 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
12656 : should_throw_on_error_value)
12657 : .FromJust());
12658 12 : }
12659 :
12660 :
12661 12 : static void ShouldThrowOnErrorPropertyEnumerator(
12662 : const v8::PropertyCallbackInfo<v8::Array>& info) {
12663 12 : ApiTestFuzzer::Fuzz();
12664 : v8::Isolate* isolate = info.GetIsolate();
12665 12 : Local<v8::Array> names = v8::Array::New(isolate, 1);
12666 36 : CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
12667 : info.GetReturnValue().Set(names);
12668 :
12669 12 : auto context = isolate->GetCurrentContext();
12670 : Local<Boolean> should_throw_on_error_value =
12671 : Boolean::New(isolate, info.ShouldThrowOnError());
12672 60 : CHECK(context->Global()
12673 : ->Set(isolate->GetCurrentContext(),
12674 : v8_str("should_throw_enumerator"),
12675 : should_throw_on_error_value)
12676 : .FromJust());
12677 12 : }
12678 :
12679 :
12680 26645 : THREADED_TEST(InterceptorShouldThrowOnError) {
12681 6 : LocalContext context;
12682 6 : v8::Isolate* isolate = context->GetIsolate();
12683 12 : v8::HandleScope scope(isolate);
12684 6 : Local<Object> global = context->Global();
12685 :
12686 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
12687 : v8::NamedPropertyHandlerConfiguration handler(
12688 : ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
12689 : ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
12690 : ShouldThrowOnErrorPropertyEnumerator);
12691 6 : interceptor_templ->SetHandler(handler);
12692 :
12693 : Local<v8::Object> instance =
12694 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
12695 :
12696 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12697 :
12698 : // SLOPPY mode
12699 6 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12700 6 : CHECK(value->IsFalse());
12701 6 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12702 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12703 : .ToLocalChecked();
12704 6 : CHECK(value->IsFalse());
12705 :
12706 6 : v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
12707 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
12708 : .ToLocalChecked();
12709 6 : CHECK(value->IsFalse());
12710 :
12711 : v8_compile("Object.getOwnPropertyNames(o)")
12712 6 : ->Run(context.local())
12713 : .ToLocalChecked();
12714 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12715 : .ToLocalChecked();
12716 6 : CHECK(value->IsFalse());
12717 :
12718 : // STRICT mode
12719 6 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12720 6 : CHECK(value->IsFalse());
12721 6 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12722 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
12723 : .ToLocalChecked();
12724 6 : CHECK(value->IsTrue());
12725 :
12726 6 : v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
12727 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
12728 : .ToLocalChecked();
12729 6 : CHECK(value->IsTrue());
12730 :
12731 : v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
12732 6 : ->Run(context.local())
12733 : .ToLocalChecked();
12734 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12735 : .ToLocalChecked();
12736 6 : CHECK(value->IsFalse());
12737 6 : }
12738 :
12739 55 : static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
12740 :
12741 26644 : TEST(CallHandlerHasNoSideEffect) {
12742 5 : v8::Isolate* isolate = CcTest::isolate();
12743 10 : v8::HandleScope scope(isolate);
12744 5 : LocalContext context;
12745 :
12746 : // Function template with call handler.
12747 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12748 5 : templ->SetCallHandler(EmptyHandler);
12749 25 : CHECK(context->Global()
12750 : ->Set(context.local(), v8_str("f"),
12751 : templ->GetFunction(context.local()).ToLocalChecked())
12752 : .FromJust());
12753 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12754 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12755 :
12756 : // Side-effect-free version.
12757 5 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
12758 5 : templ2->SetCallHandler(EmptyHandler, v8::Local<Value>(),
12759 5 : v8::SideEffectType::kHasNoSideEffect);
12760 25 : CHECK(context->Global()
12761 : ->Set(context.local(), v8_str("f2"),
12762 : templ2->GetFunction(context.local()).ToLocalChecked())
12763 : .FromJust());
12764 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12765 5 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12766 5 : }
12767 :
12768 26644 : TEST(FunctionTemplateNewHasNoSideEffect) {
12769 5 : v8::Isolate* isolate = CcTest::isolate();
12770 10 : v8::HandleScope scope(isolate);
12771 5 : LocalContext context;
12772 :
12773 : // Function template with call handler.
12774 : Local<v8::FunctionTemplate> templ =
12775 5 : v8::FunctionTemplate::New(isolate, EmptyHandler);
12776 25 : CHECK(context->Global()
12777 : ->Set(context.local(), v8_str("f"),
12778 : templ->GetFunction(context.local()).ToLocalChecked())
12779 : .FromJust());
12780 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12781 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12782 :
12783 : // Side-effect-free version.
12784 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(
12785 : isolate, EmptyHandler, v8::Local<Value>(), v8::Local<v8::Signature>(), 0,
12786 5 : v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasNoSideEffect);
12787 25 : CHECK(context->Global()
12788 : ->Set(context.local(), v8_str("f2"),
12789 : templ2->GetFunction(context.local()).ToLocalChecked())
12790 : .FromJust());
12791 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12792 5 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12793 5 : }
12794 :
12795 26644 : TEST(FunctionTemplateNewWithCacheHasNoSideEffect) {
12796 5 : v8::Isolate* isolate = CcTest::isolate();
12797 10 : v8::HandleScope scope(isolate);
12798 5 : LocalContext context;
12799 : v8::Local<v8::Private> priv =
12800 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
12801 :
12802 : // Function template with call handler.
12803 : Local<v8::FunctionTemplate> templ =
12804 5 : v8::FunctionTemplate::NewWithCache(isolate, EmptyHandler, priv);
12805 25 : CHECK(context->Global()
12806 : ->Set(context.local(), v8_str("f"),
12807 : templ->GetFunction(context.local()).ToLocalChecked())
12808 : .FromJust());
12809 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12810 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12811 :
12812 : // Side-effect-free version.
12813 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::NewWithCache(
12814 : isolate, EmptyHandler, priv, v8::Local<Value>(),
12815 5 : v8::Local<v8::Signature>(), 0, v8::SideEffectType::kHasNoSideEffect);
12816 25 : CHECK(context->Global()
12817 : ->Set(context.local(), v8_str("f2"),
12818 : templ2->GetFunction(context.local()).ToLocalChecked())
12819 : .FromJust());
12820 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12821 5 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12822 5 : }
12823 :
12824 26644 : TEST(FunctionNewHasNoSideEffect) {
12825 5 : v8::Isolate* isolate = CcTest::isolate();
12826 10 : v8::HandleScope scope(isolate);
12827 5 : LocalContext context;
12828 :
12829 : // Function with side-effect.
12830 : Local<Function> func =
12831 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
12832 20 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12833 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12834 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12835 :
12836 : // Side-effect-free version.
12837 : Local<Function> func2 =
12838 5 : Function::New(context.local(), EmptyHandler, Local<Value>(), 0,
12839 : v8::ConstructorBehavior::kAllow,
12840 5 : v8::SideEffectType::kHasNoSideEffect)
12841 : .ToLocalChecked();
12842 20 : CHECK(
12843 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12844 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12845 5 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12846 5 : }
12847 :
12848 : // These handlers instantiate a function the embedder considers safe in some
12849 : // cases (e.g. "building object wrappers"), but those functions themselves were
12850 : // not explicitly marked as side-effect-free.
12851 5 : static void DefaultConstructHandler(
12852 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12853 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12854 : v8::Context::Scope context_scope(context);
12855 10 : v8::MaybeLocal<v8::Object> instance = Function::New(context, EmptyHandler)
12856 : .ToLocalChecked()
12857 5 : ->NewInstance(context, 0, nullptr);
12858 : USE(instance);
12859 5 : }
12860 :
12861 10 : static void NoSideEffectConstructHandler(
12862 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12863 10 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12864 : v8::Context::Scope context_scope(context);
12865 : v8::MaybeLocal<v8::Object> instance =
12866 20 : Function::New(context, EmptyHandler)
12867 : .ToLocalChecked()
12868 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
12869 10 : v8::SideEffectType::kHasNoSideEffect);
12870 : USE(instance);
12871 10 : }
12872 :
12873 5 : static void NoSideEffectAndSideEffectConstructHandler(
12874 : const v8::FunctionCallbackInfo<v8::Value>& info) {
12875 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12876 : v8::Context::Scope context_scope(context);
12877 : // Constructs an instance in a side-effect-free way, followed by another with
12878 : // side effects.
12879 : v8::MaybeLocal<v8::Object> instance =
12880 10 : Function::New(context, EmptyHandler)
12881 : .ToLocalChecked()
12882 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
12883 5 : v8::SideEffectType::kHasNoSideEffect);
12884 10 : v8::MaybeLocal<v8::Object> instance2 = Function::New(context, EmptyHandler)
12885 : .ToLocalChecked()
12886 5 : ->NewInstance(context, 0, nullptr);
12887 : USE(instance);
12888 : USE(instance2);
12889 5 : }
12890 :
12891 26644 : TEST(FunctionNewInstanceHasNoSideEffect) {
12892 5 : v8::Isolate* isolate = CcTest::isolate();
12893 10 : v8::HandleScope scope(isolate);
12894 5 : LocalContext context;
12895 :
12896 : // A whitelisted function that creates a new object with both side-effect
12897 : // free/full instantiations. Should throw.
12898 : Local<Function> func0 =
12899 5 : Function::New(context.local(), NoSideEffectAndSideEffectConstructHandler,
12900 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12901 5 : v8::SideEffectType::kHasNoSideEffect)
12902 : .ToLocalChecked();
12903 20 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func0).FromJust());
12904 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12905 :
12906 : // A whitelisted function that creates a new object. Should throw.
12907 : Local<Function> func =
12908 5 : Function::New(context.local(), DefaultConstructHandler, Local<Value>(), 0,
12909 : v8::ConstructorBehavior::kAllow,
12910 5 : v8::SideEffectType::kHasNoSideEffect)
12911 : .ToLocalChecked();
12912 20 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12913 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12914 :
12915 : // A whitelisted function that creates a new object with explicit intent to
12916 : // have no side-effects (e.g. building an "object wrapper"). Should not throw.
12917 : Local<Function> func2 =
12918 5 : Function::New(context.local(), NoSideEffectConstructHandler,
12919 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12920 5 : v8::SideEffectType::kHasNoSideEffect)
12921 : .ToLocalChecked();
12922 20 : CHECK(
12923 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12924 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12925 :
12926 : // Check that side effect skipping did not leak outside to future evaluations.
12927 : Local<Function> func3 =
12928 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
12929 20 : CHECK(
12930 : context->Global()->Set(context.local(), v8_str("f3"), func3).FromJust());
12931 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f3()"), true).IsEmpty());
12932 :
12933 : // Check that using side effect free NewInstance works in normal evaluation
12934 : // (without throwOnSideEffect).
12935 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), false).ToLocalChecked();
12936 5 : }
12937 :
12938 26644 : TEST(CallHandlerAsFunctionHasNoSideEffectNotSupported) {
12939 5 : v8::Isolate* isolate = CcTest::isolate();
12940 10 : v8::HandleScope scope(isolate);
12941 5 : LocalContext context;
12942 :
12943 : // Object template with call as function handler.
12944 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12945 5 : templ->SetCallAsFunctionHandler(EmptyHandler);
12946 5 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
12947 20 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
12948 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12949 :
12950 : // Side-effect-free version is not supported.
12951 : i::FunctionTemplateInfo cons = i::FunctionTemplateInfo::cast(
12952 : v8::Utils::OpenHandle(*templ)->constructor());
12953 : i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
12954 : i::CallHandlerInfo handler_info =
12955 5 : i::CallHandlerInfo::cast(cons->GetInstanceCallHandler());
12956 5 : CHECK(!handler_info->IsSideEffectFreeCallHandlerInfo());
12957 : handler_info->set_map(
12958 5 : i::ReadOnlyRoots(heap).side_effect_free_call_handler_info_map());
12959 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12960 5 : }
12961 :
12962 12 : static void IsConstructHandler(
12963 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12964 12 : ApiTestFuzzer::Fuzz();
12965 : args.GetReturnValue().Set(args.IsConstructCall());
12966 12 : }
12967 :
12968 :
12969 26645 : THREADED_TEST(IsConstructCall) {
12970 6 : v8::Isolate* isolate = CcTest::isolate();
12971 12 : v8::HandleScope scope(isolate);
12972 :
12973 : // Function template with call handler.
12974 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12975 6 : templ->SetCallHandler(IsConstructHandler);
12976 :
12977 6 : LocalContext context;
12978 :
12979 30 : CHECK(context->Global()
12980 : ->Set(context.local(), v8_str("f"),
12981 : templ->GetFunction(context.local()).ToLocalChecked())
12982 : .FromJust());
12983 6 : Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
12984 6 : CHECK(!value->BooleanValue(isolate));
12985 6 : value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
12986 6 : CHECK(value->BooleanValue(isolate));
12987 6 : }
12988 :
12989 24 : static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
12990 24 : ApiTestFuzzer::Fuzz();
12991 : args.GetReturnValue().Set(args.NewTarget());
12992 24 : }
12993 :
12994 26645 : THREADED_TEST(NewTargetHandler) {
12995 6 : v8::Isolate* isolate = CcTest::isolate();
12996 12 : v8::HandleScope scope(isolate);
12997 :
12998 : // Function template with call handler.
12999 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13000 6 : templ->SetCallHandler(NewTargetHandler);
13001 :
13002 6 : LocalContext context;
13003 :
13004 : Local<Function> function =
13005 6 : templ->GetFunction(context.local()).ToLocalChecked();
13006 24 : CHECK(context->Global()
13007 : ->Set(context.local(), v8_str("f"), function)
13008 : .FromJust());
13009 : Local<Value> value = CompileRun("f()");
13010 6 : CHECK(value->IsUndefined());
13011 : value = CompileRun("new f()");
13012 6 : CHECK(value->IsFunction());
13013 6 : CHECK(value == function);
13014 : Local<Value> subclass = CompileRun("var g = class extends f { }; g");
13015 6 : CHECK(subclass->IsFunction());
13016 : value = CompileRun("new g()");
13017 6 : CHECK(value->IsFunction());
13018 6 : CHECK(value == subclass);
13019 : value = CompileRun("Reflect.construct(f, [], Array)");
13020 6 : CHECK(value->IsFunction());
13021 24 : CHECK(value ==
13022 : context->Global()
13023 : ->Get(context.local(), v8_str("Array"))
13024 : .ToLocalChecked());
13025 6 : }
13026 :
13027 26645 : THREADED_TEST(ObjectProtoToString) {
13028 6 : v8::Isolate* isolate = CcTest::isolate();
13029 12 : v8::HandleScope scope(isolate);
13030 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13031 6 : templ->SetClassName(v8_str("MyClass"));
13032 :
13033 6 : LocalContext context;
13034 :
13035 6 : Local<String> customized_tostring = v8_str("customized toString");
13036 :
13037 : // Replace Object.prototype.toString
13038 : v8_compile(
13039 : "Object.prototype.toString = function() {"
13040 : " return 'customized toString';"
13041 : "}")
13042 6 : ->Run(context.local())
13043 : .ToLocalChecked();
13044 :
13045 : // Normal ToString call should call replaced Object.prototype.toString
13046 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13047 : .ToLocalChecked()
13048 : ->NewInstance(context.local())
13049 : .ToLocalChecked();
13050 6 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13051 18 : CHECK(value->IsString() &&
13052 : value->Equals(context.local(), customized_tostring).FromJust());
13053 :
13054 : // ObjectProtoToString should not call replace toString function.
13055 6 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13056 18 : CHECK(value->IsString() &&
13057 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13058 :
13059 : // Check global
13060 : value =
13061 18 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13062 18 : CHECK(value->IsString() &&
13063 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13064 :
13065 : // Check ordinary object
13066 : Local<Value> object =
13067 6 : v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13068 : value = object.As<v8::Object>()
13069 6 : ->ObjectProtoToString(context.local())
13070 : .ToLocalChecked();
13071 18 : CHECK(value->IsString() &&
13072 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13073 6 : }
13074 :
13075 :
13076 26644 : TEST(ObjectProtoToStringES6) {
13077 5 : LocalContext context;
13078 5 : v8::Isolate* isolate = CcTest::isolate();
13079 10 : v8::HandleScope scope(isolate);
13080 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13081 5 : templ->SetClassName(v8_str("MyClass"));
13082 :
13083 5 : Local<String> customized_tostring = v8_str("customized toString");
13084 :
13085 : // Replace Object.prototype.toString
13086 : CompileRun(
13087 : "Object.prototype.toString = function() {"
13088 : " return 'customized toString';"
13089 : "}");
13090 :
13091 : // Normal ToString call should call replaced Object.prototype.toString
13092 5 : Local<v8::Object> instance = templ->GetFunction(context.local())
13093 : .ToLocalChecked()
13094 : ->NewInstance(context.local())
13095 : .ToLocalChecked();
13096 5 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13097 15 : CHECK(value->IsString() &&
13098 : value->Equals(context.local(), customized_tostring).FromJust());
13099 :
13100 : // ObjectProtoToString should not call replace toString function.
13101 5 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13102 15 : CHECK(value->IsString() &&
13103 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13104 :
13105 : // Check global
13106 : value =
13107 15 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13108 15 : CHECK(value->IsString() &&
13109 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13110 :
13111 : // Check ordinary object
13112 : Local<Value> object = CompileRun("new Object()");
13113 : value = object.As<v8::Object>()
13114 5 : ->ObjectProtoToString(context.local())
13115 : .ToLocalChecked();
13116 15 : CHECK(value->IsString() &&
13117 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13118 :
13119 : // Check that ES6 semantics using @@toStringTag work
13120 5 : Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13121 :
13122 : #define TEST_TOSTRINGTAG(type, tag, expected) \
13123 : do { \
13124 : object = CompileRun("new " #type "()"); \
13125 : CHECK(object.As<v8::Object>() \
13126 : ->Set(context.local(), toStringTag, v8_str(#tag)) \
13127 : .FromJust()); \
13128 : value = object.As<v8::Object>() \
13129 : ->ObjectProtoToString(context.local()) \
13130 : .ToLocalChecked(); \
13131 : CHECK(value->IsString() && \
13132 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13133 : .FromJust()); \
13134 : } while (false)
13135 :
13136 35 : TEST_TOSTRINGTAG(Array, Object, Object);
13137 35 : TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13138 35 : TEST_TOSTRINGTAG(Object, Array, Array);
13139 35 : TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13140 35 : TEST_TOSTRINGTAG(Object, Date, Date);
13141 35 : TEST_TOSTRINGTAG(Object, Error, Error);
13142 35 : TEST_TOSTRINGTAG(Object, Function, Function);
13143 35 : TEST_TOSTRINGTAG(Object, Number, Number);
13144 35 : TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13145 35 : TEST_TOSTRINGTAG(Object, String, String);
13146 35 : TEST_TOSTRINGTAG(Object, Foo, Foo);
13147 :
13148 : #undef TEST_TOSTRINGTAG
13149 :
13150 : Local<v8::RegExp> valueRegExp =
13151 10 : v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13152 : .ToLocalChecked();
13153 5 : Local<Value> valueNumber = v8_num(123);
13154 5 : Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13155 : Local<v8::Function> valueFunction =
13156 : CompileRun("(function fn() {})").As<v8::Function>();
13157 5 : Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13158 5 : Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13159 5 : Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13160 :
13161 : #define TEST_TOSTRINGTAG(type, tagValue, expected) \
13162 : do { \
13163 : object = CompileRun("new " #type "()"); \
13164 : CHECK(object.As<v8::Object>() \
13165 : ->Set(context.local(), toStringTag, tagValue) \
13166 : .FromJust()); \
13167 : value = object.As<v8::Object>() \
13168 : ->ObjectProtoToString(context.local()) \
13169 : .ToLocalChecked(); \
13170 : CHECK(value->IsString() && \
13171 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13172 : .FromJust()); \
13173 : } while (false)
13174 :
13175 : #define TEST_TOSTRINGTAG_TYPES(tagValue) \
13176 : TEST_TOSTRINGTAG(Array, tagValue, Array); \
13177 : TEST_TOSTRINGTAG(Object, tagValue, Object); \
13178 : TEST_TOSTRINGTAG(Function, tagValue, Function); \
13179 : TEST_TOSTRINGTAG(Date, tagValue, Date); \
13180 : TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13181 : TEST_TOSTRINGTAG(Error, tagValue, Error); \
13182 :
13183 : // Test non-String-valued @@toStringTag
13184 180 : TEST_TOSTRINGTAG_TYPES(valueRegExp);
13185 180 : TEST_TOSTRINGTAG_TYPES(valueNumber);
13186 180 : TEST_TOSTRINGTAG_TYPES(valueSymbol);
13187 180 : TEST_TOSTRINGTAG_TYPES(valueFunction);
13188 180 : TEST_TOSTRINGTAG_TYPES(valueObject);
13189 180 : TEST_TOSTRINGTAG_TYPES(valueNull);
13190 180 : TEST_TOSTRINGTAG_TYPES(valueUndef);
13191 :
13192 : #undef TEST_TOSTRINGTAG
13193 : #undef TEST_TOSTRINGTAG_TYPES
13194 :
13195 : // @@toStringTag getter throws
13196 5 : Local<Value> obj = v8::Object::New(isolate);
13197 : obj.As<v8::Object>()
13198 10 : ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13199 : .FromJust();
13200 : {
13201 10 : TryCatch try_catch(isolate);
13202 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13203 5 : CHECK(try_catch.HasCaught());
13204 : }
13205 :
13206 : // @@toStringTag getter does not throw
13207 5 : obj = v8::Object::New(isolate);
13208 : obj.As<v8::Object>()
13209 10 : ->SetAccessor(context.local(), toStringTag,
13210 10 : SymbolAccessorGetterReturnsDefault, nullptr, v8_str("Test"))
13211 : .FromJust();
13212 : {
13213 10 : TryCatch try_catch(isolate);
13214 : value = obj.As<v8::Object>()
13215 5 : ->ObjectProtoToString(context.local())
13216 : .ToLocalChecked();
13217 15 : CHECK(value->IsString() &&
13218 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13219 5 : CHECK(!try_catch.HasCaught());
13220 : }
13221 :
13222 : // JS @@toStringTag value
13223 : obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13224 : {
13225 10 : TryCatch try_catch(isolate);
13226 : value = obj.As<v8::Object>()
13227 5 : ->ObjectProtoToString(context.local())
13228 : .ToLocalChecked();
13229 15 : CHECK(value->IsString() &&
13230 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13231 5 : CHECK(!try_catch.HasCaught());
13232 : }
13233 :
13234 : // JS @@toStringTag getter throws
13235 : obj = CompileRun(
13236 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13237 : " get: function() { throw 'Test'; }"
13238 : "}); obj");
13239 : {
13240 10 : TryCatch try_catch(isolate);
13241 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13242 5 : CHECK(try_catch.HasCaught());
13243 : }
13244 :
13245 : // JS @@toStringTag getter does not throw
13246 : obj = CompileRun(
13247 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13248 : " get: function() { return 'Test'; }"
13249 : "}); obj");
13250 : {
13251 10 : TryCatch try_catch(isolate);
13252 : value = obj.As<v8::Object>()
13253 5 : ->ObjectProtoToString(context.local())
13254 : .ToLocalChecked();
13255 15 : CHECK(value->IsString() &&
13256 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13257 5 : CHECK(!try_catch.HasCaught());
13258 : }
13259 5 : }
13260 :
13261 :
13262 26645 : THREADED_TEST(ObjectGetConstructorName) {
13263 6 : v8::Isolate* isolate = CcTest::isolate();
13264 6 : LocalContext context;
13265 12 : v8::HandleScope scope(isolate);
13266 : v8_compile(
13267 : "function Parent() {};"
13268 : "function Child() {};"
13269 : "Child.prototype = new Parent();"
13270 : "Child.prototype.constructor = Child;"
13271 : "var outer = { inner: (0, function() { }) };"
13272 : "var p = new Parent();"
13273 : "var c = new Child();"
13274 : "var x = new outer.inner();"
13275 : "var proto = Child.prototype;")
13276 6 : ->Run(context.local())
13277 : .ToLocalChecked();
13278 :
13279 : Local<v8::Value> p =
13280 24 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13281 30 : CHECK(p->IsObject() &&
13282 : p->ToObject(context.local())
13283 : .ToLocalChecked()
13284 : ->GetConstructorName()
13285 : ->Equals(context.local(), v8_str("Parent"))
13286 : .FromJust());
13287 :
13288 : Local<v8::Value> c =
13289 24 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13290 30 : CHECK(c->IsObject() &&
13291 : c->ToObject(context.local())
13292 : .ToLocalChecked()
13293 : ->GetConstructorName()
13294 : ->Equals(context.local(), v8_str("Child"))
13295 : .FromJust());
13296 :
13297 : Local<v8::Value> x =
13298 24 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13299 30 : CHECK(x->IsObject() &&
13300 : x->ToObject(context.local())
13301 : .ToLocalChecked()
13302 : ->GetConstructorName()
13303 : ->Equals(context.local(), v8_str("outer.inner"))
13304 : .FromJust());
13305 :
13306 : Local<v8::Value> child_prototype =
13307 24 : context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13308 30 : CHECK(child_prototype->IsObject() &&
13309 : child_prototype->ToObject(context.local())
13310 : .ToLocalChecked()
13311 : ->GetConstructorName()
13312 : ->Equals(context.local(), v8_str("Parent"))
13313 : .FromJust());
13314 6 : }
13315 :
13316 :
13317 26645 : THREADED_TEST(SubclassGetConstructorName) {
13318 6 : v8::Isolate* isolate = CcTest::isolate();
13319 6 : LocalContext context;
13320 12 : v8::HandleScope scope(isolate);
13321 : v8_compile(
13322 : "\"use strict\";"
13323 : "class Parent {}"
13324 : "class Child extends Parent {}"
13325 : "var p = new Parent();"
13326 : "var c = new Child();")
13327 6 : ->Run(context.local())
13328 : .ToLocalChecked();
13329 :
13330 : Local<v8::Value> p =
13331 24 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13332 30 : CHECK(p->IsObject() &&
13333 : p->ToObject(context.local())
13334 : .ToLocalChecked()
13335 : ->GetConstructorName()
13336 : ->Equals(context.local(), v8_str("Parent"))
13337 : .FromJust());
13338 :
13339 : Local<v8::Value> c =
13340 24 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13341 30 : CHECK(c->IsObject() &&
13342 : c->ToObject(context.local())
13343 : .ToLocalChecked()
13344 : ->GetConstructorName()
13345 : ->Equals(context.local(), v8_str("Child"))
13346 : .FromJust());
13347 6 : }
13348 :
13349 :
13350 : bool ApiTestFuzzer::fuzzing_ = false;
13351 26639 : v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13352 : int ApiTestFuzzer::active_tests_;
13353 : int ApiTestFuzzer::tests_being_run_;
13354 : int ApiTestFuzzer::current_;
13355 :
13356 :
13357 : // We are in a callback and want to switch to another thread (if we
13358 : // are currently running the thread fuzzing test).
13359 514722 : void ApiTestFuzzer::Fuzz() {
13360 514722 : if (!fuzzing_) return;
13361 85307 : ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13362 85307 : test->ContextSwitch();
13363 : }
13364 :
13365 :
13366 : // Let the next thread go. Since it is also waiting on the V8 lock it may
13367 : // not start immediately.
13368 85787 : bool ApiTestFuzzer::NextThread() {
13369 85787 : int test_position = GetNextTestNumber();
13370 85787 : const char* test_name = RegisterThreadedTest::nth(current_)->name();
13371 85787 : if (test_position == current_) {
13372 : if (kLogThreading)
13373 : printf("Stay with %s\n", test_name);
13374 : return false;
13375 : }
13376 : if (kLogThreading) {
13377 : printf("Switch from %s to %s\n",
13378 : test_name,
13379 : RegisterThreadedTest::nth(test_position)->name());
13380 : }
13381 31793 : current_ = test_position;
13382 31793 : RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13383 31793 : return true;
13384 : }
13385 :
13386 :
13387 477 : void ApiTestFuzzer::Run() {
13388 : // When it is our turn...
13389 477 : gate_.Wait();
13390 : {
13391 : // ... get the V8 lock and start running the test.
13392 960 : v8::Locker locker(CcTest::isolate());
13393 480 : CallTest();
13394 : }
13395 : // This test finished.
13396 480 : active_ = false;
13397 480 : active_tests_--;
13398 : // If it was the last then signal that fact.
13399 480 : if (active_tests_ == 0) {
13400 8 : all_tests_done_.Signal();
13401 : } else {
13402 : // Otherwise select a new test and start that.
13403 472 : NextThread();
13404 : }
13405 480 : }
13406 :
13407 :
13408 : static unsigned linear_congruential_generator;
13409 :
13410 :
13411 8 : void ApiTestFuzzer::SetUp(PartOfTest part) {
13412 8 : linear_congruential_generator = i::FLAG_testing_prng_seed;
13413 8 : fuzzing_ = true;
13414 : int count = RegisterThreadedTest::count();
13415 8 : int start = count * part / (LAST_PART + 1);
13416 8 : int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13417 8 : active_tests_ = tests_being_run_ = end - start + 1;
13418 968 : for (int i = 0; i < tests_being_run_; i++) {
13419 480 : RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13420 : }
13421 968 : for (int i = 0; i < active_tests_; i++) {
13422 480 : RegisterThreadedTest::nth(i)->fuzzer_->Start();
13423 : }
13424 8 : }
13425 :
13426 :
13427 : static void CallTestNumber(int test_number) {
13428 480 : (RegisterThreadedTest::nth(test_number)->callback())();
13429 : }
13430 :
13431 :
13432 0 : void ApiTestFuzzer::RunAllTests() {
13433 : // Set off the first test.
13434 8 : current_ = -1;
13435 8 : NextThread();
13436 : // Wait till they are all done.
13437 8 : all_tests_done_.Wait();
13438 0 : }
13439 :
13440 :
13441 85787 : int ApiTestFuzzer::GetNextTestNumber() {
13442 : int next_test;
13443 3249266 : do {
13444 3249266 : next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13445 3249266 : linear_congruential_generator *= 1664525u;
13446 3249266 : linear_congruential_generator += 1013904223u;
13447 3249266 : } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13448 85787 : return next_test;
13449 : }
13450 :
13451 :
13452 85307 : void ApiTestFuzzer::ContextSwitch() {
13453 : // If the new thread is the same as the current thread there is nothing to do.
13454 85307 : if (NextThread()) {
13455 : // Now it can start.
13456 62626 : v8::Unlocker unlocker(CcTest::isolate());
13457 : // Wait till someone starts us again.
13458 31313 : gate_.Wait();
13459 : // And we're off.
13460 : }
13461 85307 : }
13462 :
13463 :
13464 8 : void ApiTestFuzzer::TearDown() {
13465 8 : fuzzing_ = false;
13466 7688 : for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13467 3840 : ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13468 3840 : if (fuzzer != nullptr) fuzzer->Join();
13469 : }
13470 8 : }
13471 :
13472 480 : void ApiTestFuzzer::CallTest() {
13473 480 : v8::Isolate::Scope scope(CcTest::isolate());
13474 : if (kLogThreading)
13475 : printf("Start test %s #%d\n",
13476 : RegisterThreadedTest::nth(test_number_)->name(), test_number_);
13477 480 : CallTestNumber(test_number_);
13478 : if (kLogThreading)
13479 : printf("End test %s #%d\n", RegisterThreadedTest::nth(test_number_)->name(),
13480 : test_number_);
13481 480 : }
13482 :
13483 : #define THREADING_TEST(INDEX, NAME) \
13484 : TEST(Threading##INDEX) { \
13485 : ApiTestFuzzer::SetUp(ApiTestFuzzer::NAME); \
13486 : ApiTestFuzzer::RunAllTests(); \
13487 : ApiTestFuzzer::TearDown(); \
13488 : }
13489 :
13490 26641 : THREADING_TEST(1, FIRST_PART)
13491 26641 : THREADING_TEST(2, SECOND_PART)
13492 26641 : THREADING_TEST(3, THIRD_PART)
13493 26641 : THREADING_TEST(4, FOURTH_PART)
13494 26641 : THREADING_TEST(5, FIFTH_PART)
13495 26641 : THREADING_TEST(6, SIXTH_PART)
13496 26641 : THREADING_TEST(7, SEVENTH_PART)
13497 26641 : THREADING_TEST(8, EIGHTH_PART)
13498 :
13499 : #undef THREADING_TEST
13500 :
13501 5 : static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13502 : v8::Isolate* isolate = args.GetIsolate();
13503 5 : CHECK(v8::Locker::IsLocked(isolate));
13504 5 : ApiTestFuzzer::Fuzz();
13505 5 : v8::Unlocker unlocker(isolate);
13506 : const char* code = "throw 7;";
13507 : {
13508 5 : v8::Locker nested_locker(isolate);
13509 10 : v8::HandleScope scope(isolate);
13510 : v8::Local<Value> exception;
13511 : {
13512 10 : v8::TryCatch try_catch(isolate);
13513 : v8::Local<Value> value = CompileRun(code);
13514 5 : CHECK(value.IsEmpty());
13515 5 : CHECK(try_catch.HasCaught());
13516 : // Make sure to wrap the exception in a new handle because
13517 : // the handle returned from the TryCatch is destroyed
13518 : // when the TryCatch is destroyed.
13519 10 : exception = Local<Value>::New(isolate, try_catch.Exception());
13520 : }
13521 5 : args.GetIsolate()->ThrowException(exception);
13522 : }
13523 5 : }
13524 :
13525 :
13526 5 : static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13527 5 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13528 5 : ApiTestFuzzer::Fuzz();
13529 10 : v8::Unlocker unlocker(CcTest::isolate());
13530 : const char* code = "throw 7;";
13531 : {
13532 10 : v8::Locker nested_locker(CcTest::isolate());
13533 10 : v8::HandleScope scope(args.GetIsolate());
13534 : v8::Local<Value> value = CompileRun(code);
13535 5 : CHECK(value.IsEmpty());
13536 5 : args.GetReturnValue().Set(v8_str("foo"));
13537 : }
13538 5 : }
13539 :
13540 :
13541 : // These are locking tests that don't need to be run again
13542 : // as part of the locking aggregation tests.
13543 26644 : TEST(NestedLockers) {
13544 5 : v8::Isolate* isolate = CcTest::isolate();
13545 5 : v8::Locker locker(isolate);
13546 5 : CHECK(v8::Locker::IsLocked(isolate));
13547 5 : LocalContext env;
13548 10 : v8::HandleScope scope(env->GetIsolate());
13549 : Local<v8::FunctionTemplate> fun_templ =
13550 5 : v8::FunctionTemplate::New(isolate, ThrowInJS);
13551 5 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13552 20 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13553 : Local<Script> script = v8_compile("(function () {"
13554 : " try {"
13555 : " throw_in_js();"
13556 : " return 42;"
13557 : " } catch (e) {"
13558 : " return e * 13;"
13559 : " }"
13560 : "})();");
13561 15 : CHECK_EQ(91, script->Run(env.local())
13562 : .ToLocalChecked()
13563 : ->Int32Value(env.local())
13564 : .FromJust());
13565 5 : }
13566 :
13567 :
13568 : // These are locking tests that don't need to be run again
13569 : // as part of the locking aggregation tests.
13570 26644 : TEST(NestedLockersNoTryCatch) {
13571 10 : v8::Locker locker(CcTest::isolate());
13572 5 : LocalContext env;
13573 10 : v8::HandleScope scope(env->GetIsolate());
13574 : Local<v8::FunctionTemplate> fun_templ =
13575 5 : v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13576 5 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13577 20 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13578 : Local<Script> script = v8_compile("(function () {"
13579 : " try {"
13580 : " throw_in_js();"
13581 : " return 42;"
13582 : " } catch (e) {"
13583 : " return e * 13;"
13584 : " }"
13585 : "})();");
13586 15 : CHECK_EQ(91, script->Run(env.local())
13587 : .ToLocalChecked()
13588 : ->Int32Value(env.local())
13589 : .FromJust());
13590 5 : }
13591 :
13592 :
13593 26645 : THREADED_TEST(RecursiveLocking) {
13594 12 : v8::Locker locker(CcTest::isolate());
13595 : {
13596 12 : v8::Locker locker2(CcTest::isolate());
13597 6 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13598 : }
13599 6 : }
13600 :
13601 :
13602 12 : static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13603 12 : ApiTestFuzzer::Fuzz();
13604 24 : v8::Unlocker unlocker(CcTest::isolate());
13605 12 : }
13606 :
13607 :
13608 26645 : THREADED_TEST(LockUnlockLock) {
13609 : {
13610 12 : v8::Locker locker(CcTest::isolate());
13611 12 : v8::HandleScope scope(CcTest::isolate());
13612 6 : LocalContext env;
13613 : Local<v8::FunctionTemplate> fun_templ =
13614 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13615 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13616 24 : CHECK(env->Global()
13617 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13618 : .FromJust());
13619 : Local<Script> script = v8_compile("(function () {"
13620 : " unlock_for_a_moment();"
13621 : " return 42;"
13622 : "})();");
13623 18 : CHECK_EQ(42, script->Run(env.local())
13624 : .ToLocalChecked()
13625 : ->Int32Value(env.local())
13626 : .FromJust());
13627 : }
13628 : {
13629 12 : v8::Locker locker(CcTest::isolate());
13630 12 : v8::HandleScope scope(CcTest::isolate());
13631 6 : LocalContext env;
13632 : Local<v8::FunctionTemplate> fun_templ =
13633 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13634 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13635 24 : CHECK(env->Global()
13636 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13637 : .FromJust());
13638 : Local<Script> script = v8_compile("(function () {"
13639 : " unlock_for_a_moment();"
13640 : " return 42;"
13641 : "})();");
13642 18 : CHECK_EQ(42, script->Run(env.local())
13643 : .ToLocalChecked()
13644 : ->Int32Value(env.local())
13645 : .FromJust());
13646 : }
13647 6 : }
13648 :
13649 :
13650 130 : static int GetGlobalObjectsCount() {
13651 : int count = 0;
13652 260 : i::HeapIterator it(CcTest::heap());
13653 705689 : for (i::HeapObject object = it.next(); !object.is_null();
13654 : object = it.next()) {
13655 705559 : if (object->IsJSGlobalObject()) {
13656 : i::JSGlobalObject g = i::JSGlobalObject::cast(object);
13657 : // Skip dummy global object.
13658 30 : if (g->global_dictionary()->NumberOfElements() != 0) {
13659 30 : count++;
13660 : }
13661 : }
13662 : }
13663 130 : return count;
13664 : }
13665 :
13666 :
13667 100 : static void CheckSurvivingGlobalObjectsCount(int expected) {
13668 : // We need to collect all garbage twice to be sure that everything
13669 : // has been collected. This is because inline caches are cleared in
13670 : // the first garbage collection but some of the maps have already
13671 : // been marked at that point. Therefore some of the maps are not
13672 : // collected until the second garbage collection.
13673 100 : CcTest::CollectAllGarbage();
13674 100 : CcTest::CollectAllGarbage();
13675 100 : int count = GetGlobalObjectsCount();
13676 100 : CHECK_EQ(expected, count);
13677 100 : }
13678 :
13679 :
13680 26644 : TEST(DontLeakGlobalObjects) {
13681 : // Regression test for issues 1139850 and 1174891.
13682 :
13683 5 : i::FLAG_expose_gc = true;
13684 5 : v8::V8::Initialize();
13685 :
13686 55 : for (int i = 0; i < 5; i++) {
13687 50 : { v8::HandleScope scope(CcTest::isolate());
13688 25 : LocalContext context;
13689 : }
13690 25 : CcTest::isolate()->ContextDisposedNotification();
13691 25 : CheckSurvivingGlobalObjectsCount(0);
13692 :
13693 50 : { v8::HandleScope scope(CcTest::isolate());
13694 25 : LocalContext context;
13695 25 : v8_compile("Date")->Run(context.local()).ToLocalChecked();
13696 : }
13697 25 : CcTest::isolate()->ContextDisposedNotification();
13698 25 : CheckSurvivingGlobalObjectsCount(0);
13699 :
13700 50 : { v8::HandleScope scope(CcTest::isolate());
13701 25 : LocalContext context;
13702 25 : v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
13703 : }
13704 25 : CcTest::isolate()->ContextDisposedNotification();
13705 25 : CheckSurvivingGlobalObjectsCount(0);
13706 :
13707 50 : { v8::HandleScope scope(CcTest::isolate());
13708 25 : const char* extension_list[] = { "v8/gc" };
13709 : v8::ExtensionConfiguration extensions(1, extension_list);
13710 25 : LocalContext context(&extensions);
13711 25 : v8_compile("gc();")->Run(context.local()).ToLocalChecked();
13712 : }
13713 25 : CcTest::isolate()->ContextDisposedNotification();
13714 25 : CheckSurvivingGlobalObjectsCount(0);
13715 : }
13716 5 : }
13717 :
13718 :
13719 26644 : TEST(CopyablePersistent) {
13720 5 : LocalContext context;
13721 5 : v8::Isolate* isolate = context->GetIsolate();
13722 : i::GlobalHandles* globals =
13723 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13724 : size_t initial_handles = globals->handles_count();
13725 : typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13726 : CopyableObject;
13727 : {
13728 : CopyableObject handle1;
13729 : {
13730 10 : v8::HandleScope scope(isolate);
13731 10 : handle1.Reset(isolate, v8::Object::New(isolate));
13732 : }
13733 5 : CHECK_EQ(initial_handles + 1, globals->handles_count());
13734 : CopyableObject handle2;
13735 : handle2 = handle1;
13736 5 : CHECK(handle1 == handle2);
13737 5 : CHECK_EQ(initial_handles + 2, globals->handles_count());
13738 : CopyableObject handle3(handle2);
13739 5 : CHECK(handle1 == handle3);
13740 5 : CHECK_EQ(initial_handles + 3, globals->handles_count());
13741 : }
13742 : // Verify autodispose
13743 5 : CHECK_EQ(initial_handles, globals->handles_count());
13744 5 : }
13745 :
13746 :
13747 5 : static void WeakApiCallback(
13748 : const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
13749 : data.GetParameter()->Reset();
13750 10 : delete data.GetParameter();
13751 5 : }
13752 :
13753 :
13754 26644 : TEST(WeakCallbackApi) {
13755 5 : LocalContext context;
13756 5 : v8::Isolate* isolate = context->GetIsolate();
13757 : i::GlobalHandles* globals =
13758 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13759 : size_t initial_handles = globals->handles_count();
13760 : {
13761 10 : v8::HandleScope scope(isolate);
13762 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
13763 20 : CHECK(
13764 : obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
13765 : .FromJust());
13766 : v8::Persistent<v8::Object>* handle =
13767 5 : new v8::Persistent<v8::Object>(isolate, obj);
13768 : handle->SetWeak<v8::Persistent<v8::Object>>(
13769 : handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
13770 : }
13771 5 : CcTest::PreciseCollectAllGarbage();
13772 : // Verify disposed.
13773 5 : CHECK_EQ(initial_handles, globals->handles_count());
13774 5 : }
13775 :
13776 :
13777 26639 : v8::Persistent<v8::Object> some_object;
13778 26639 : v8::Persistent<v8::Object> bad_handle;
13779 :
13780 :
13781 6 : void NewPersistentHandleCallback2(
13782 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13783 12 : v8::HandleScope scope(data.GetIsolate());
13784 : bad_handle.Reset(data.GetIsolate(), some_object);
13785 6 : }
13786 :
13787 :
13788 6 : void NewPersistentHandleCallback1(
13789 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13790 : data.GetParameter()->Reset();
13791 : data.SetSecondPassCallback(NewPersistentHandleCallback2);
13792 6 : }
13793 :
13794 :
13795 26645 : THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13796 6 : LocalContext context;
13797 6 : v8::Isolate* isolate = context->GetIsolate();
13798 :
13799 : v8::Persistent<v8::Object> handle1, handle2;
13800 : {
13801 12 : v8::HandleScope scope(isolate);
13802 12 : some_object.Reset(isolate, v8::Object::New(isolate));
13803 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13804 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13805 : }
13806 : // Note: order is implementation dependent alas: currently
13807 : // global handle nodes are processed by PostGarbageCollectionProcessing
13808 : // in reverse allocation order, so if second allocated handle is deleted,
13809 : // weak callback of the first handle would be able to 'reallocate' it.
13810 : handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
13811 : v8::WeakCallbackType::kParameter);
13812 : handle2.Reset();
13813 6 : CcTest::CollectAllGarbage();
13814 6 : }
13815 :
13816 :
13817 26639 : v8::Persistent<v8::Object> to_be_disposed;
13818 :
13819 :
13820 6 : void DisposeAndForceGcCallback2(
13821 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13822 : to_be_disposed.Reset();
13823 6 : CcTest::CollectAllGarbage();
13824 6 : }
13825 :
13826 :
13827 6 : void DisposeAndForceGcCallback1(
13828 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13829 : data.GetParameter()->Reset();
13830 : data.SetSecondPassCallback(DisposeAndForceGcCallback2);
13831 6 : }
13832 :
13833 :
13834 26645 : THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13835 6 : LocalContext context;
13836 6 : v8::Isolate* isolate = context->GetIsolate();
13837 :
13838 : v8::Persistent<v8::Object> handle1, handle2;
13839 : {
13840 12 : v8::HandleScope scope(isolate);
13841 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13842 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13843 : }
13844 : handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
13845 : v8::WeakCallbackType::kParameter);
13846 : to_be_disposed.Reset(isolate, handle2);
13847 6 : CcTest::CollectAllGarbage();
13848 6 : }
13849 :
13850 6 : void DisposingCallback(
13851 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13852 : data.GetParameter()->Reset();
13853 6 : }
13854 :
13855 6 : void HandleCreatingCallback2(
13856 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13857 12 : v8::HandleScope scope(data.GetIsolate());
13858 6 : v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
13859 6 : }
13860 :
13861 :
13862 6 : void HandleCreatingCallback1(
13863 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13864 : data.GetParameter()->Reset();
13865 : data.SetSecondPassCallback(HandleCreatingCallback2);
13866 6 : }
13867 :
13868 :
13869 26645 : THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13870 12 : v8::Locker locker(CcTest::isolate());
13871 6 : LocalContext context;
13872 6 : v8::Isolate* isolate = context->GetIsolate();
13873 :
13874 : v8::Persistent<v8::Object> handle1, handle2, handle3;
13875 : {
13876 12 : v8::HandleScope scope(isolate);
13877 12 : handle3.Reset(isolate, v8::Object::New(isolate));
13878 12 : handle2.Reset(isolate, v8::Object::New(isolate));
13879 12 : handle1.Reset(isolate, v8::Object::New(isolate));
13880 : }
13881 : handle2.SetWeak(&handle2, DisposingCallback,
13882 : v8::WeakCallbackType::kParameter);
13883 : handle3.SetWeak(&handle3, HandleCreatingCallback1,
13884 : v8::WeakCallbackType::kParameter);
13885 6 : CcTest::CollectAllGarbage();
13886 6 : EmptyMessageQueues(isolate);
13887 6 : }
13888 :
13889 :
13890 26645 : THREADED_TEST(CheckForCrossContextObjectLiterals) {
13891 6 : v8::V8::Initialize();
13892 :
13893 : const int nof = 2;
13894 : const char* sources[nof] = {
13895 : "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13896 : "Object()"
13897 6 : };
13898 :
13899 30 : for (int i = 0; i < nof; i++) {
13900 12 : const char* source = sources[i];
13901 24 : { v8::HandleScope scope(CcTest::isolate());
13902 12 : LocalContext context;
13903 : CompileRun(source);
13904 : }
13905 24 : { v8::HandleScope scope(CcTest::isolate());
13906 12 : LocalContext context;
13907 : CompileRun(source);
13908 : }
13909 : }
13910 6 : }
13911 :
13912 :
13913 6 : static v8::Local<Value> NestedScope(v8::Local<Context> env) {
13914 6 : v8::EscapableHandleScope inner(env->GetIsolate());
13915 6 : env->Enter();
13916 6 : v8::Local<Value> three = v8_num(3);
13917 : v8::Local<Value> value = inner.Escape(three);
13918 6 : env->Exit();
13919 12 : return value;
13920 : }
13921 :
13922 :
13923 26645 : THREADED_TEST(NestedHandleScopeAndContexts) {
13924 6 : v8::Isolate* isolate = CcTest::isolate();
13925 12 : v8::HandleScope outer(isolate);
13926 6 : v8::Local<Context> env = Context::New(isolate);
13927 6 : env->Enter();
13928 6 : v8::Local<Value> value = NestedScope(env);
13929 6 : v8::Local<String> str(value->ToString(env).ToLocalChecked());
13930 6 : CHECK(!str.IsEmpty());
13931 6 : env->Exit();
13932 6 : }
13933 :
13934 : static v8::base::HashMap* code_map = nullptr;
13935 : static v8::base::HashMap* jitcode_line_info = nullptr;
13936 : static int saw_bar = 0;
13937 : static int move_events = 0;
13938 :
13939 :
13940 5441 : static bool FunctionNameIs(const char* expected,
13941 : const v8::JitCodeEvent* event) {
13942 : // Log lines for functions are of the general form:
13943 : // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
13944 : // where the type is one of "*", "~" or "".
13945 : static const char* kPreamble;
13946 5441 : if (!i::FLAG_lazy) {
13947 0 : kPreamble = "Function:";
13948 : } else {
13949 5441 : kPreamble = "LazyCompile:";
13950 : }
13951 5441 : static size_t kPreambleLen = strlen(kPreamble);
13952 :
13953 10827 : if (event->name.len < kPreambleLen ||
13954 5386 : strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13955 : return false;
13956 : }
13957 :
13958 153 : const char* tail = event->name.str + kPreambleLen;
13959 153 : size_t tail_len = event->name.len - kPreambleLen;
13960 153 : size_t expected_len = strlen(expected);
13961 153 : if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13962 148 : --tail_len;
13963 148 : ++tail;
13964 : }
13965 :
13966 : // Check for tails like 'bar :1'.
13967 285 : if (tail_len > expected_len + 2 &&
13968 264 : tail[expected_len] == ' ' &&
13969 264 : tail[expected_len + 1] == ':' &&
13970 264 : tail[expected_len + 2] &&
13971 132 : !strncmp(tail, expected, expected_len)) {
13972 : return true;
13973 : }
13974 :
13975 87 : if (tail_len != expected_len)
13976 : return false;
13977 :
13978 21 : return strncmp(tail, expected, expected_len) == 0;
13979 : }
13980 :
13981 :
13982 7769 : static void event_handler(const v8::JitCodeEvent* event) {
13983 7769 : CHECK_NOT_NULL(event);
13984 7769 : CHECK_NOT_NULL(code_map);
13985 7769 : CHECK_NOT_NULL(jitcode_line_info);
13986 :
13987 : class DummyJitCodeLineInfo {
13988 : };
13989 :
13990 7769 : switch (event->type) {
13991 : case v8::JitCodeEvent::CODE_ADDED: {
13992 5441 : CHECK_NOT_NULL(event->code_start);
13993 5441 : CHECK_NE(0, static_cast<int>(event->code_len));
13994 5441 : CHECK_NOT_NULL(event->name.str);
13995 5441 : v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
13996 : event->code_start, i::ComputePointerHash(event->code_start));
13997 5441 : entry->value = reinterpret_cast<void*>(event->code_len);
13998 :
13999 5441 : if (FunctionNameIs("bar", event)) {
14000 66 : ++saw_bar;
14001 : }
14002 : }
14003 : break;
14004 :
14005 : case v8::JitCodeEvent::CODE_MOVED: {
14006 198 : uint32_t hash = i::ComputePointerHash(event->code_start);
14007 : // We would like to never see code move that we haven't seen before,
14008 : // but the code creation event does not happen until the line endings
14009 : // have been calculated (this is so that we can report the line in the
14010 : // script at which the function source is found, see
14011 : // Compiler::RecordFunctionCompilation) and the line endings
14012 : // calculations can cause a GC, which can move the newly created code
14013 : // before its existence can be logged.
14014 : v8::base::HashMap::Entry* entry =
14015 : code_map->Lookup(event->code_start, hash);
14016 198 : if (entry != nullptr) {
14017 198 : ++move_events;
14018 :
14019 198 : CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14020 198 : code_map->Remove(event->code_start, hash);
14021 :
14022 198 : entry = code_map->LookupOrInsert(
14023 : event->new_code_start,
14024 198 : i::ComputePointerHash(event->new_code_start));
14025 198 : entry->value = reinterpret_cast<void*>(event->code_len);
14026 : }
14027 : }
14028 : break;
14029 :
14030 : case v8::JitCodeEvent::CODE_REMOVED:
14031 : // Object/code removal events are currently not dispatched from the GC.
14032 0 : UNREACHABLE();
14033 :
14034 : // For CODE_START_LINE_INFO_RECORDING event, we will create one
14035 : // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14036 : // record it in jitcode_line_info.
14037 : case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14038 180 : DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14039 : v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14040 180 : temp_event->user_data = line_info;
14041 360 : v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14042 : line_info, i::ComputePointerHash(line_info));
14043 180 : entry->value = reinterpret_cast<void*>(line_info);
14044 : }
14045 180 : break;
14046 : // For these two events, we will check whether the event->user_data
14047 : // data structure is created before during CODE_START_LINE_INFO_RECORDING
14048 : // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14049 : case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14050 180 : CHECK_NOT_NULL(event->user_data);
14051 : uint32_t hash = i::ComputePointerHash(event->user_data);
14052 : v8::base::HashMap::Entry* entry =
14053 : jitcode_line_info->Lookup(event->user_data, hash);
14054 180 : CHECK_NOT_NULL(entry);
14055 180 : delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14056 : }
14057 180 : break;
14058 :
14059 : case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14060 1770 : CHECK_NOT_NULL(event->user_data);
14061 : uint32_t hash = i::ComputePointerHash(event->user_data);
14062 : v8::base::HashMap::Entry* entry =
14063 : jitcode_line_info->Lookup(event->user_data, hash);
14064 1770 : CHECK_NOT_NULL(entry);
14065 : }
14066 : break;
14067 :
14068 : default:
14069 : // Impossible event.
14070 0 : UNREACHABLE();
14071 : }
14072 7769 : }
14073 :
14074 :
14075 26644 : UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14076 5 : i::FLAG_stress_compaction = true;
14077 5 : i::FLAG_incremental_marking = false;
14078 5 : if (i::FLAG_never_compact) return;
14079 : const char* script =
14080 : "function bar() {"
14081 : " var sum = 0;"
14082 : " for (i = 0; i < 10; ++i)"
14083 : " sum = foo(i);"
14084 : " return sum;"
14085 : "}"
14086 : "function foo(i) { return i; };"
14087 : "bar();";
14088 :
14089 : // Run this test in a new isolate to make sure we don't
14090 : // have remnants of state from other code.
14091 : v8::Isolate::CreateParams create_params;
14092 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14093 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
14094 5 : isolate->Enter();
14095 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14096 : i::Heap* heap = i_isolate->heap();
14097 :
14098 : // Start with a clean slate.
14099 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14100 :
14101 : {
14102 10 : v8::HandleScope scope(isolate);
14103 : v8::base::HashMap code;
14104 5 : code_map = &code;
14105 :
14106 : v8::base::HashMap lineinfo;
14107 5 : jitcode_line_info = &lineinfo;
14108 :
14109 5 : saw_bar = 0;
14110 5 : move_events = 0;
14111 :
14112 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14113 :
14114 : // Generate new code objects sparsely distributed across several
14115 : // different fragmented code-space pages.
14116 : const int kIterations = 10;
14117 105 : for (int i = 0; i < kIterations; ++i) {
14118 50 : LocalContext env(isolate);
14119 : i::AlwaysAllocateScope always_allocate(i_isolate);
14120 : CompileRun(script);
14121 :
14122 : // Keep a strong reference to the code object in the handle scope.
14123 : i::Handle<i::JSFunction> bar(i::Handle<i::JSFunction>::cast(
14124 100 : v8::Utils::OpenHandle(*env->Global()
14125 150 : ->Get(env.local(), v8_str("bar"))
14126 : .ToLocalChecked())));
14127 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
14128 100 : v8::Utils::OpenHandle(*env->Global()
14129 150 : ->Get(env.local(), v8_str("foo"))
14130 : .ToLocalChecked())));
14131 :
14132 : i::PagedSpace* foo_owning_space = reinterpret_cast<i::PagedSpace*>(
14133 100 : i::Page::FromHeapObject(foo->abstract_code())->owner());
14134 : i::PagedSpace* bar_owning_space = reinterpret_cast<i::PagedSpace*>(
14135 100 : i::Page::FromHeapObject(bar->abstract_code())->owner());
14136 50 : CHECK_EQ(foo_owning_space, bar_owning_space);
14137 50 : i::heap::SimulateFullSpace(foo_owning_space);
14138 :
14139 : // Clear the compilation cache to get more wastage.
14140 50 : reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14141 : }
14142 :
14143 : // Force code movement.
14144 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14145 :
14146 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14147 :
14148 5 : CHECK_LE(kIterations, saw_bar);
14149 5 : CHECK_LT(0, move_events);
14150 :
14151 5 : code_map = nullptr;
14152 5 : jitcode_line_info = nullptr;
14153 : }
14154 :
14155 5 : isolate->Exit();
14156 5 : isolate->Dispose();
14157 :
14158 : // Do this in a new isolate.
14159 5 : isolate = v8::Isolate::New(create_params);
14160 5 : isolate->Enter();
14161 :
14162 : // Verify that we get callbacks for existing code objects when we
14163 : // request enumeration of existing code.
14164 : {
14165 10 : v8::HandleScope scope(isolate);
14166 5 : LocalContext env(isolate);
14167 : CompileRun(script);
14168 :
14169 : // Now get code through initial iteration.
14170 : v8::base::HashMap code;
14171 5 : code_map = &code;
14172 :
14173 : v8::base::HashMap lineinfo;
14174 5 : jitcode_line_info = &lineinfo;
14175 :
14176 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14177 5 : event_handler);
14178 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14179 :
14180 5 : jitcode_line_info = nullptr;
14181 : // We expect that we got some events. Note that if we could get code removal
14182 : // notifications, we could compare two collections, one created by listening
14183 : // from the time of creation of an isolate, and the other by subscribing
14184 : // with EnumExisting.
14185 5 : CHECK_LT(0u, code.occupancy());
14186 :
14187 5 : code_map = nullptr;
14188 : }
14189 :
14190 5 : isolate->Exit();
14191 5 : isolate->Dispose();
14192 : }
14193 :
14194 26644 : TEST(ExternalAllocatedMemory) {
14195 5 : v8::Isolate* isolate = CcTest::isolate();
14196 10 : v8::HandleScope outer(isolate);
14197 5 : v8::Local<Context> env(Context::New(isolate));
14198 5 : CHECK(!env.IsEmpty());
14199 : const int64_t kSize = 1024*1024;
14200 : int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14201 5 : CHECK_EQ(baseline + kSize,
14202 : isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14203 5 : CHECK_EQ(baseline,
14204 : isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14205 : const int64_t kTriggerGCSize =
14206 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14207 5 : CHECK_EQ(baseline + kTriggerGCSize,
14208 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14209 10 : CHECK_EQ(baseline,
14210 : isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14211 5 : }
14212 :
14213 :
14214 26644 : TEST(Regress51719) {
14215 5 : i::FLAG_incremental_marking = false;
14216 5 : CcTest::InitializeVM();
14217 :
14218 : const int64_t kTriggerGCSize =
14219 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14220 5 : v8::Isolate* isolate = CcTest::isolate();
14221 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14222 5 : }
14223 :
14224 : // Regression test for issue 54, object templates with embedder fields
14225 : // but no accessors or interceptors did not get their embedder field
14226 : // count set on instances.
14227 26645 : THREADED_TEST(Regress54) {
14228 6 : LocalContext context;
14229 6 : v8::Isolate* isolate = context->GetIsolate();
14230 12 : v8::HandleScope outer(isolate);
14231 12 : static v8::Persistent<v8::ObjectTemplate> templ;
14232 6 : if (templ.IsEmpty()) {
14233 6 : v8::EscapableHandleScope inner(isolate);
14234 6 : v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14235 6 : local->SetInternalFieldCount(1);
14236 : templ.Reset(isolate, inner.Escape(local));
14237 : }
14238 : v8::Local<v8::Object> result =
14239 : v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14240 6 : ->NewInstance(context.local())
14241 : .ToLocalChecked();
14242 6 : CHECK_EQ(1, result->InternalFieldCount());
14243 6 : }
14244 :
14245 :
14246 : // If part of the threaded tests, this test makes ThreadingTest fail
14247 : // on mac.
14248 26644 : TEST(CatchStackOverflow) {
14249 5 : LocalContext context;
14250 10 : v8::HandleScope scope(context->GetIsolate());
14251 10 : v8::TryCatch try_catch(context->GetIsolate());
14252 : v8::Local<v8::Value> result = CompileRun(
14253 : "function f() {"
14254 : " return f();"
14255 : "}"
14256 : ""
14257 : "f();");
14258 5 : CHECK(result.IsEmpty());
14259 5 : }
14260 :
14261 :
14262 18 : static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14263 : const char* resource_name,
14264 : int line_offset) {
14265 36 : v8::HandleScope scope(CcTest::isolate());
14266 36 : v8::TryCatch try_catch(CcTest::isolate());
14267 18 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14268 36 : CHECK(script->Run(context).IsEmpty());
14269 18 : CHECK(try_catch.HasCaught());
14270 18 : v8::Local<v8::Message> message = try_catch.Message();
14271 18 : CHECK(!message.IsEmpty());
14272 36 : CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14273 18 : CHECK_EQ(91, message->GetStartPosition());
14274 18 : CHECK_EQ(92, message->GetEndPosition());
14275 36 : CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14276 36 : CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14277 : v8::String::Utf8Value line(CcTest::isolate(),
14278 54 : message->GetSourceLine(context).ToLocalChecked());
14279 18 : CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14280 : v8::String::Utf8Value name(CcTest::isolate(),
14281 54 : message->GetScriptOrigin().ResourceName());
14282 18 : CHECK_EQ(0, strcmp(resource_name, *name));
14283 18 : }
14284 :
14285 :
14286 26645 : THREADED_TEST(TryCatchSourceInfo) {
14287 6 : LocalContext context;
14288 12 : v8::HandleScope scope(context->GetIsolate());
14289 : v8::Local<v8::String> source = v8_str(
14290 : "function Foo() {\n"
14291 : " return Bar();\n"
14292 : "}\n"
14293 : "\n"
14294 : "function Bar() {\n"
14295 : " return Baz();\n"
14296 : "}\n"
14297 : "\n"
14298 : "function Baz() {\n"
14299 : " throw 'nirk';\n"
14300 : "}\n"
14301 : "\n"
14302 6 : "Foo();\n");
14303 :
14304 : const char* resource_name;
14305 : v8::Local<v8::Script> script;
14306 : resource_name = "test.js";
14307 6 : script = CompileWithOrigin(source, resource_name, false);
14308 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14309 :
14310 : resource_name = "test1.js";
14311 6 : v8::ScriptOrigin origin1(v8_str(resource_name));
14312 : script =
14313 12 : v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
14314 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14315 :
14316 : resource_name = "test2.js";
14317 : v8::ScriptOrigin origin2(v8_str(resource_name),
14318 6 : v8::Integer::New(context->GetIsolate(), 7));
14319 : script =
14320 12 : v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
14321 6 : CheckTryCatchSourceInfo(script, resource_name, 7);
14322 6 : }
14323 :
14324 :
14325 26645 : THREADED_TEST(TryCatchSourceInfoForEOSError) {
14326 6 : LocalContext context;
14327 12 : v8::HandleScope scope(context->GetIsolate());
14328 12 : v8::TryCatch try_catch(context->GetIsolate());
14329 18 : CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
14330 6 : CHECK(try_catch.HasCaught());
14331 6 : v8::Local<v8::Message> message = try_catch.Message();
14332 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
14333 12 : CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
14334 6 : }
14335 :
14336 :
14337 26645 : THREADED_TEST(CompilationCache) {
14338 6 : LocalContext context;
14339 12 : v8::HandleScope scope(context->GetIsolate());
14340 6 : v8::Local<v8::String> source0 = v8_str("1234");
14341 6 : v8::Local<v8::String> source1 = v8_str("1234");
14342 6 : v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js", false);
14343 6 : v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js", false);
14344 6 : v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
14345 : .ToLocalChecked(); // different origin
14346 18 : CHECK_EQ(1234, script0->Run(context.local())
14347 : .ToLocalChecked()
14348 : ->Int32Value(context.local())
14349 : .FromJust());
14350 18 : CHECK_EQ(1234, script1->Run(context.local())
14351 : .ToLocalChecked()
14352 : ->Int32Value(context.local())
14353 : .FromJust());
14354 18 : CHECK_EQ(1234, script2->Run(context.local())
14355 : .ToLocalChecked()
14356 : ->Int32Value(context.local())
14357 : .FromJust());
14358 6 : }
14359 :
14360 :
14361 0 : static void FunctionNameCallback(
14362 : const v8::FunctionCallbackInfo<v8::Value>& args) {
14363 0 : ApiTestFuzzer::Fuzz();
14364 0 : args.GetReturnValue().Set(v8_num(42));
14365 0 : }
14366 :
14367 :
14368 26645 : THREADED_TEST(CallbackFunctionName) {
14369 6 : LocalContext context;
14370 6 : v8::Isolate* isolate = context->GetIsolate();
14371 12 : v8::HandleScope scope(isolate);
14372 6 : Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14373 18 : t->Set(v8_str("asdf"),
14374 6 : v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14375 30 : CHECK(context->Global()
14376 : ->Set(context.local(), v8_str("obj"),
14377 : t->NewInstance(context.local()).ToLocalChecked())
14378 : .FromJust());
14379 : v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
14380 6 : CHECK(value->IsString());
14381 12 : v8::String::Utf8Value name(isolate, value);
14382 6 : CHECK_EQ(0, strcmp("asdf", *name));
14383 6 : }
14384 :
14385 :
14386 26645 : THREADED_TEST(DateAccess) {
14387 6 : LocalContext context;
14388 12 : v8::HandleScope scope(context->GetIsolate());
14389 : v8::Local<v8::Value> date =
14390 6 : v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
14391 6 : CHECK(date->IsDate());
14392 6 : CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14393 6 : }
14394 :
14395 48 : void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14396 : unsigned index, const char* name) {
14397 48 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14398 : v8::Local<v8::Value> value =
14399 144 : properties->Get(context, v8::Integer::New(isolate, index))
14400 : .ToLocalChecked();
14401 48 : CHECK(value->IsSymbol());
14402 : v8::String::Utf8Value symbol_name(isolate,
14403 96 : Local<Symbol>::Cast(value)->Name());
14404 48 : if (strcmp(name, *symbol_name) != 0) {
14405 : FATAL("properties[%u] was Symbol('%s') instead of Symbol('%s').", index,
14406 0 : name, *symbol_name);
14407 : }
14408 48 : }
14409 :
14410 150 : void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14411 : unsigned length, const char* names[]) {
14412 150 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14413 150 : CHECK_EQ(length, properties->Length());
14414 1998 : for (unsigned i = 0; i < length; i++) {
14415 : v8::Local<v8::Value> value =
14416 2772 : properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
14417 924 : if (names[i] == nullptr) {
14418 : DCHECK(value->IsSymbol());
14419 : } else {
14420 1752 : v8::String::Utf8Value elm(isolate, value);
14421 876 : if (strcmp(names[i], *elm) != 0) {
14422 0 : FATAL("properties[%u] was '%s' instead of '%s'.", i, *elm, names[i]);
14423 : }
14424 : }
14425 : }
14426 150 : }
14427 :
14428 42 : void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14429 : unsigned length, const char* names[]) {
14430 42 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14431 : v8::Local<v8::Object> obj = val.As<v8::Object>();
14432 84 : v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
14433 42 : CheckStringArray(isolate, props, length, names);
14434 42 : }
14435 :
14436 :
14437 24 : void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14438 : unsigned elmc, const char* elmv[]) {
14439 24 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14440 : v8::Local<v8::Object> obj = val.As<v8::Object>();
14441 : v8::Local<v8::Array> props =
14442 24 : obj->GetOwnPropertyNames(context).ToLocalChecked();
14443 24 : CHECK_EQ(elmc, props->Length());
14444 108 : for (unsigned i = 0; i < elmc; i++) {
14445 : v8::String::Utf8Value elm(
14446 : isolate,
14447 168 : props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
14448 42 : CHECK_EQ(0, strcmp(elmv[i], *elm));
14449 : }
14450 24 : }
14451 :
14452 :
14453 26645 : THREADED_TEST(PropertyEnumeration) {
14454 6 : LocalContext context;
14455 6 : v8::Isolate* isolate = context->GetIsolate();
14456 12 : v8::HandleScope scope(isolate);
14457 : v8::Local<v8::Value> obj = CompileRun(
14458 : "var result = [];"
14459 : "result[0] = {};"
14460 : "result[1] = {a: 1, b: 2};"
14461 : "result[2] = [1, 2, 3];"
14462 : "var proto = {x: 1, y: 2, z: 3};"
14463 : "var x = { __proto__: proto, w: 0, z: 1 };"
14464 : "result[3] = x;"
14465 : "result[4] = {21350:1};"
14466 : "x = Object.create(null);"
14467 : "x.a = 1; x[12345678] = 1;"
14468 : "result[5] = x;"
14469 : "result;");
14470 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
14471 6 : CHECK_EQ(6u, elms->Length());
14472 : int elmc0 = 0;
14473 : const char** elmv0 = nullptr;
14474 : CheckProperties(
14475 : isolate,
14476 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14477 6 : elmc0, elmv0);
14478 : CheckOwnProperties(
14479 : isolate,
14480 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14481 6 : elmc0, elmv0);
14482 : int elmc1 = 2;
14483 6 : const char* elmv1[] = {"a", "b"};
14484 : CheckProperties(
14485 : isolate,
14486 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14487 6 : elmc1, elmv1);
14488 : CheckOwnProperties(
14489 : isolate,
14490 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14491 6 : elmc1, elmv1);
14492 : int elmc2 = 3;
14493 6 : const char* elmv2[] = {"0", "1", "2"};
14494 : CheckProperties(
14495 : isolate,
14496 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14497 6 : elmc2, elmv2);
14498 : CheckOwnProperties(
14499 : isolate,
14500 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14501 6 : elmc2, elmv2);
14502 : int elmc3 = 4;
14503 6 : const char* elmv3[] = {"w", "z", "x", "y"};
14504 : CheckProperties(
14505 : isolate,
14506 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14507 6 : elmc3, elmv3);
14508 : int elmc4 = 2;
14509 6 : const char* elmv4[] = {"w", "z"};
14510 : CheckOwnProperties(
14511 : isolate,
14512 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14513 6 : elmc4, elmv4);
14514 : // Dictionary elements.
14515 : int elmc5 = 1;
14516 6 : const char* elmv5[] = {"21350"};
14517 : CheckProperties(
14518 : isolate,
14519 18 : elms->Get(context.local(), v8::Integer::New(isolate, 4)).ToLocalChecked(),
14520 6 : elmc5, elmv5);
14521 : // Dictionary properties.
14522 : int elmc6 = 2;
14523 6 : const char* elmv6[] = {"12345678", "a"};
14524 : CheckProperties(
14525 : isolate,
14526 18 : elms->Get(context.local(), v8::Integer::New(isolate, 5)).ToLocalChecked(),
14527 6 : elmc6, elmv6);
14528 6 : }
14529 :
14530 :
14531 26645 : THREADED_TEST(PropertyEnumeration2) {
14532 6 : LocalContext context;
14533 6 : v8::Isolate* isolate = context->GetIsolate();
14534 12 : v8::HandleScope scope(isolate);
14535 : v8::Local<v8::Value> obj = CompileRun(
14536 : "var result = [];"
14537 : "result[0] = {};"
14538 : "result[1] = {a: 1, b: 2};"
14539 : "result[2] = [1, 2, 3];"
14540 : "var proto = {x: 1, y: 2, z: 3};"
14541 : "var x = { __proto__: proto, w: 0, z: 1 };"
14542 : "result[3] = x;"
14543 : "result;");
14544 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
14545 6 : CHECK_EQ(4u, elms->Length());
14546 : int elmc0 = 0;
14547 : const char** elmv0 = nullptr;
14548 : CheckProperties(
14549 : isolate,
14550 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14551 6 : elmc0, elmv0);
14552 :
14553 : v8::Local<v8::Value> val =
14554 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
14555 : v8::Local<v8::Array> props =
14556 6 : val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
14557 6 : CHECK_EQ(0u, props->Length());
14558 6 : for (uint32_t i = 0; i < props->Length(); i++) {
14559 : printf("p[%u]\n", i);
14560 : }
14561 6 : }
14562 :
14563 26645 : THREADED_TEST(GetPropertyNames) {
14564 6 : LocalContext context;
14565 6 : v8::Isolate* isolate = context->GetIsolate();
14566 12 : v8::HandleScope scope(isolate);
14567 : v8::Local<v8::Value> result = CompileRun(
14568 : "var result = {0: 0, 1: 1, a: 2, b: 3};"
14569 : "result[2**32] = '4294967296';"
14570 : "result[2**32-1] = '4294967295';"
14571 : "result[2**32-2] = '4294967294';"
14572 : "result[Symbol('symbol')] = true;"
14573 : "result.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14574 : "result;");
14575 : v8::Local<v8::Object> object = result.As<v8::Object>();
14576 : v8::PropertyFilter default_filter =
14577 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14578 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14579 :
14580 : v8::Local<v8::Array> properties =
14581 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
14582 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14583 : "b", "4294967296", "4294967295", "2",
14584 6 : "3", "c", "d"};
14585 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14586 :
14587 : properties =
14588 : object
14589 6 : ->GetPropertyNames(context.local(),
14590 : v8::KeyCollectionMode::kIncludePrototypes,
14591 : default_filter, v8::IndexFilter::kIncludeIndices)
14592 6 : .ToLocalChecked();
14593 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14594 :
14595 : properties = object
14596 6 : ->GetPropertyNames(context.local(),
14597 : v8::KeyCollectionMode::kIncludePrototypes,
14598 : include_symbols_filter,
14599 : v8::IndexFilter::kIncludeIndices)
14600 6 : .ToLocalChecked();
14601 : const char* expected_properties1_1[] = {
14602 : "0", "1", "4294967294", "a", "b", "4294967296",
14603 6 : "4294967295", nullptr, "2", "3", "c", "d"};
14604 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
14605 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14606 :
14607 : properties =
14608 : object
14609 6 : ->GetPropertyNames(context.local(),
14610 : v8::KeyCollectionMode::kIncludePrototypes,
14611 : default_filter, v8::IndexFilter::kSkipIndices)
14612 6 : .ToLocalChecked();
14613 : const char* expected_properties2[] = {"a", "b", "4294967296",
14614 6 : "4294967295", "c", "d"};
14615 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
14616 :
14617 : properties = object
14618 6 : ->GetPropertyNames(context.local(),
14619 : v8::KeyCollectionMode::kIncludePrototypes,
14620 : include_symbols_filter,
14621 : v8::IndexFilter::kSkipIndices)
14622 6 : .ToLocalChecked();
14623 : const char* expected_properties2_1[] = {
14624 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14625 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
14626 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14627 :
14628 : properties =
14629 : object
14630 6 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14631 : default_filter, v8::IndexFilter::kIncludeIndices)
14632 6 : .ToLocalChecked();
14633 : const char* expected_properties3[] = {
14634 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295",
14635 6 : };
14636 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
14637 :
14638 : properties = object
14639 6 : ->GetPropertyNames(
14640 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14641 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14642 6 : .ToLocalChecked();
14643 : const char* expected_properties3_1[] = {
14644 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14645 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
14646 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14647 :
14648 : properties =
14649 : object
14650 6 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14651 : default_filter, v8::IndexFilter::kSkipIndices)
14652 6 : .ToLocalChecked();
14653 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14654 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
14655 :
14656 : properties = object
14657 6 : ->GetPropertyNames(
14658 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14659 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
14660 6 : .ToLocalChecked();
14661 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14662 6 : nullptr};
14663 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
14664 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14665 6 : }
14666 :
14667 26645 : THREADED_TEST(ProxyGetPropertyNames) {
14668 6 : LocalContext context;
14669 6 : v8::Isolate* isolate = context->GetIsolate();
14670 12 : v8::HandleScope scope(isolate);
14671 : v8::Local<v8::Value> result = CompileRun(
14672 : "var target = {0: 0, 1: 1, a: 2, b: 3};"
14673 : "target[2**32] = '4294967296';"
14674 : "target[2**32-1] = '4294967295';"
14675 : "target[2**32-2] = '4294967294';"
14676 : "target[Symbol('symbol')] = true;"
14677 : "target.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14678 : "var result = new Proxy(target, {});"
14679 : "result;");
14680 : v8::Local<v8::Object> object = result.As<v8::Object>();
14681 : v8::PropertyFilter default_filter =
14682 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14683 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14684 :
14685 : v8::Local<v8::Array> properties =
14686 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
14687 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14688 : "b", "4294967296", "4294967295", "2",
14689 6 : "3", "c", "d"};
14690 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14691 :
14692 : properties =
14693 : object
14694 6 : ->GetPropertyNames(context.local(),
14695 : v8::KeyCollectionMode::kIncludePrototypes,
14696 : default_filter, v8::IndexFilter::kIncludeIndices)
14697 6 : .ToLocalChecked();
14698 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
14699 :
14700 : properties = object
14701 6 : ->GetPropertyNames(context.local(),
14702 : v8::KeyCollectionMode::kIncludePrototypes,
14703 : include_symbols_filter,
14704 : v8::IndexFilter::kIncludeIndices)
14705 6 : .ToLocalChecked();
14706 : const char* expected_properties1_1[] = {
14707 : "0", "1", "4294967294", "a", "b", "4294967296",
14708 6 : "4294967295", nullptr, "2", "3", "c", "d"};
14709 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
14710 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14711 :
14712 : properties =
14713 : object
14714 6 : ->GetPropertyNames(context.local(),
14715 : v8::KeyCollectionMode::kIncludePrototypes,
14716 : default_filter, v8::IndexFilter::kSkipIndices)
14717 6 : .ToLocalChecked();
14718 : const char* expected_properties2[] = {"a", "b", "4294967296",
14719 6 : "4294967295", "c", "d"};
14720 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
14721 :
14722 : properties = object
14723 6 : ->GetPropertyNames(context.local(),
14724 : v8::KeyCollectionMode::kIncludePrototypes,
14725 : include_symbols_filter,
14726 : v8::IndexFilter::kSkipIndices)
14727 6 : .ToLocalChecked();
14728 : const char* expected_properties2_1[] = {
14729 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14730 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
14731 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14732 :
14733 : properties =
14734 : object
14735 6 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14736 : default_filter, v8::IndexFilter::kIncludeIndices)
14737 6 : .ToLocalChecked();
14738 : const char* expected_properties3[] = {"0", "1", "4294967294", "a",
14739 6 : "b", "4294967296", "4294967295"};
14740 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
14741 :
14742 : properties = object
14743 6 : ->GetPropertyNames(
14744 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14745 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14746 6 : .ToLocalChecked();
14747 : const char* expected_properties3_1[] = {
14748 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14749 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
14750 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
14751 :
14752 : properties =
14753 : object
14754 6 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14755 : default_filter, v8::IndexFilter::kSkipIndices)
14756 6 : .ToLocalChecked();
14757 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14758 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
14759 :
14760 : properties = object
14761 6 : ->GetPropertyNames(
14762 : context.local(), v8::KeyCollectionMode::kOwnOnly,
14763 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
14764 6 : .ToLocalChecked();
14765 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14766 6 : nullptr};
14767 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
14768 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
14769 6 : }
14770 :
14771 26645 : THREADED_TEST(AccessChecksReenabledCorrectly) {
14772 6 : LocalContext context;
14773 6 : v8::Isolate* isolate = context->GetIsolate();
14774 12 : v8::HandleScope scope(isolate);
14775 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14776 6 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
14777 18 : templ->Set(v8_str("a"), v8_str("a"));
14778 : // Add more than 8 (see kMaxFastProperties) properties
14779 : // so that the constructor will force copying map.
14780 : // Cannot sprintf, gcc complains unsafety.
14781 : char buf[4];
14782 126 : for (char i = '0'; i <= '9' ; i++) {
14783 60 : buf[0] = i;
14784 1260 : for (char j = '0'; j <= '9'; j++) {
14785 600 : buf[1] = j;
14786 12600 : for (char k = '0'; k <= '9'; k++) {
14787 6000 : buf[2] = k;
14788 6000 : buf[3] = 0;
14789 18000 : templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14790 : }
14791 : }
14792 : }
14793 :
14794 : Local<v8::Object> instance_1 =
14795 6 : templ->NewInstance(context.local()).ToLocalChecked();
14796 24 : CHECK(context->Global()
14797 : ->Set(context.local(), v8_str("obj_1"), instance_1)
14798 : .FromJust());
14799 :
14800 : Local<Value> value_1 = CompileRun("obj_1.a");
14801 6 : CHECK(value_1.IsEmpty());
14802 :
14803 : Local<v8::Object> instance_2 =
14804 6 : templ->NewInstance(context.local()).ToLocalChecked();
14805 24 : CHECK(context->Global()
14806 : ->Set(context.local(), v8_str("obj_2"), instance_2)
14807 : .FromJust());
14808 :
14809 : Local<Value> value_2 = CompileRun("obj_2.a");
14810 6 : CHECK(value_2.IsEmpty());
14811 6 : }
14812 :
14813 :
14814 : // This tests that we do not allow dictionary load/call inline caches
14815 : // to use functions that have not yet been compiled. The potential
14816 : // problem of loading a function that has not yet been compiled can
14817 : // arise because we share code between contexts via the compilation
14818 : // cache.
14819 26645 : THREADED_TEST(DictionaryICLoadedFunction) {
14820 12 : v8::HandleScope scope(CcTest::isolate());
14821 : // Test LoadIC.
14822 30 : for (int i = 0; i < 2; i++) {
14823 12 : LocalContext context;
14824 60 : CHECK(context->Global()
14825 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14826 : .FromJust());
14827 48 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14828 : CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14829 : }
14830 : // Test CallIC.
14831 30 : for (int i = 0; i < 2; i++) {
14832 12 : LocalContext context;
14833 60 : CHECK(context->Global()
14834 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14835 : .FromJust());
14836 48 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14837 : CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14838 : }
14839 6 : }
14840 :
14841 :
14842 : // Test that cross-context new calls use the context of the callee to
14843 : // create the new JavaScript object.
14844 26645 : THREADED_TEST(CrossContextNew) {
14845 6 : v8::Isolate* isolate = CcTest::isolate();
14846 12 : v8::HandleScope scope(isolate);
14847 6 : v8::Local<Context> context0 = Context::New(isolate);
14848 6 : v8::Local<Context> context1 = Context::New(isolate);
14849 :
14850 : // Allow cross-domain access.
14851 6 : Local<String> token = v8_str("<security token>");
14852 6 : context0->SetSecurityToken(token);
14853 6 : context1->SetSecurityToken(token);
14854 :
14855 : // Set an 'x' property on the Object prototype and define a
14856 : // constructor function in context0.
14857 6 : context0->Enter();
14858 : CompileRun("Object.prototype.x = 42; function C() {};");
14859 6 : context0->Exit();
14860 :
14861 : // Call the constructor function from context0 and check that the
14862 : // result has the 'x' property.
14863 6 : context1->Enter();
14864 30 : CHECK(context1->Global()
14865 : ->Set(context1, v8_str("other"), context0->Global())
14866 : .FromJust());
14867 : Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14868 6 : CHECK(value->IsInt32());
14869 12 : CHECK_EQ(42, value->Int32Value(context1).FromJust());
14870 6 : context1->Exit();
14871 6 : }
14872 :
14873 :
14874 : // Verify that we can clone an object
14875 26644 : TEST(ObjectClone) {
14876 5 : LocalContext env;
14877 5 : v8::Isolate* isolate = env->GetIsolate();
14878 10 : v8::HandleScope scope(isolate);
14879 :
14880 : const char* sample =
14881 : "var rv = {};" \
14882 : "rv.alpha = 'hello';" \
14883 : "rv.beta = 123;" \
14884 : "rv;";
14885 :
14886 : // Create an object, verify basics.
14887 : Local<Value> val = CompileRun(sample);
14888 5 : CHECK(val->IsObject());
14889 : Local<v8::Object> obj = val.As<v8::Object>();
14890 20 : obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
14891 :
14892 25 : CHECK(v8_str("hello")
14893 : ->Equals(env.local(),
14894 : obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14895 : .FromJust());
14896 25 : CHECK(v8::Integer::New(isolate, 123)
14897 : ->Equals(env.local(),
14898 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14899 : .FromJust());
14900 25 : CHECK(v8_str("cloneme")
14901 : ->Equals(env.local(),
14902 : obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14903 : .FromJust());
14904 :
14905 : // Clone it.
14906 5 : Local<v8::Object> clone = obj->Clone();
14907 25 : CHECK(v8_str("hello")
14908 : ->Equals(env.local(),
14909 : clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14910 : .FromJust());
14911 25 : CHECK(v8::Integer::New(isolate, 123)
14912 : ->Equals(env.local(),
14913 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14914 : .FromJust());
14915 25 : CHECK(v8_str("cloneme")
14916 : ->Equals(env.local(),
14917 : clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14918 : .FromJust());
14919 :
14920 : // Set a property on the clone, verify each object.
14921 20 : CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
14922 : .FromJust());
14923 25 : CHECK(v8::Integer::New(isolate, 123)
14924 : ->Equals(env.local(),
14925 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14926 : .FromJust());
14927 25 : CHECK(v8::Integer::New(isolate, 456)
14928 : ->Equals(env.local(),
14929 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14930 : .FromJust());
14931 5 : }
14932 :
14933 :
14934 : class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
14935 : public:
14936 : explicit OneByteVectorResource(i::Vector<const char> vector)
14937 26645 : : data_(vector) {}
14938 53290 : ~OneByteVectorResource() override = default;
14939 58 : size_t length() const override { return data_.length(); }
14940 106729 : const char* data() const override { return data_.start(); }
14941 5 : void Dispose() override {}
14942 :
14943 : private:
14944 : i::Vector<const char> data_;
14945 : };
14946 :
14947 :
14948 : class UC16VectorResource : public v8::String::ExternalStringResource {
14949 : public:
14950 : explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14951 26645 : : data_(vector) {}
14952 53290 : ~UC16VectorResource() override = default;
14953 34 : size_t length() const override { return data_.length(); }
14954 108562 : const i::uc16* data() const override { return data_.start(); }
14955 5 : void Dispose() override {}
14956 :
14957 : private:
14958 : i::Vector<const i::uc16> data_;
14959 : };
14960 :
14961 12 : static void MorphAString(i::String string,
14962 : OneByteVectorResource* one_byte_resource,
14963 : UC16VectorResource* uc16_resource) {
14964 : i::Isolate* isolate = CcTest::i_isolate();
14965 12 : CHECK(i::StringShape(string).IsExternal());
14966 12 : i::ReadOnlyRoots roots(CcTest::heap());
14967 12 : if (string->IsOneByteRepresentation()) {
14968 : // Check old map is not internalized or long.
14969 12 : CHECK(string->map() == roots.external_one_byte_string_map());
14970 : // Morph external string to be TwoByte string.
14971 12 : string->set_map(roots.external_string_map());
14972 12 : i::ExternalTwoByteString morphed = i::ExternalTwoByteString::cast(string);
14973 12 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14974 12 : morphed->SetResource(isolate, uc16_resource);
14975 : } else {
14976 : // Check old map is not internalized or long.
14977 0 : CHECK(string->map() == roots.external_string_map());
14978 : // Morph external string to be one-byte string.
14979 0 : string->set_map(roots.external_one_byte_string_map());
14980 0 : i::ExternalOneByteString morphed = i::ExternalOneByteString::cast(string);
14981 0 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14982 0 : morphed->SetResource(isolate, one_byte_resource);
14983 : }
14984 12 : }
14985 :
14986 : // Test that we can still flatten a string if the components it is built up
14987 : // from have been turned into 16 bit strings in the mean time.
14988 26645 : THREADED_TEST(MorphCompositeStringTest) {
14989 : char utf_buffer[129];
14990 : const char* c_string = "Now is the time for all good men"
14991 : " to come to the aid of the party";
14992 6 : uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14993 : {
14994 6 : LocalContext env;
14995 : i::Factory* factory = CcTest::i_isolate()->factory();
14996 6 : v8::Isolate* isolate = env->GetIsolate();
14997 : i::Isolate* i_isolate = CcTest::i_isolate();
14998 12 : v8::HandleScope scope(isolate);
14999 : OneByteVectorResource one_byte_resource(
15000 : i::Vector<const char>(c_string, i::StrLength(c_string)));
15001 : UC16VectorResource uc16_resource(
15002 : i::Vector<const uint16_t>(two_byte_string, i::StrLength(c_string)));
15003 :
15004 : Local<String> lhs(v8::Utils::ToLocal(
15005 12 : factory->NewExternalStringFromOneByte(&one_byte_resource)
15006 : .ToHandleChecked()));
15007 : Local<String> rhs(v8::Utils::ToLocal(
15008 12 : factory->NewExternalStringFromOneByte(&one_byte_resource)
15009 : .ToHandleChecked()));
15010 :
15011 24 : CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
15012 24 : CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
15013 :
15014 : CompileRun(
15015 : "var cons = lhs + rhs;"
15016 : "var slice = lhs.substring(1, lhs.length - 1);"
15017 : "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15018 :
15019 6 : CHECK(lhs->IsOneByte());
15020 6 : CHECK(rhs->IsOneByte());
15021 :
15022 : i::String ilhs = *v8::Utils::OpenHandle(*lhs);
15023 : i::String irhs = *v8::Utils::OpenHandle(*rhs);
15024 6 : MorphAString(ilhs, &one_byte_resource, &uc16_resource);
15025 6 : MorphAString(irhs, &one_byte_resource, &uc16_resource);
15026 :
15027 : // This should UTF-8 without flattening, since everything is ASCII.
15028 : Local<String> cons =
15029 6 : v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15030 6 : CHECK_EQ(128, cons->Utf8Length(isolate));
15031 6 : int nchars = -1;
15032 6 : CHECK_EQ(129, cons->WriteUtf8(isolate, utf_buffer, -1, &nchars));
15033 6 : CHECK_EQ(128, nchars);
15034 6 : CHECK_EQ(0, strcmp(
15035 : utf_buffer,
15036 : "Now is the time for all good men to come to the aid of the party"
15037 : "Now is the time for all good men to come to the aid of the party"));
15038 :
15039 : // Now do some stuff to make sure the strings are flattened, etc.
15040 : CompileRun(
15041 : "/[^a-z]/.test(cons);"
15042 : "/[^a-z]/.test(slice);"
15043 : "/[^a-z]/.test(slice_on_cons);");
15044 : const char* expected_cons =
15045 : "Now is the time for all good men to come to the aid of the party"
15046 : "Now is the time for all good men to come to the aid of the party";
15047 : const char* expected_slice =
15048 : "ow is the time for all good men to come to the aid of the part";
15049 : const char* expected_slice_on_cons =
15050 : "ow is the time for all good men to come to the aid of the party"
15051 : "Now is the time for all good men to come to the aid of the part";
15052 36 : CHECK(v8_str(expected_cons)
15053 : ->Equals(env.local(), env->Global()
15054 : ->Get(env.local(), v8_str("cons"))
15055 : .ToLocalChecked())
15056 : .FromJust());
15057 36 : CHECK(v8_str(expected_slice)
15058 : ->Equals(env.local(), env->Global()
15059 : ->Get(env.local(), v8_str("slice"))
15060 : .ToLocalChecked())
15061 : .FromJust());
15062 36 : CHECK(v8_str(expected_slice_on_cons)
15063 : ->Equals(env.local(),
15064 : env->Global()
15065 : ->Get(env.local(), v8_str("slice_on_cons"))
15066 : .ToLocalChecked())
15067 : .FromJust());
15068 :
15069 : // This avoids the GC from trying to free a stack allocated resource.
15070 6 : if (ilhs->IsExternalOneByteString())
15071 0 : i::ExternalOneByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15072 : else
15073 6 : i::ExternalTwoByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15074 6 : if (irhs->IsExternalOneByteString())
15075 0 : i::ExternalOneByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15076 : else
15077 6 : i::ExternalTwoByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15078 : }
15079 : i::DeleteArray(two_byte_string);
15080 6 : }
15081 :
15082 :
15083 26644 : TEST(CompileExternalTwoByteSource) {
15084 5 : LocalContext context;
15085 10 : v8::HandleScope scope(context->GetIsolate());
15086 :
15087 : // This is a very short list of sources, which currently is to check for a
15088 : // regression caused by r2703.
15089 : const char* one_byte_sources[] = {
15090 : "0.5",
15091 : "-0.5", // This mainly testes PushBack in the Scanner.
15092 : "--0.5", // This mainly testes PushBack in the Scanner.
15093 5 : nullptr};
15094 :
15095 : // Compile the sources as external two byte strings.
15096 35 : for (int i = 0; one_byte_sources[i] != nullptr; i++) {
15097 15 : uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15098 15 : TestResource* uc16_resource = new TestResource(two_byte_string);
15099 : v8::Local<v8::String> source =
15100 15 : v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15101 15 : .ToLocalChecked();
15102 15 : v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15103 : }
15104 5 : }
15105 :
15106 : // Test that we cannot set a property on the global object if there
15107 : // is a read-only property in the prototype chain.
15108 26644 : TEST(ReadOnlyPropertyInGlobalProto) {
15109 5 : v8::Isolate* isolate = CcTest::isolate();
15110 10 : v8::HandleScope scope(isolate);
15111 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15112 5 : LocalContext context(nullptr, templ);
15113 5 : v8::Local<v8::Object> global = context->Global();
15114 : v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15115 15 : global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15116 10 : global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15117 15 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15118 : .FromJust();
15119 10 : global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15120 15 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15121 : .FromJust();
15122 : // Check without 'eval' or 'with'.
15123 : v8::Local<v8::Value> res =
15124 5 : CompileRun("function f() { x = 42; return x; }; f()");
15125 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15126 : // Check with 'eval'.
15127 5 : res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15128 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15129 : // Check with 'with'.
15130 5 : res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15131 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15132 5 : }
15133 :
15134 :
15135 26644 : TEST(CreateDataProperty) {
15136 5 : LocalContext env;
15137 5 : v8::Isolate* isolate = env->GetIsolate();
15138 10 : v8::HandleScope handle_scope(isolate);
15139 :
15140 : CompileRun(
15141 : "var a = {};"
15142 : "var b = [];"
15143 : "Object.defineProperty(a, 'foo', {value: 23});"
15144 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15145 :
15146 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15147 20 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15148 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15149 20 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15150 : {
15151 : // Can't change a non-configurable properties.
15152 10 : v8::TryCatch try_catch(isolate);
15153 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15154 : v8::Integer::New(isolate, 42)).FromJust());
15155 5 : CHECK(!try_catch.HasCaught());
15156 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15157 : v8::Integer::New(isolate, 42)).FromJust());
15158 5 : CHECK(!try_catch.HasCaught());
15159 : v8::Local<v8::Value> val =
15160 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15161 5 : CHECK(val->IsNumber());
15162 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15163 : }
15164 :
15165 : {
15166 : // Set a regular property.
15167 10 : v8::TryCatch try_catch(isolate);
15168 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15169 : v8::Integer::New(isolate, 42)).FromJust());
15170 5 : CHECK(!try_catch.HasCaught());
15171 : v8::Local<v8::Value> val =
15172 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15173 5 : CHECK(val->IsNumber());
15174 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15175 : }
15176 :
15177 : {
15178 : // Set an indexed property.
15179 10 : v8::TryCatch try_catch(isolate);
15180 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15181 : v8::Integer::New(isolate, 42)).FromJust());
15182 5 : CHECK(!try_catch.HasCaught());
15183 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15184 5 : CHECK(val->IsNumber());
15185 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15186 : }
15187 :
15188 : {
15189 : // Special cases for arrays.
15190 10 : v8::TryCatch try_catch(isolate);
15191 20 : CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15192 : v8::Integer::New(isolate, 1)).FromJust());
15193 5 : CHECK(!try_catch.HasCaught());
15194 : }
15195 : {
15196 : // Special cases for arrays: index exceeds the array's length
15197 10 : v8::TryCatch try_catch(isolate);
15198 15 : CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15199 : .FromJust());
15200 5 : CHECK(!try_catch.HasCaught());
15201 5 : CHECK_EQ(2U, arr->Length());
15202 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15203 5 : CHECK(val->IsNumber());
15204 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15205 :
15206 : // Set an existing entry.
15207 15 : CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15208 : .FromJust());
15209 5 : CHECK(!try_catch.HasCaught());
15210 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15211 5 : CHECK(val->IsNumber());
15212 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15213 : }
15214 :
15215 : CompileRun("Object.freeze(a);");
15216 : {
15217 : // Can't change non-extensible objects.
15218 10 : v8::TryCatch try_catch(isolate);
15219 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15220 : v8::Integer::New(isolate, 42)).FromJust());
15221 5 : CHECK(!try_catch.HasCaught());
15222 : }
15223 :
15224 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15225 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15226 : v8::Local<v8::Object> access_checked =
15227 5 : templ->NewInstance(env.local()).ToLocalChecked();
15228 : {
15229 10 : v8::TryCatch try_catch(isolate);
15230 20 : CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15231 : v8::Integer::New(isolate, 42))
15232 : .IsNothing());
15233 5 : CHECK(try_catch.HasCaught());
15234 : }
15235 5 : }
15236 :
15237 :
15238 26644 : TEST(DefineOwnProperty) {
15239 5 : LocalContext env;
15240 5 : v8::Isolate* isolate = env->GetIsolate();
15241 10 : v8::HandleScope handle_scope(isolate);
15242 :
15243 : CompileRun(
15244 : "var a = {};"
15245 : "var b = [];"
15246 : "Object.defineProperty(a, 'foo', {value: 23});"
15247 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15248 :
15249 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15250 20 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15251 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15252 20 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15253 : {
15254 : // Can't change a non-configurable properties.
15255 10 : v8::TryCatch try_catch(isolate);
15256 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15257 : v8::Integer::New(isolate, 42)).FromJust());
15258 5 : CHECK(!try_catch.HasCaught());
15259 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15260 : v8::Integer::New(isolate, 42)).FromJust());
15261 5 : CHECK(!try_catch.HasCaught());
15262 : v8::Local<v8::Value> val =
15263 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15264 5 : CHECK(val->IsNumber());
15265 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15266 : }
15267 :
15268 : {
15269 : // Set a regular property.
15270 10 : v8::TryCatch try_catch(isolate);
15271 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15272 : v8::Integer::New(isolate, 42)).FromJust());
15273 5 : CHECK(!try_catch.HasCaught());
15274 : v8::Local<v8::Value> val =
15275 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15276 5 : CHECK(val->IsNumber());
15277 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15278 : }
15279 :
15280 : {
15281 : // Set an indexed property.
15282 10 : v8::TryCatch try_catch(isolate);
15283 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15284 : v8::Integer::New(isolate, 42)).FromJust());
15285 5 : CHECK(!try_catch.HasCaught());
15286 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15287 5 : CHECK(val->IsNumber());
15288 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15289 : }
15290 :
15291 : {
15292 : // Special cases for arrays.
15293 10 : v8::TryCatch try_catch(isolate);
15294 20 : CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15295 : v8::Integer::New(isolate, 1)).FromJust());
15296 5 : CHECK(!try_catch.HasCaught());
15297 : }
15298 : {
15299 : // Special cases for arrays: index exceeds the array's length
15300 10 : v8::TryCatch try_catch(isolate);
15301 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15302 : v8::Integer::New(isolate, 23)).FromJust());
15303 5 : CHECK(!try_catch.HasCaught());
15304 5 : CHECK_EQ(2U, arr->Length());
15305 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15306 5 : CHECK(val->IsNumber());
15307 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15308 :
15309 : // Set an existing entry.
15310 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15311 : v8::Integer::New(isolate, 42)).FromJust());
15312 5 : CHECK(!try_catch.HasCaught());
15313 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15314 5 : CHECK(val->IsNumber());
15315 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15316 : }
15317 :
15318 : {
15319 : // Set a non-writable property.
15320 10 : v8::TryCatch try_catch(isolate);
15321 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15322 : v8::Integer::New(isolate, 42),
15323 : v8::ReadOnly).FromJust());
15324 5 : CHECK(!try_catch.HasCaught());
15325 : v8::Local<v8::Value> val =
15326 15 : obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15327 5 : CHECK(val->IsNumber());
15328 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15329 15 : CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
15330 : env.local(), v8_str("lala")).FromJust());
15331 5 : CHECK(!try_catch.HasCaught());
15332 : }
15333 :
15334 : CompileRun("Object.freeze(a);");
15335 : {
15336 : // Can't change non-extensible objects.
15337 10 : v8::TryCatch try_catch(isolate);
15338 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
15339 : v8::Integer::New(isolate, 42)).FromJust());
15340 5 : CHECK(!try_catch.HasCaught());
15341 : }
15342 :
15343 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15344 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15345 : v8::Local<v8::Object> access_checked =
15346 5 : templ->NewInstance(env.local()).ToLocalChecked();
15347 : {
15348 10 : v8::TryCatch try_catch(isolate);
15349 20 : CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
15350 : v8::Integer::New(isolate, 42))
15351 : .IsNothing());
15352 5 : CHECK(try_catch.HasCaught());
15353 : }
15354 5 : }
15355 :
15356 26644 : TEST(DefineProperty) {
15357 5 : LocalContext env;
15358 5 : v8::Isolate* isolate = env->GetIsolate();
15359 10 : v8::HandleScope handle_scope(isolate);
15360 :
15361 : v8::Local<v8::Name> p;
15362 :
15363 : CompileRun(
15364 : "var a = {};"
15365 : "var b = [];"
15366 : "Object.defineProperty(a, 'v1', {value: 23});"
15367 : "Object.defineProperty(a, 'v2', {value: 23, configurable: true});");
15368 :
15369 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15370 20 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15371 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15372 20 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15373 :
15374 10 : v8::PropertyDescriptor desc(v8_num(42));
15375 : {
15376 : // Use a data descriptor.
15377 :
15378 : // Cannot change a non-configurable property.
15379 5 : p = v8_str("v1");
15380 10 : v8::TryCatch try_catch(isolate);
15381 10 : CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
15382 5 : CHECK(!try_catch.HasCaught());
15383 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15384 5 : CHECK(val->IsNumber());
15385 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15386 :
15387 : // Change a configurable property.
15388 5 : p = v8_str("v2");
15389 10 : obj->DefineProperty(env.local(), p, desc).FromJust();
15390 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15391 5 : CHECK(!try_catch.HasCaught());
15392 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15393 5 : CHECK(val->IsNumber());
15394 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15395 :
15396 : // Check that missing writable has default value false.
15397 5 : p = v8_str("v12");
15398 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15399 5 : CHECK(!try_catch.HasCaught());
15400 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15401 5 : CHECK(val->IsNumber());
15402 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15403 10 : v8::PropertyDescriptor desc2(v8_num(43));
15404 10 : CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust());
15405 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15406 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15407 5 : CHECK(!try_catch.HasCaught());
15408 : }
15409 :
15410 : {
15411 : // Set a regular property.
15412 5 : p = v8_str("v3");
15413 10 : v8::TryCatch try_catch(isolate);
15414 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15415 5 : CHECK(!try_catch.HasCaught());
15416 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15417 5 : CHECK(val->IsNumber());
15418 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15419 : }
15420 :
15421 : {
15422 : // Set an indexed property.
15423 10 : v8::TryCatch try_catch(isolate);
15424 15 : CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust());
15425 5 : CHECK(!try_catch.HasCaught());
15426 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15427 5 : CHECK(val->IsNumber());
15428 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15429 : }
15430 :
15431 : {
15432 : // No special case when changing array length.
15433 10 : v8::TryCatch try_catch(isolate);
15434 : // Use a writable descriptor, otherwise the next test, that changes
15435 : // the array length will fail.
15436 10 : v8::PropertyDescriptor desc(v8_num(42), true);
15437 15 : CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust());
15438 5 : CHECK(!try_catch.HasCaught());
15439 : }
15440 :
15441 : {
15442 : // Special cases for arrays: index exceeds the array's length.
15443 10 : v8::TryCatch try_catch(isolate);
15444 15 : CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust());
15445 5 : CHECK(!try_catch.HasCaught());
15446 5 : CHECK_EQ(101U, arr->Length());
15447 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
15448 5 : CHECK(val->IsNumber());
15449 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15450 :
15451 : // Set an existing entry.
15452 15 : CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust());
15453 5 : CHECK(!try_catch.HasCaught());
15454 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15455 5 : CHECK(val->IsNumber());
15456 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15457 : }
15458 :
15459 : {
15460 : // Use a generic descriptor.
15461 10 : v8::PropertyDescriptor desc_generic;
15462 :
15463 5 : p = v8_str("v4");
15464 10 : v8::TryCatch try_catch(isolate);
15465 10 : CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust());
15466 5 : CHECK(!try_catch.HasCaught());
15467 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15468 5 : CHECK(val->IsUndefined());
15469 :
15470 15 : obj->Set(env.local(), p, v8_num(1)).FromJust();
15471 5 : CHECK(!try_catch.HasCaught());
15472 :
15473 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15474 5 : CHECK(val->IsUndefined());
15475 5 : CHECK(!try_catch.HasCaught());
15476 : }
15477 :
15478 : {
15479 : // Use a data descriptor with undefined value.
15480 10 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate));
15481 :
15482 10 : v8::TryCatch try_catch(isolate);
15483 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15484 5 : CHECK(!try_catch.HasCaught());
15485 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15486 5 : CHECK(val->IsUndefined());
15487 5 : CHECK(!try_catch.HasCaught());
15488 : }
15489 :
15490 : {
15491 : // Use a descriptor with attribute == v8::ReadOnly.
15492 10 : v8::PropertyDescriptor desc_read_only(v8_num(42), false);
15493 5 : desc_read_only.set_enumerable(true);
15494 5 : desc_read_only.set_configurable(true);
15495 :
15496 5 : p = v8_str("v5");
15497 10 : v8::TryCatch try_catch(isolate);
15498 10 : CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust());
15499 5 : CHECK(!try_catch.HasCaught());
15500 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15501 5 : CHECK(val->IsNumber());
15502 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15503 10 : CHECK_EQ(v8::ReadOnly,
15504 : obj->GetPropertyAttributes(env.local(), p).FromJust());
15505 5 : CHECK(!try_catch.HasCaught());
15506 : }
15507 :
15508 : {
15509 : // Use an accessor descriptor with empty handles.
15510 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate),
15511 10 : v8::Undefined(isolate));
15512 :
15513 5 : p = v8_str("v6");
15514 10 : v8::TryCatch try_catch(isolate);
15515 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15516 5 : CHECK(!try_catch.HasCaught());
15517 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15518 5 : CHECK(val->IsUndefined());
15519 5 : CHECK(!try_catch.HasCaught());
15520 : }
15521 :
15522 : {
15523 : // Use an accessor descriptor.
15524 : CompileRun(
15525 : "var set = function(x) {this.val = 2*x;};"
15526 : "var get = function() {return this.val || 0;};");
15527 :
15528 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15529 20 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15530 : v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
15531 20 : env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
15532 10 : v8::PropertyDescriptor desc(get, set);
15533 :
15534 5 : p = v8_str("v7");
15535 10 : v8::TryCatch try_catch(isolate);
15536 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15537 5 : CHECK(!try_catch.HasCaught());
15538 :
15539 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15540 5 : CHECK(val->IsNumber());
15541 10 : CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
15542 5 : CHECK(!try_catch.HasCaught());
15543 :
15544 15 : obj->Set(env.local(), p, v8_num(7)).FromJust();
15545 5 : CHECK(!try_catch.HasCaught());
15546 :
15547 10 : val = obj->Get(env.local(), p).ToLocalChecked();
15548 5 : CHECK(val->IsNumber());
15549 10 : CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
15550 5 : CHECK(!try_catch.HasCaught());
15551 : }
15552 :
15553 : {
15554 : // Redefine an existing property.
15555 :
15556 : // desc = {value: 42, enumerable: true}
15557 10 : v8::PropertyDescriptor desc(v8_num(42));
15558 5 : desc.set_enumerable(true);
15559 :
15560 5 : p = v8_str("v8");
15561 10 : v8::TryCatch try_catch(isolate);
15562 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15563 5 : CHECK(!try_catch.HasCaught());
15564 :
15565 : // desc = {enumerable: true}
15566 10 : v8::PropertyDescriptor desc_true((v8::Local<v8::Value>()));
15567 5 : desc_true.set_enumerable(true);
15568 :
15569 : // Successful redefinition because all present attributes have the same
15570 : // value as the current descriptor.
15571 10 : CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust());
15572 5 : CHECK(!try_catch.HasCaught());
15573 :
15574 : // desc = {}
15575 10 : v8::PropertyDescriptor desc_empty;
15576 : // Successful redefinition because no attributes are overwritten in the
15577 : // current descriptor.
15578 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15579 5 : CHECK(!try_catch.HasCaught());
15580 :
15581 : // desc = {enumerable: false}
15582 10 : v8::PropertyDescriptor desc_false((v8::Local<v8::Value>()));
15583 5 : desc_false.set_enumerable(false);
15584 : // Not successful because we cannot define a different value for enumerable.
15585 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
15586 5 : CHECK(!try_catch.HasCaught());
15587 : }
15588 :
15589 : {
15590 : // Redefine a property that has a getter.
15591 : CompileRun("var get = function() {};");
15592 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15593 20 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15594 :
15595 : // desc = {get: function() {}}
15596 10 : v8::PropertyDescriptor desc(get, v8::Local<v8::Function>());
15597 10 : v8::TryCatch try_catch(isolate);
15598 :
15599 5 : p = v8_str("v9");
15600 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15601 5 : CHECK(!try_catch.HasCaught());
15602 :
15603 : // desc_empty = {}
15604 : // Successful because we are not redefining the current getter.
15605 10 : v8::PropertyDescriptor desc_empty;
15606 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15607 5 : CHECK(!try_catch.HasCaught());
15608 :
15609 : // desc = {get: function() {}}
15610 : // Successful because we redefine the getter with its current value.
15611 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15612 5 : CHECK(!try_catch.HasCaught());
15613 :
15614 : // desc = {get: undefined}
15615 : v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate),
15616 10 : v8::Local<v8::Function>());
15617 : // Not successful because we cannot redefine with the current value of get
15618 : // with undefined.
15619 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust());
15620 5 : CHECK(!try_catch.HasCaught());
15621 : }
15622 :
15623 : CompileRun("Object.freeze(a);");
15624 : {
15625 : // We cannot change non-extensible objects.
15626 10 : v8::TryCatch try_catch(isolate);
15627 15 : CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust());
15628 5 : CHECK(!try_catch.HasCaught());
15629 : }
15630 :
15631 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15632 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15633 : v8::Local<v8::Object> access_checked =
15634 5 : templ->NewInstance(env.local()).ToLocalChecked();
15635 : {
15636 10 : v8::TryCatch try_catch(isolate);
15637 15 : CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc)
15638 : .IsNothing());
15639 5 : CHECK(try_catch.HasCaught());
15640 : }
15641 5 : }
15642 :
15643 26645 : THREADED_TEST(GetCurrentContextWhenNotInContext) {
15644 : i::Isolate* isolate = CcTest::i_isolate();
15645 6 : CHECK_NOT_NULL(isolate);
15646 6 : CHECK(isolate->context().is_null());
15647 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15648 12 : v8::HandleScope scope(v8_isolate);
15649 : // The following should not crash, but return an empty handle.
15650 6 : v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15651 6 : CHECK(current.IsEmpty());
15652 6 : }
15653 :
15654 :
15655 : // Check that a variable declaration with no explicit initialization
15656 : // value does shadow an existing property in the prototype chain.
15657 26645 : THREADED_TEST(InitGlobalVarInProtoChain) {
15658 6 : LocalContext context;
15659 12 : v8::HandleScope scope(context->GetIsolate());
15660 : // Introduce a variable in the prototype chain.
15661 : CompileRun("__proto__.x = 42");
15662 : v8::Local<v8::Value> result = CompileRun("var x = 43; x");
15663 6 : CHECK(!result->IsUndefined());
15664 12 : CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
15665 6 : }
15666 :
15667 :
15668 : // Regression test for issue 398.
15669 : // If a function is added to an object, creating a constant function
15670 : // field, and the result is cloned, replacing the constant function on the
15671 : // original should not affect the clone.
15672 : // See http://code.google.com/p/v8/issues/detail?id=398
15673 26645 : THREADED_TEST(ReplaceConstantFunction) {
15674 6 : LocalContext context;
15675 6 : v8::Isolate* isolate = context->GetIsolate();
15676 12 : v8::HandleScope scope(isolate);
15677 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
15678 : v8::Local<v8::FunctionTemplate> func_templ =
15679 6 : v8::FunctionTemplate::New(isolate);
15680 6 : v8::Local<v8::String> foo_string = v8_str("foo");
15681 12 : obj->Set(context.local(), foo_string,
15682 12 : func_templ->GetFunction(context.local()).ToLocalChecked())
15683 : .FromJust();
15684 6 : v8::Local<v8::Object> obj_clone = obj->Clone();
15685 18 : obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
15686 12 : CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
15687 6 : }
15688 :
15689 :
15690 504 : static void CheckElementValue(i::Isolate* isolate,
15691 : int expected,
15692 : i::Handle<i::Object> obj,
15693 : int offset) {
15694 : i::Object element =
15695 1008 : *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15696 504 : CHECK_EQ(expected, i::Smi::ToInt(element));
15697 504 : }
15698 :
15699 :
15700 : template <class ExternalArrayClass, class ElementType>
15701 162 : static void ObjectWithExternalArrayTestHelper(Local<Context> context,
15702 : v8::Local<Object> obj,
15703 : int element_count,
15704 : i::ExternalArrayType array_type,
15705 : int64_t low, int64_t high) {
15706 : i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
15707 162 : v8::Isolate* v8_isolate = context->GetIsolate();
15708 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
15709 486 : obj->Set(context, v8_str("field"), v8::Int32::New(v8_isolate, 1503))
15710 324 : .FromJust();
15711 648 : CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
15712 : v8::Local<v8::Value> result = CompileRun("ext_array.field");
15713 324 : CHECK_EQ(1503, result->Int32Value(context).FromJust());
15714 : result = CompileRun("ext_array[1]");
15715 324 : CHECK_EQ(1, result->Int32Value(context).FromJust());
15716 :
15717 : // Check assigned smis
15718 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15719 : " ext_array[i] = i;"
15720 : "}"
15721 : "var sum = 0;"
15722 : "for (var i = 0; i < 8; i++) {"
15723 : " sum += ext_array[i];"
15724 : "}"
15725 : "sum;");
15726 :
15727 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15728 : // Check pass through of assigned smis
15729 : result = CompileRun("var sum = 0;"
15730 : "for (var i = 0; i < 8; i++) {"
15731 : " sum += ext_array[i] = ext_array[i] = -i;"
15732 : "}"
15733 : "sum;");
15734 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
15735 :
15736 :
15737 : // Check assigned smis in reverse order
15738 : result = CompileRun("for (var i = 8; --i >= 0; ) {"
15739 : " ext_array[i] = i;"
15740 : "}"
15741 : "var sum = 0;"
15742 : "for (var i = 0; i < 8; i++) {"
15743 : " sum += ext_array[i];"
15744 : "}"
15745 : "sum;");
15746 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15747 :
15748 : // Check pass through of assigned HeapNumbers
15749 : result = CompileRun("var sum = 0;"
15750 : "for (var i = 0; i < 16; i+=2) {"
15751 : " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15752 : "}"
15753 : "sum;");
15754 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
15755 :
15756 : // Check assigned HeapNumbers
15757 : result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15758 : " ext_array[i] = (i * 0.5);"
15759 : "}"
15760 : "var sum = 0;"
15761 : "for (var i = 0; i < 16; i+=2) {"
15762 : " sum += ext_array[i];"
15763 : "}"
15764 : "sum;");
15765 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15766 :
15767 : // Check assigned HeapNumbers in reverse order
15768 : result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15769 : " ext_array[i] = (i * 0.5);"
15770 : "}"
15771 : "var sum = 0;"
15772 : "for (var i = 0; i < 16; i+=2) {"
15773 : " sum += ext_array[i];"
15774 : "}"
15775 : "sum;");
15776 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15777 :
15778 : i::ScopedVector<char> test_buf(1024);
15779 :
15780 : // Check legal boundary conditions.
15781 : // The repeated loads and stores ensure the ICs are exercised.
15782 : const char* boundary_program =
15783 : "var res = 0;"
15784 : "for (var i = 0; i < 16; i++) {"
15785 : " ext_array[i] = %lld;"
15786 : " if (i > 8) {"
15787 : " res = ext_array[i];"
15788 : " }"
15789 : "}"
15790 : "res;";
15791 162 : i::SNPrintF(test_buf,
15792 : boundary_program,
15793 : low);
15794 : result = CompileRun(test_buf.start());
15795 324 : CHECK_EQ(low, result->IntegerValue(context).FromJust());
15796 :
15797 162 : i::SNPrintF(test_buf,
15798 : boundary_program,
15799 : high);
15800 : result = CompileRun(test_buf.start());
15801 324 : CHECK_EQ(high, result->IntegerValue(context).FromJust());
15802 :
15803 : // Check misprediction of type in IC.
15804 : result = CompileRun("var tmp_array = ext_array;"
15805 : "var sum = 0;"
15806 : "for (var i = 0; i < 8; i++) {"
15807 : " tmp_array[i] = i;"
15808 : " sum += tmp_array[i];"
15809 : " if (i == 4) {"
15810 : " tmp_array = {};"
15811 : " }"
15812 : "}"
15813 : "sum;");
15814 : // Force GC to trigger verification.
15815 162 : CcTest::CollectAllGarbage();
15816 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
15817 :
15818 : // Make sure out-of-range loads do not throw.
15819 162 : i::SNPrintF(test_buf,
15820 : "var caught_exception = false;"
15821 : "try {"
15822 : " ext_array[%d];"
15823 : "} catch (e) {"
15824 : " caught_exception = true;"
15825 : "}"
15826 : "caught_exception;",
15827 : element_count);
15828 : result = CompileRun(test_buf.start());
15829 162 : CHECK(!result->BooleanValue(v8_isolate));
15830 :
15831 : // Make sure out-of-range stores do not throw.
15832 162 : i::SNPrintF(test_buf,
15833 : "var caught_exception = false;"
15834 : "try {"
15835 : " ext_array[%d] = 1;"
15836 : "} catch (e) {"
15837 : " caught_exception = true;"
15838 : "}"
15839 : "caught_exception;",
15840 : element_count);
15841 : result = CompileRun(test_buf.start());
15842 162 : CHECK(!result->BooleanValue(v8_isolate));
15843 :
15844 : // Check other boundary conditions, values and operations.
15845 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15846 : " ext_array[7] = undefined;"
15847 : "}"
15848 : "ext_array[7];");
15849 324 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15850 162 : if (array_type == i::kExternalFloat64Array ||
15851 : array_type == i::kExternalFloat32Array) {
15852 72 : CHECK(std::isnan(
15853 : i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
15854 : } else {
15855 126 : CheckElementValue(isolate, 0, jsobj, 7);
15856 : }
15857 :
15858 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15859 : " ext_array[6] = '2.3';"
15860 : "}"
15861 : "ext_array[6];");
15862 324 : CHECK_EQ(2, result->Int32Value(context).FromJust());
15863 324 : CHECK_EQ(2,
15864 : static_cast<int>(
15865 : i::Object::GetElement(
15866 : isolate, jsobj, 6).ToHandleChecked()->Number()));
15867 :
15868 162 : if (array_type != i::kExternalFloat32Array &&
15869 : array_type != i::kExternalFloat64Array) {
15870 : // Though the specification doesn't state it, be explicit about
15871 : // converting NaNs and +/-Infinity to zero.
15872 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15873 : " ext_array[i] = 5;"
15874 : "}"
15875 : "for (var i = 0; i < 8; i++) {"
15876 : " ext_array[i] = NaN;"
15877 : "}"
15878 : "ext_array[5];");
15879 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15880 126 : CheckElementValue(isolate, 0, jsobj, 5);
15881 :
15882 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15883 : " ext_array[i] = 5;"
15884 : "}"
15885 : "for (var i = 0; i < 8; i++) {"
15886 : " ext_array[i] = Infinity;"
15887 : "}"
15888 : "ext_array[5];");
15889 : int expected_value =
15890 126 : (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
15891 252 : CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
15892 126 : CheckElementValue(isolate, expected_value, jsobj, 5);
15893 :
15894 : result = CompileRun("for (var i = 0; i < 8; i++) {"
15895 : " ext_array[i] = 5;"
15896 : "}"
15897 : "for (var i = 0; i < 8; i++) {"
15898 : " ext_array[i] = -Infinity;"
15899 : "}"
15900 : "ext_array[5];");
15901 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
15902 126 : CheckElementValue(isolate, 0, jsobj, 5);
15903 :
15904 : // Check truncation behavior of integral arrays.
15905 : const char* unsigned_data =
15906 : "var source_data = [0.6, 10.6];"
15907 : "var expected_results = [0, 10];";
15908 : const char* signed_data =
15909 : "var source_data = [0.6, 10.6, -0.6, -10.6];"
15910 : "var expected_results = [0, 10, 0, -10];";
15911 : const char* pixel_data =
15912 : "var source_data = [0.6, 10.6];"
15913 : "var expected_results = [1, 11];";
15914 : bool is_unsigned = (array_type == i::kExternalUint8Array ||
15915 : array_type == i::kExternalUint16Array ||
15916 126 : array_type == i::kExternalUint32Array);
15917 : bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
15918 :
15919 126 : i::SNPrintF(test_buf,
15920 : "%s"
15921 : "var all_passed = true;"
15922 : "for (var i = 0; i < source_data.length; i++) {"
15923 : " for (var j = 0; j < 8; j++) {"
15924 : " ext_array[j] = source_data[i];"
15925 : " }"
15926 : " all_passed = all_passed &&"
15927 : " (ext_array[5] == expected_results[i]);"
15928 : "}"
15929 : "all_passed;",
15930 : (is_unsigned ?
15931 : unsigned_data :
15932 : (is_pixel_data ? pixel_data : signed_data)));
15933 : result = CompileRun(test_buf.start());
15934 126 : CHECK(result->BooleanValue(v8_isolate));
15935 : }
15936 :
15937 : i::Handle<ExternalArrayClass> array(
15938 : ExternalArrayClass::cast(i::Handle<i::JSObject>::cast(jsobj)->elements()),
15939 : isolate);
15940 39042 : for (int i = 0; i < element_count; i++) {
15941 36720 : array->set(i, static_cast<ElementType>(i));
15942 : }
15943 :
15944 162 : bool old_natives_flag_sentry = i::FLAG_allow_natives_syntax;
15945 162 : i::FLAG_allow_natives_syntax = true;
15946 :
15947 : // Test complex assignments
15948 : result = CompileRun(
15949 : "function ee_op_test_complex_func(sum) {"
15950 : " for (var i = 0; i < 40; ++i) {"
15951 : " sum += (ext_array[i] += 1);"
15952 : " sum += (ext_array[i] -= 1);"
15953 : " } "
15954 : " return sum;"
15955 : "}"
15956 : "sum=0;"
15957 : "sum=ee_op_test_complex_func(sum);"
15958 : "sum=ee_op_test_complex_func(sum);"
15959 : "%OptimizeFunctionOnNextCall(ee_op_test_complex_func);"
15960 : "sum=ee_op_test_complex_func(sum);"
15961 : "sum;");
15962 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
15963 :
15964 : // Test count operations
15965 : result = CompileRun(
15966 : "function ee_op_test_count_func(sum) {"
15967 : " for (var i = 0; i < 40; ++i) {"
15968 : " sum += (++ext_array[i]);"
15969 : " sum += (--ext_array[i]);"
15970 : " } "
15971 : " return sum;"
15972 : "}"
15973 : "sum=0;"
15974 : "sum=ee_op_test_count_func(sum);"
15975 : "sum=ee_op_test_count_func(sum);"
15976 : "%OptimizeFunctionOnNextCall(ee_op_test_count_func);"
15977 : "sum=ee_op_test_count_func(sum);"
15978 : "sum;");
15979 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
15980 :
15981 162 : i::FLAG_allow_natives_syntax = old_natives_flag_sentry;
15982 :
15983 : result = CompileRun("ext_array[3] = 33;"
15984 : "delete ext_array[3];"
15985 : "ext_array[3];");
15986 324 : CHECK_EQ(33, result->Int32Value(context).FromJust());
15987 :
15988 : result = CompileRun(
15989 : "ext_array[0] = 10; ext_array[1] = 11;"
15990 : "ext_array[2] = 12; ext_array[3] = 13;"
15991 : "try { ext_array.__defineGetter__('2', function() { return 120; }); }"
15992 : "catch (e) { }"
15993 : "ext_array[2];");
15994 324 : CHECK_EQ(12, result->Int32Value(context).FromJust());
15995 :
15996 : result = CompileRun("var js_array = new Array(40);"
15997 : "js_array[0] = 77;"
15998 : "js_array;");
15999 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16000 : ->Get(context, v8_str("0"))
16001 : .ToLocalChecked()
16002 : ->Int32Value(context)
16003 : .FromJust());
16004 :
16005 : result = CompileRun("ext_array[1] = 23;"
16006 : "ext_array.__proto__ = [];"
16007 : "js_array.__proto__ = ext_array;"
16008 : "js_array.concat(ext_array);");
16009 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16010 : ->Get(context, v8_str("0"))
16011 : .ToLocalChecked()
16012 : ->Int32Value(context)
16013 : .FromJust());
16014 648 : CHECK_EQ(23, v8::Object::Cast(*result)
16015 : ->Get(context, v8_str("1"))
16016 : .ToLocalChecked()
16017 : ->Int32Value(context)
16018 : .FromJust());
16019 :
16020 : result = CompileRun("ext_array[1] = 23;");
16021 324 : CHECK_EQ(23, result->Int32Value(context).FromJust());
16022 162 : }
16023 :
16024 :
16025 : template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16026 : class ElementType>
16027 54 : static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16028 : ElementType low, ElementType high) {
16029 54 : i::FLAG_allow_natives_syntax = true;
16030 54 : LocalContext context;
16031 : i::Isolate* isolate = CcTest::i_isolate();
16032 : i::Factory* factory = isolate->factory();
16033 108 : v8::HandleScope scope(context->GetIsolate());
16034 : const int kElementCount = 260;
16035 : i::Handle<i::JSTypedArray> jsobj =
16036 54 : factory->NewJSTypedArray(elements_kind, kElementCount);
16037 : i::Handle<FixedTypedArrayClass> fixed_array(
16038 : FixedTypedArrayClass::cast(jsobj->elements()), isolate);
16039 54 : CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16040 : fixed_array->map()->instance_type());
16041 54 : CHECK_EQ(kElementCount, fixed_array->length());
16042 54 : CcTest::CollectAllGarbage();
16043 28134 : for (int i = 0; i < kElementCount; i++) {
16044 26520 : fixed_array->set(i, static_cast<ElementType>(i));
16045 : }
16046 : // Force GC to trigger verification.
16047 54 : CcTest::CollectAllGarbage();
16048 28134 : for (int i = 0; i < kElementCount; i++) {
16049 14040 : CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16050 : static_cast<int64_t>(fixed_array->get_scalar(i)));
16051 : }
16052 : v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16053 :
16054 108 : ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16055 : context.local(), obj, kElementCount, array_type,
16056 : static_cast<int64_t>(low),
16057 : static_cast<int64_t>(high));
16058 54 : }
16059 :
16060 :
16061 26645 : THREADED_TEST(FixedUint8Array) {
16062 : FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16063 6 : i::kExternalUint8Array, 0x0, 0xFF);
16064 6 : }
16065 :
16066 :
16067 26645 : THREADED_TEST(FixedUint8ClampedArray) {
16068 : FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16069 : i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16070 6 : i::kExternalUint8ClampedArray, 0x0, 0xFF);
16071 6 : }
16072 :
16073 :
16074 26645 : THREADED_TEST(FixedInt8Array) {
16075 : FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16076 6 : i::kExternalInt8Array, -0x80, 0x7F);
16077 6 : }
16078 :
16079 :
16080 26645 : THREADED_TEST(FixedUint16Array) {
16081 : FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16082 6 : i::kExternalUint16Array, 0x0, 0xFFFF);
16083 6 : }
16084 :
16085 :
16086 26645 : THREADED_TEST(FixedInt16Array) {
16087 : FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16088 6 : i::kExternalInt16Array, -0x8000, 0x7FFF);
16089 6 : }
16090 :
16091 :
16092 26645 : THREADED_TEST(FixedUint32Array) {
16093 : FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16094 6 : i::kExternalUint32Array, 0x0, UINT_MAX);
16095 6 : }
16096 :
16097 :
16098 26645 : THREADED_TEST(FixedInt32Array) {
16099 : FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16100 6 : i::kExternalInt32Array, INT_MIN, INT_MAX);
16101 6 : }
16102 :
16103 :
16104 26645 : THREADED_TEST(FixedFloat32Array) {
16105 : FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16106 6 : i::kExternalFloat32Array, -500, 500);
16107 6 : }
16108 :
16109 :
16110 26645 : THREADED_TEST(FixedFloat64Array) {
16111 : FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16112 6 : i::kExternalFloat64Array, -500, 500);
16113 6 : }
16114 :
16115 :
16116 : template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16117 : class ArrayBufferType>
16118 108 : void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16119 : int64_t high) {
16120 : const int kElementCount = 50;
16121 :
16122 : i::ScopedVector<ElementType> backing_store(kElementCount+2);
16123 :
16124 108 : LocalContext env;
16125 108 : v8::Isolate* isolate = env->GetIsolate();
16126 216 : v8::HandleScope handle_scope(isolate);
16127 :
16128 : Local<ArrayBufferType> ab =
16129 : ArrayBufferType::New(isolate, backing_store.start(),
16130 108 : (kElementCount + 2) * sizeof(ElementType));
16131 : Local<TypedArray> ta =
16132 108 : TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16133 108 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16134 108 : CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16135 108 : CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16136 108 : CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16137 324 : CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16138 :
16139 : ElementType* data = backing_store.start() + 2;
16140 10908 : for (int i = 0; i < kElementCount; i++) {
16141 5400 : data[i] = static_cast<ElementType>(i);
16142 : }
16143 :
16144 108 : ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16145 : env.local(), ta, kElementCount, array_type, low, high);
16146 108 : }
16147 :
16148 :
16149 26645 : THREADED_TEST(Uint8Array) {
16150 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16151 6 : v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16152 6 : }
16153 :
16154 :
16155 26645 : THREADED_TEST(Int8Array) {
16156 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16157 6 : v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16158 6 : }
16159 :
16160 :
16161 26645 : THREADED_TEST(Uint16Array) {
16162 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16163 6 : v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16164 6 : }
16165 :
16166 :
16167 26645 : THREADED_TEST(Int16Array) {
16168 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16169 : v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16170 6 : 0x7FFF);
16171 6 : }
16172 :
16173 :
16174 26645 : THREADED_TEST(Uint32Array) {
16175 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16176 6 : v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16177 6 : }
16178 :
16179 :
16180 26645 : THREADED_TEST(Int32Array) {
16181 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16182 : v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16183 6 : INT_MAX);
16184 6 : }
16185 :
16186 :
16187 26645 : THREADED_TEST(Float32Array) {
16188 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16189 6 : v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16190 6 : }
16191 :
16192 :
16193 26645 : THREADED_TEST(Float64Array) {
16194 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16195 6 : v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16196 6 : }
16197 :
16198 :
16199 26645 : THREADED_TEST(Uint8ClampedArray) {
16200 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16201 : i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16202 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16203 6 : }
16204 :
16205 :
16206 26645 : THREADED_TEST(DataView) {
16207 : const int kSize = 50;
16208 :
16209 : i::ScopedVector<uint8_t> backing_store(kSize+2);
16210 :
16211 6 : LocalContext env;
16212 6 : v8::Isolate* isolate = env->GetIsolate();
16213 12 : v8::HandleScope handle_scope(isolate);
16214 :
16215 : Local<v8::ArrayBuffer> ab =
16216 6 : v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16217 6 : Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16218 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16219 6 : CHECK_EQ(2u, dv->ByteOffset());
16220 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16221 18 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16222 6 : }
16223 :
16224 :
16225 26645 : THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16226 6 : LocalContext env;
16227 6 : v8::Isolate* isolate = env->GetIsolate();
16228 12 : v8::HandleScope handle_scope(isolate);
16229 :
16230 : // Make sure the pointer looks like a heap object
16231 : uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16232 :
16233 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16234 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16235 :
16236 : // Should not crash
16237 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16238 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16239 6 : CcTest::CollectAllGarbage();
16240 6 : CcTest::CollectAllGarbage();
16241 :
16242 : // Should not move the pointer
16243 6 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16244 6 : }
16245 :
16246 :
16247 26645 : THREADED_TEST(SkipArrayBufferDuringScavenge) {
16248 6 : LocalContext env;
16249 6 : v8::Isolate* isolate = env->GetIsolate();
16250 12 : v8::HandleScope handle_scope(isolate);
16251 :
16252 : // Make sure the pointer looks like a heap object
16253 6 : Local<v8::Object> tmp = v8::Object::New(isolate);
16254 : uint8_t* store_ptr =
16255 6 : reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16256 :
16257 : // Make `store_ptr` point to from space
16258 6 : CcTest::CollectGarbage(i::NEW_SPACE);
16259 :
16260 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16261 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16262 :
16263 : // Should not crash,
16264 : // i.e. backing store pointer should not be treated as a heap object pointer
16265 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16266 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16267 :
16268 : // Use `ab` to silence compiler warning
16269 6 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16270 6 : }
16271 :
16272 :
16273 26645 : THREADED_TEST(SharedUint8Array) {
16274 6 : i::FLAG_harmony_sharedarraybuffer = true;
16275 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16276 6 : v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16277 6 : }
16278 :
16279 :
16280 26645 : THREADED_TEST(SharedInt8Array) {
16281 6 : i::FLAG_harmony_sharedarraybuffer = true;
16282 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16283 : v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16284 6 : 0x7F);
16285 6 : }
16286 :
16287 :
16288 26645 : THREADED_TEST(SharedUint16Array) {
16289 6 : i::FLAG_harmony_sharedarraybuffer = true;
16290 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16291 : v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16292 6 : 0xFFFF);
16293 6 : }
16294 :
16295 :
16296 26645 : THREADED_TEST(SharedInt16Array) {
16297 6 : i::FLAG_harmony_sharedarraybuffer = true;
16298 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16299 : v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16300 6 : 0x7FFF);
16301 6 : }
16302 :
16303 :
16304 26645 : THREADED_TEST(SharedUint32Array) {
16305 6 : i::FLAG_harmony_sharedarraybuffer = true;
16306 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16307 : v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16308 6 : UINT_MAX);
16309 6 : }
16310 :
16311 :
16312 26645 : THREADED_TEST(SharedInt32Array) {
16313 6 : i::FLAG_harmony_sharedarraybuffer = true;
16314 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16315 : v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16316 6 : INT_MAX);
16317 6 : }
16318 :
16319 :
16320 26645 : THREADED_TEST(SharedFloat32Array) {
16321 6 : i::FLAG_harmony_sharedarraybuffer = true;
16322 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16323 : v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16324 6 : 500);
16325 6 : }
16326 :
16327 :
16328 26645 : THREADED_TEST(SharedFloat64Array) {
16329 6 : i::FLAG_harmony_sharedarraybuffer = true;
16330 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16331 : v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
16332 6 : 500);
16333 6 : }
16334 :
16335 :
16336 26645 : THREADED_TEST(SharedUint8ClampedArray) {
16337 6 : i::FLAG_harmony_sharedarraybuffer = true;
16338 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16339 : i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
16340 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16341 6 : }
16342 :
16343 :
16344 26645 : THREADED_TEST(SharedDataView) {
16345 6 : i::FLAG_harmony_sharedarraybuffer = true;
16346 : const int kSize = 50;
16347 :
16348 : i::ScopedVector<uint8_t> backing_store(kSize + 2);
16349 :
16350 6 : LocalContext env;
16351 6 : v8::Isolate* isolate = env->GetIsolate();
16352 12 : v8::HandleScope handle_scope(isolate);
16353 :
16354 : Local<v8::SharedArrayBuffer> ab =
16355 6 : v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16356 : Local<v8::DataView> dv =
16357 6 : v8::DataView::New(ab, 2, kSize);
16358 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16359 6 : CHECK_EQ(2u, dv->ByteOffset());
16360 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16361 18 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16362 6 : }
16363 :
16364 : #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16365 : THREADED_TEST(Is##View) { \
16366 : LocalContext env; \
16367 : v8::Isolate* isolate = env->GetIsolate(); \
16368 : v8::HandleScope handle_scope(isolate); \
16369 : \
16370 : Local<Value> result = CompileRun( \
16371 : "var ab = new ArrayBuffer(128);" \
16372 : "new " #View "(ab)"); \
16373 : CHECK(result->IsArrayBufferView()); \
16374 : CHECK(result->Is##View()); \
16375 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16376 : }
16377 :
16378 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16379 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16380 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16381 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16382 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16383 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16384 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16385 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16386 26663 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16387 26663 : IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16388 :
16389 : #undef IS_ARRAY_BUFFER_VIEW_TEST
16390 :
16391 :
16392 :
16393 26645 : THREADED_TEST(ScriptContextDependence) {
16394 6 : LocalContext c1;
16395 12 : v8::HandleScope scope(c1->GetIsolate());
16396 : const char *source = "foo";
16397 : v8::Local<v8::Script> dep = v8_compile(source);
16398 : v8::ScriptCompiler::Source script_source(
16399 6 : v8::String::NewFromUtf8(c1->GetIsolate(), source,
16400 6 : v8::NewStringType::kNormal)
16401 : .ToLocalChecked());
16402 : v8::Local<v8::UnboundScript> indep =
16403 6 : v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
16404 : .ToLocalChecked();
16405 12 : c1->Global()
16406 18 : ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
16407 6 : v8::NewStringType::kNormal)
16408 : .ToLocalChecked(),
16409 12 : v8::Integer::New(c1->GetIsolate(), 100))
16410 : .FromJust();
16411 18 : CHECK_EQ(
16412 : dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
16413 : 100);
16414 24 : CHECK_EQ(indep->BindToCurrentContext()
16415 : ->Run(c1.local())
16416 : .ToLocalChecked()
16417 : ->Int32Value(c1.local())
16418 : .FromJust(),
16419 : 100);
16420 6 : LocalContext c2;
16421 12 : c2->Global()
16422 18 : ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
16423 6 : v8::NewStringType::kNormal)
16424 : .ToLocalChecked(),
16425 12 : v8::Integer::New(c2->GetIsolate(), 101))
16426 : .FromJust();
16427 18 : CHECK_EQ(
16428 : dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
16429 : 100);
16430 24 : CHECK_EQ(indep->BindToCurrentContext()
16431 : ->Run(c2.local())
16432 : .ToLocalChecked()
16433 : ->Int32Value(c2.local())
16434 : .FromJust(),
16435 : 101);
16436 6 : }
16437 :
16438 :
16439 26645 : THREADED_TEST(StackTrace) {
16440 6 : LocalContext context;
16441 12 : v8::HandleScope scope(context->GetIsolate());
16442 12 : v8::TryCatch try_catch(context->GetIsolate());
16443 : const char *source = "function foo() { FAIL.FAIL; }; foo();";
16444 6 : v8::Local<v8::String> src = v8_str(source);
16445 6 : v8::Local<v8::String> origin = v8_str("stack-trace-test");
16446 : v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
16447 24 : CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
16448 : &script_source)
16449 : .ToLocalChecked()
16450 : ->BindToCurrentContext()
16451 : ->Run(context.local())
16452 : .IsEmpty());
16453 6 : CHECK(try_catch.HasCaught());
16454 : v8::String::Utf8Value stack(
16455 : context->GetIsolate(),
16456 18 : try_catch.StackTrace(context.local()).ToLocalChecked());
16457 6 : CHECK_NOT_NULL(strstr(*stack, "at foo (stack-trace-test"));
16458 6 : }
16459 :
16460 :
16461 : // Checks that a StackFrame has certain expected values.
16462 100 : void checkStackFrame(const char* expected_script_name,
16463 : const char* expected_func_name, int expected_line_number,
16464 : int expected_column, bool is_eval, bool is_constructor,
16465 : v8::Local<v8::StackFrame> frame) {
16466 200 : v8::HandleScope scope(CcTest::isolate());
16467 300 : v8::String::Utf8Value func_name(CcTest::isolate(), frame->GetFunctionName());
16468 300 : v8::String::Utf8Value script_name(CcTest::isolate(), frame->GetScriptName());
16469 100 : if (*script_name == nullptr) {
16470 : // The situation where there is no associated script, like for evals.
16471 35 : CHECK_NULL(expected_script_name);
16472 : } else {
16473 65 : CHECK_NOT_NULL(strstr(*script_name, expected_script_name));
16474 : }
16475 100 : CHECK_NOT_NULL(strstr(*func_name, expected_func_name));
16476 100 : CHECK_EQ(expected_line_number, frame->GetLineNumber());
16477 100 : CHECK_EQ(expected_column, frame->GetColumn());
16478 100 : CHECK_EQ(is_eval, frame->IsEval());
16479 100 : CHECK_EQ(is_constructor, frame->IsConstructor());
16480 100 : }
16481 :
16482 :
16483 35 : void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16484 70 : v8::HandleScope scope(args.GetIsolate());
16485 : const char* origin = "capture-stack-trace-test";
16486 : const int kOverviewTest = 1;
16487 : const int kDetailedTest = 2;
16488 : const int kFunctionName = 3;
16489 : const int kDisplayName = 4;
16490 : const int kFunctionNameAndDisplayName = 5;
16491 : const int kDisplayNameIsNotString = 6;
16492 : const int kFunctionNameIsNotString = 7;
16493 :
16494 35 : CHECK_EQ(args.Length(), 1);
16495 :
16496 35 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
16497 : v8::Isolate* isolate = args.GetIsolate();
16498 70 : int testGroup = args[0]->Int32Value(context).FromJust();
16499 35 : if (testGroup == kOverviewTest) {
16500 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16501 5 : args.GetIsolate(), 10, v8::StackTrace::kOverview);
16502 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
16503 5 : checkStackFrame(origin, "bar", 2, 10, false, false,
16504 5 : stackTrace->GetFrame(args.GetIsolate(), 0));
16505 5 : checkStackFrame(origin, "foo", 6, 3, false, true,
16506 5 : stackTrace->GetFrame(isolate, 1));
16507 : // This is the source string inside the eval which has the call to foo.
16508 5 : checkStackFrame(nullptr, "", 1, 1, true, false,
16509 5 : stackTrace->GetFrame(isolate, 2));
16510 : // The last frame is an anonymous function which has the initial eval call.
16511 5 : checkStackFrame(origin, "", 8, 7, false, false,
16512 5 : stackTrace->GetFrame(isolate, 3));
16513 30 : } else if (testGroup == kDetailedTest) {
16514 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16515 5 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
16516 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
16517 5 : checkStackFrame(origin, "bat", 4, 22, false, false,
16518 5 : stackTrace->GetFrame(isolate, 0));
16519 5 : checkStackFrame(origin, "baz", 8, 3, false, true,
16520 5 : stackTrace->GetFrame(isolate, 1));
16521 : bool is_eval = true;
16522 : // This is the source string inside the eval which has the call to baz.
16523 5 : checkStackFrame(nullptr, "", 1, 1, is_eval, false,
16524 5 : stackTrace->GetFrame(isolate, 2));
16525 : // The last frame is an anonymous function which has the initial eval call.
16526 5 : checkStackFrame(origin, "", 10, 1, false, false,
16527 5 : stackTrace->GetFrame(isolate, 3));
16528 25 : } else if (testGroup == kFunctionName) {
16529 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16530 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16531 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16532 5 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16533 5 : stackTrace->GetFrame(isolate, 0));
16534 20 : } else if (testGroup == kDisplayName) {
16535 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16536 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16537 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16538 5 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16539 5 : stackTrace->GetFrame(isolate, 0));
16540 15 : } else if (testGroup == kFunctionNameAndDisplayName) {
16541 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16542 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16543 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16544 5 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16545 5 : stackTrace->GetFrame(isolate, 0));
16546 10 : } else if (testGroup == kDisplayNameIsNotString) {
16547 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16548 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16549 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16550 5 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16551 5 : stackTrace->GetFrame(isolate, 0));
16552 5 : } else if (testGroup == kFunctionNameIsNotString) {
16553 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16554 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
16555 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
16556 5 : checkStackFrame(nullptr, "", 3, 1, true, false,
16557 5 : stackTrace->GetFrame(isolate, 0));
16558 : }
16559 35 : }
16560 :
16561 :
16562 : // Tests the C++ StackTrace API.
16563 : // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16564 : // THREADED_TEST(CaptureStackTrace) {
16565 26644 : TEST(CaptureStackTrace) {
16566 5 : v8::Isolate* isolate = CcTest::isolate();
16567 10 : v8::HandleScope scope(isolate);
16568 5 : v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
16569 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16570 15 : templ->Set(v8_str("AnalyzeStackInNativeCode"),
16571 5 : v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
16572 5 : LocalContext context(nullptr, templ);
16573 :
16574 : // Test getting OVERVIEW information. Should ignore information that is not
16575 : // script name, function name, line number, and column offset.
16576 : const char *overview_source =
16577 : "function bar() {\n"
16578 : " var y; AnalyzeStackInNativeCode(1);\n"
16579 : "}\n"
16580 : "function foo() {\n"
16581 : "\n"
16582 : " bar();\n"
16583 : "}\n"
16584 : "var x;eval('new foo();');";
16585 5 : v8::Local<v8::String> overview_src = v8_str(overview_source);
16586 : v8::ScriptCompiler::Source script_source(overview_src,
16587 : v8::ScriptOrigin(origin));
16588 : v8::Local<Value> overview_result(
16589 5 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
16590 : .ToLocalChecked()
16591 10 : ->BindToCurrentContext()
16592 5 : ->Run(context.local())
16593 : .ToLocalChecked());
16594 5 : CHECK(!overview_result.IsEmpty());
16595 5 : CHECK(overview_result->IsObject());
16596 :
16597 : // Test getting DETAILED information.
16598 : const char *detailed_source =
16599 : "function bat() {AnalyzeStackInNativeCode(2);\n"
16600 : "}\n"
16601 : "\n"
16602 : "function baz() {\n"
16603 : " bat();\n"
16604 : "}\n"
16605 : "eval('new baz();');";
16606 5 : v8::Local<v8::String> detailed_src = v8_str(detailed_source);
16607 : // Make the script using a non-zero line and column offset.
16608 5 : v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
16609 5 : v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
16610 : v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16611 : v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
16612 : v8::Local<v8::UnboundScript> detailed_script(
16613 5 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
16614 : .ToLocalChecked());
16615 10 : v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
16616 5 : ->Run(context.local())
16617 : .ToLocalChecked());
16618 5 : CHECK(!detailed_result.IsEmpty());
16619 5 : CHECK(detailed_result->IsObject());
16620 :
16621 : // Test using function.name and function.displayName in stack trace
16622 : const char* function_name_source =
16623 : "function bar(function_name, display_name, testGroup) {\n"
16624 : " var f = new Function(`AnalyzeStackInNativeCode(${testGroup});`);\n"
16625 : " if (function_name) {\n"
16626 : " Object.defineProperty(f, 'name', { value: function_name });\n"
16627 : " }\n"
16628 : " if (display_name) {\n"
16629 : " f.displayName = display_name;"
16630 : " }\n"
16631 : " f()\n"
16632 : "}\n"
16633 : "bar('function.name', undefined, 3);\n"
16634 : "bar(undefined, 'function.displayName', 4);\n"
16635 : "bar('function.name', 'function.displayName', 5);\n"
16636 : "bar('function.name', 239, 6);\n"
16637 : "bar(239, undefined, 7);\n";
16638 : v8::Local<v8::String> function_name_src =
16639 5 : v8::String::NewFromUtf8(isolate, function_name_source,
16640 : v8::NewStringType::kNormal)
16641 : .ToLocalChecked();
16642 : v8::ScriptCompiler::Source script_source3(function_name_src,
16643 : v8::ScriptOrigin(origin));
16644 : v8::Local<Value> function_name_result(
16645 5 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
16646 : .ToLocalChecked()
16647 10 : ->BindToCurrentContext()
16648 5 : ->Run(context.local())
16649 : .ToLocalChecked());
16650 5 : CHECK(!function_name_result.IsEmpty());
16651 5 : }
16652 :
16653 :
16654 5 : static void StackTraceForUncaughtExceptionListener(
16655 : v8::Local<v8::Message> message, v8::Local<Value>) {
16656 5 : report_count++;
16657 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16658 5 : CHECK_EQ(2, stack_trace->GetFrameCount());
16659 5 : checkStackFrame("origin", "foo", 2, 3, false, false,
16660 5 : stack_trace->GetFrame(message->GetIsolate(), 0));
16661 5 : checkStackFrame("origin", "bar", 5, 3, false, false,
16662 5 : stack_trace->GetFrame(message->GetIsolate(), 1));
16663 5 : }
16664 :
16665 :
16666 26644 : TEST(CaptureStackTraceForUncaughtException) {
16667 5 : report_count = 0;
16668 5 : LocalContext env;
16669 5 : v8::Isolate* isolate = env->GetIsolate();
16670 10 : v8::HandleScope scope(isolate);
16671 5 : isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
16672 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16673 :
16674 : CompileRunWithOrigin(
16675 : "function foo() {\n"
16676 : " throw 1;\n"
16677 : "};\n"
16678 : "function bar() {\n"
16679 : " foo();\n"
16680 : "};",
16681 : "origin");
16682 5 : v8::Local<v8::Object> global = env->Global();
16683 : Local<Value> trouble =
16684 15 : global->Get(env.local(), v8_str("bar")).ToLocalChecked();
16685 5 : CHECK(trouble->IsFunction());
16686 10 : CHECK(Function::Cast(*trouble)
16687 : ->Call(env.local(), global, 0, nullptr)
16688 : .IsEmpty());
16689 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16690 5 : isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16691 5 : CHECK_EQ(1, report_count);
16692 5 : }
16693 :
16694 26644 : TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16695 5 : LocalContext env;
16696 5 : v8::Isolate* isolate = env->GetIsolate();
16697 10 : v8::HandleScope scope(isolate);
16698 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
16699 5 : v8::StackTrace::kDetailed);
16700 :
16701 : CompileRun(
16702 : "var setters = ['column', 'lineNumber', 'scriptName',\n"
16703 : " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16704 : " 'isConstructor'];\n"
16705 : "for (var i = 0; i < setters.length; i++) {\n"
16706 : " var prop = setters[i];\n"
16707 : " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16708 : "}\n");
16709 : CompileRun("throw 'exception';");
16710 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16711 5 : }
16712 :
16713 : static int asm_warning_triggered = 0;
16714 :
16715 5 : static void AsmJsWarningListener(v8::Local<v8::Message> message,
16716 : v8::Local<Value>) {
16717 : DCHECK_EQ(v8::Isolate::kMessageWarning, message->ErrorLevel());
16718 5 : asm_warning_triggered = 1;
16719 5 : }
16720 :
16721 26644 : TEST(AsmJsWarning) {
16722 5 : i::FLAG_validate_asm = true;
16723 5 : if (i::FLAG_suppress_asm_messages) return;
16724 :
16725 5 : LocalContext env;
16726 5 : v8::Isolate* isolate = env->GetIsolate();
16727 10 : v8::HandleScope scope(isolate);
16728 :
16729 5 : asm_warning_triggered = 0;
16730 5 : isolate->AddMessageListenerWithErrorLevel(AsmJsWarningListener,
16731 5 : v8::Isolate::kMessageAll);
16732 : CompileRun(
16733 : "function module() {\n"
16734 : " 'use asm';\n"
16735 : " var x = 'hi';\n"
16736 : " return {};\n"
16737 : "}\n"
16738 : "module();");
16739 : DCHECK_EQ(1, asm_warning_triggered);
16740 5 : isolate->RemoveMessageListeners(AsmJsWarningListener);
16741 : }
16742 :
16743 : static int error_level_message_count = 0;
16744 : static int expected_error_level = 0;
16745 :
16746 20 : static void ErrorLevelListener(v8::Local<v8::Message> message,
16747 : v8::Local<Value>) {
16748 : DCHECK_EQ(expected_error_level, message->ErrorLevel());
16749 20 : ++error_level_message_count;
16750 20 : }
16751 :
16752 26644 : TEST(ErrorLevelWarning) {
16753 5 : LocalContext env;
16754 5 : v8::Isolate* isolate = env->GetIsolate();
16755 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
16756 10 : v8::HandleScope scope(isolate);
16757 :
16758 : const char* source = "fake = 1;";
16759 5 : v8::Local<v8::Script> lscript = CompileWithOrigin(source, "test", false);
16760 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
16761 10 : v8::Utils::OpenHandle(*lscript->GetUnboundScript()));
16762 10 : CHECK(obj->script()->IsScript());
16763 10 : i::Handle<i::Script> script(i::Script::cast(obj->script()), i_isolate);
16764 :
16765 : int levels[] = {
16766 : v8::Isolate::kMessageLog, v8::Isolate::kMessageInfo,
16767 : v8::Isolate::kMessageDebug, v8::Isolate::kMessageWarning,
16768 5 : };
16769 5 : error_level_message_count = 0;
16770 5 : isolate->AddMessageListenerWithErrorLevel(ErrorLevelListener,
16771 5 : v8::Isolate::kMessageAll);
16772 45 : for (size_t i = 0; i < arraysize(levels); i++) {
16773 20 : i::MessageLocation location(script, 0, 0);
16774 : i::Handle<i::String> msg(i_isolate->factory()->InternalizeOneByteString(
16775 20 : i::StaticCharVector("test")));
16776 : i::Handle<i::JSMessageObject> message =
16777 : i::MessageHandler::MakeMessageObject(
16778 : i_isolate, i::MessageTemplate::kAsmJsInvalid, &location, msg,
16779 20 : i::Handle<i::FixedArray>::null());
16780 20 : message->set_error_level(levels[i]);
16781 20 : expected_error_level = levels[i];
16782 20 : i::MessageHandler::ReportMessage(i_isolate, &location, message);
16783 : }
16784 5 : isolate->RemoveMessageListeners(ErrorLevelListener);
16785 : DCHECK_EQ(arraysize(levels), error_level_message_count);
16786 5 : }
16787 :
16788 5 : static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
16789 : v8::Local<Value>) {
16790 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16791 5 : v8::Isolate* isolate = message->GetIsolate();
16792 5 : CHECK_EQ(5, stack_trace->GetFrameCount());
16793 5 : checkStackFrame("origin", "foo:0", 4, 7, false, false,
16794 5 : stack_trace->GetFrame(isolate, 0));
16795 5 : checkStackFrame("origin", "foo:1", 5, 27, false, false,
16796 5 : stack_trace->GetFrame(isolate, 1));
16797 5 : checkStackFrame("origin", "foo", 5, 27, false, false,
16798 5 : stack_trace->GetFrame(isolate, 2));
16799 5 : checkStackFrame("origin", "foo", 5, 27, false, false,
16800 5 : stack_trace->GetFrame(isolate, 3));
16801 5 : checkStackFrame("origin", "", 1, 14, false, false,
16802 5 : stack_trace->GetFrame(isolate, 4));
16803 5 : }
16804 :
16805 :
16806 26644 : TEST(GetStackTraceContainsFunctionsWithFunctionName) {
16807 5 : LocalContext env;
16808 5 : v8::Isolate* isolate = env->GetIsolate();
16809 10 : v8::HandleScope scope(isolate);
16810 :
16811 : CompileRunWithOrigin(
16812 : "function gen(name, counter) {\n"
16813 : " var f = function foo() {\n"
16814 : " if (counter === 0)\n"
16815 : " throw 1;\n"
16816 : " gen(name, counter - 1)();\n"
16817 : " };\n"
16818 : " if (counter == 3) {\n"
16819 : " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
16820 : " } else {\n"
16821 : " Object.defineProperty(f, 'name', {writable:true});\n"
16822 : " if (counter == 2)\n"
16823 : " f.name = 42;\n"
16824 : " else\n"
16825 : " f.name = name + ':' + counter;\n"
16826 : " }\n"
16827 : " return f;\n"
16828 : "};",
16829 : "origin");
16830 :
16831 5 : isolate->AddMessageListener(StackTraceFunctionNameListener);
16832 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16833 : CompileRunWithOrigin("gen('foo', 3)();", "origin");
16834 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16835 5 : isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
16836 5 : }
16837 :
16838 :
16839 5 : static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
16840 : v8::Local<v8::Value> data) {
16841 : // Use the frame where JavaScript is called from.
16842 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16843 5 : CHECK(!stack_trace.IsEmpty());
16844 5 : int frame_count = stack_trace->GetFrameCount();
16845 5 : CHECK_EQ(3, frame_count);
16846 5 : int line_number[] = {1, 2, 5};
16847 35 : for (int i = 0; i < frame_count; i++) {
16848 30 : CHECK_EQ(line_number[i],
16849 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16850 : }
16851 5 : }
16852 :
16853 :
16854 : // Test that we only return the stack trace at the site where the exception
16855 : // is first thrown (not where it is rethrown).
16856 26644 : TEST(RethrowStackTrace) {
16857 5 : LocalContext env;
16858 5 : v8::Isolate* isolate = env->GetIsolate();
16859 10 : v8::HandleScope scope(isolate);
16860 : // We make sure that
16861 : // - the stack trace of the ReferenceError in g() is reported.
16862 : // - the stack trace is not overwritten when e1 is rethrown by t().
16863 : // - the stack trace of e2 does not overwrite that of e1.
16864 : const char* source =
16865 : "function g() { error; } \n"
16866 : "function f() { g(); } \n"
16867 : "function t(e) { throw e; } \n"
16868 : "try { \n"
16869 : " f(); \n"
16870 : "} catch (e1) { \n"
16871 : " try { \n"
16872 : " error; \n"
16873 : " } catch (e2) { \n"
16874 : " t(e1); \n"
16875 : " } \n"
16876 : "} \n";
16877 5 : isolate->AddMessageListener(RethrowStackTraceHandler);
16878 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16879 : CompileRun(source);
16880 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16881 5 : isolate->RemoveMessageListeners(RethrowStackTraceHandler);
16882 5 : }
16883 :
16884 :
16885 5 : static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
16886 : v8::Local<v8::Value> data) {
16887 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16888 5 : CHECK(!stack_trace.IsEmpty());
16889 5 : int frame_count = stack_trace->GetFrameCount();
16890 5 : CHECK_EQ(2, frame_count);
16891 5 : int line_number[] = {3, 7};
16892 25 : for (int i = 0; i < frame_count; i++) {
16893 20 : CHECK_EQ(line_number[i],
16894 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16895 : }
16896 5 : }
16897 :
16898 :
16899 : // Test that we do not recognize identity for primitive exceptions.
16900 26644 : TEST(RethrowPrimitiveStackTrace) {
16901 5 : LocalContext env;
16902 5 : v8::Isolate* isolate = env->GetIsolate();
16903 10 : v8::HandleScope scope(isolate);
16904 : // We do not capture stack trace for non Error objects on creation time.
16905 : // Instead, we capture the stack trace on last throw.
16906 : const char* source =
16907 : "function g() { throw 404; } \n"
16908 : "function f() { g(); } \n"
16909 : "function t(e) { throw e; } \n"
16910 : "try { \n"
16911 : " f(); \n"
16912 : "} catch (e1) { \n"
16913 : " t(e1) \n"
16914 : "} \n";
16915 5 : isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
16916 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16917 : CompileRun(source);
16918 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16919 5 : isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16920 5 : }
16921 :
16922 :
16923 5 : static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
16924 : v8::Local<v8::Value> data) {
16925 : // Use the frame where JavaScript is called from.
16926 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16927 5 : CHECK(!stack_trace.IsEmpty());
16928 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
16929 10 : CHECK_EQ(1, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
16930 5 : }
16931 :
16932 :
16933 : // Test that the stack trace is captured when the error object is created and
16934 : // not where it is thrown.
16935 26644 : TEST(RethrowExistingStackTrace) {
16936 5 : LocalContext env;
16937 5 : v8::Isolate* isolate = env->GetIsolate();
16938 10 : v8::HandleScope scope(isolate);
16939 : const char* source =
16940 : "var e = new Error(); \n"
16941 : "throw e; \n";
16942 5 : isolate->AddMessageListener(RethrowExistingStackTraceHandler);
16943 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16944 : CompileRun(source);
16945 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16946 5 : isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
16947 5 : }
16948 :
16949 :
16950 5 : static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
16951 : v8::Local<v8::Value> data) {
16952 : // Use the frame where JavaScript is called from.
16953 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16954 5 : CHECK(!stack_trace.IsEmpty());
16955 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
16956 10 : CHECK_EQ(2, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
16957 5 : }
16958 :
16959 :
16960 : // Test that the stack trace is captured where the bogus Error object is thrown.
16961 26644 : TEST(RethrowBogusErrorStackTrace) {
16962 5 : LocalContext env;
16963 5 : v8::Isolate* isolate = env->GetIsolate();
16964 10 : v8::HandleScope scope(isolate);
16965 : const char* source =
16966 : "var e = {__proto__: new Error()} \n"
16967 : "throw e; \n";
16968 5 : isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
16969 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16970 : CompileRun(source);
16971 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16972 5 : isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16973 5 : }
16974 :
16975 :
16976 : v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
16977 : int promise_reject_counter = 0;
16978 : int promise_revoke_counter = 0;
16979 : int promise_reject_after_resolved_counter = 0;
16980 : int promise_resolve_after_resolved_counter = 0;
16981 : int promise_reject_msg_line_number = -1;
16982 : int promise_reject_msg_column_number = -1;
16983 : int promise_reject_line_number = -1;
16984 : int promise_reject_column_number = -1;
16985 : int promise_reject_frame_count = -1;
16986 : bool promise_reject_is_shared_cross_origin = false;
16987 :
16988 140 : void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
16989 140 : v8::Local<v8::Object> global = CcTest::global();
16990 140 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
16991 140 : CHECK_NE(v8::Promise::PromiseState::kPending,
16992 : reject_message.GetPromise()->State());
16993 140 : switch (reject_message.GetEvent()) {
16994 : case v8::kPromiseRejectWithNoHandler: {
16995 95 : promise_reject_counter++;
16996 285 : global->Set(context, v8_str("rejected"), reject_message.GetPromise())
16997 : .FromJust();
16998 285 : global->Set(context, v8_str("value"), reject_message.GetValue())
16999 : .FromJust();
17000 : v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17001 95 : CcTest::isolate(), reject_message.GetValue());
17002 95 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17003 :
17004 : promise_reject_msg_line_number =
17005 190 : message->GetLineNumber(context).FromJust();
17006 : promise_reject_msg_column_number =
17007 190 : message->GetStartColumn(context).FromJust() + 1;
17008 : promise_reject_is_shared_cross_origin =
17009 95 : message->IsSharedCrossOrigin();
17010 :
17011 95 : if (!stack_trace.IsEmpty()) {
17012 35 : promise_reject_frame_count = stack_trace->GetFrameCount();
17013 35 : if (promise_reject_frame_count > 0) {
17014 150 : CHECK(stack_trace->GetFrame(CcTest::isolate(), 0)
17015 : ->GetScriptName()
17016 : ->Equals(context, v8_str("pro"))
17017 : .FromJust());
17018 : promise_reject_line_number =
17019 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetLineNumber();
17020 : promise_reject_column_number =
17021 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetColumn();
17022 : } else {
17023 5 : promise_reject_line_number = -1;
17024 5 : promise_reject_column_number = -1;
17025 : }
17026 : }
17027 : break;
17028 : }
17029 : case v8::kPromiseHandlerAddedAfterReject: {
17030 30 : promise_revoke_counter++;
17031 90 : global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17032 : .FromJust();
17033 30 : CHECK(reject_message.GetValue().IsEmpty());
17034 : break;
17035 : }
17036 : case v8::kPromiseRejectAfterResolved: {
17037 10 : promise_reject_after_resolved_counter++;
17038 10 : break;
17039 : }
17040 : case v8::kPromiseResolveAfterResolved: {
17041 5 : promise_resolve_after_resolved_counter++;
17042 5 : break;
17043 : }
17044 : }
17045 140 : }
17046 :
17047 :
17048 600 : v8::Local<v8::Promise> GetPromise(const char* name) {
17049 : return v8::Local<v8::Promise>::Cast(
17050 1200 : CcTest::global()
17051 2400 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17052 600 : .ToLocalChecked());
17053 : }
17054 :
17055 :
17056 35 : v8::Local<v8::Value> RejectValue() {
17057 70 : return CcTest::global()
17058 140 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17059 35 : .ToLocalChecked();
17060 : }
17061 :
17062 :
17063 70 : void ResetPromiseStates() {
17064 70 : promise_reject_counter = 0;
17065 70 : promise_revoke_counter = 0;
17066 70 : promise_reject_after_resolved_counter = 0;
17067 70 : promise_resolve_after_resolved_counter = 0;
17068 70 : promise_reject_msg_line_number = -1;
17069 70 : promise_reject_msg_column_number = -1;
17070 70 : promise_reject_line_number = -1;
17071 70 : promise_reject_column_number = -1;
17072 70 : promise_reject_frame_count = -1;
17073 :
17074 70 : v8::Local<v8::Object> global = CcTest::global();
17075 70 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17076 280 : global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17077 280 : global->Set(context, v8_str("value"), v8_str("")).FromJust();
17078 280 : global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17079 70 : }
17080 :
17081 :
17082 26644 : TEST(PromiseRejectCallback) {
17083 5 : LocalContext env;
17084 5 : v8::Isolate* isolate = env->GetIsolate();
17085 10 : v8::HandleScope scope(isolate);
17086 :
17087 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17088 :
17089 5 : ResetPromiseStates();
17090 :
17091 : // Create promise p0.
17092 : CompileRun(
17093 : "var reject; \n"
17094 : "var p0 = new Promise( \n"
17095 : " function(res, rej) { \n"
17096 : " reject = rej; \n"
17097 : " } \n"
17098 : "); \n");
17099 10 : CHECK(!GetPromise("p0")->HasHandler());
17100 5 : CHECK_EQ(0, promise_reject_counter);
17101 5 : CHECK_EQ(0, promise_revoke_counter);
17102 :
17103 : // Add resolve handler (and default reject handler) to p0.
17104 : CompileRun("var p1 = p0.then(function(){});");
17105 10 : CHECK(GetPromise("p0")->HasHandler());
17106 10 : CHECK(!GetPromise("p1")->HasHandler());
17107 5 : CHECK_EQ(0, promise_reject_counter);
17108 5 : CHECK_EQ(0, promise_revoke_counter);
17109 :
17110 : // Reject p0.
17111 : CompileRun("reject('ppp');");
17112 10 : CHECK(GetPromise("p0")->HasHandler());
17113 10 : CHECK(!GetPromise("p1")->HasHandler());
17114 5 : CHECK_EQ(1, promise_reject_counter);
17115 5 : CHECK_EQ(0, promise_revoke_counter);
17116 5 : CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17117 20 : CHECK(
17118 : GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17119 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17120 :
17121 : // Reject p0 again. Callback is not triggered again.
17122 : CompileRun("reject();");
17123 10 : CHECK(GetPromise("p0")->HasHandler());
17124 10 : CHECK(!GetPromise("p1")->HasHandler());
17125 5 : CHECK_EQ(1, promise_reject_counter);
17126 5 : CHECK_EQ(0, promise_revoke_counter);
17127 :
17128 : // Add resolve handler to p1.
17129 : CompileRun("var p2 = p1.then(function(){});");
17130 10 : CHECK(GetPromise("p0")->HasHandler());
17131 10 : CHECK(GetPromise("p1")->HasHandler());
17132 10 : CHECK(!GetPromise("p2")->HasHandler());
17133 5 : CHECK_EQ(2, promise_reject_counter);
17134 5 : CHECK_EQ(1, promise_revoke_counter);
17135 20 : CHECK(
17136 : GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17137 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17138 20 : CHECK(
17139 : GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17140 :
17141 5 : ResetPromiseStates();
17142 :
17143 : // Create promise q0.
17144 : CompileRun(
17145 : "var q0 = new Promise( \n"
17146 : " function(res, rej) { \n"
17147 : " reject = rej; \n"
17148 : " } \n"
17149 : "); \n");
17150 10 : CHECK(!GetPromise("q0")->HasHandler());
17151 5 : CHECK_EQ(0, promise_reject_counter);
17152 5 : CHECK_EQ(0, promise_revoke_counter);
17153 :
17154 : // Add reject handler to q0.
17155 : CompileRun("var q1 = q0.catch(function() {});");
17156 10 : CHECK(GetPromise("q0")->HasHandler());
17157 10 : CHECK(!GetPromise("q1")->HasHandler());
17158 5 : CHECK_EQ(0, promise_reject_counter);
17159 5 : CHECK_EQ(0, promise_revoke_counter);
17160 :
17161 : // Reject q0.
17162 : CompileRun("reject('qq')");
17163 10 : CHECK(GetPromise("q0")->HasHandler());
17164 10 : CHECK(!GetPromise("q1")->HasHandler());
17165 5 : CHECK_EQ(0, promise_reject_counter);
17166 5 : CHECK_EQ(0, promise_revoke_counter);
17167 :
17168 : // Add a new reject handler, which rejects by returning Promise.reject().
17169 : // The returned promise q_ triggers a reject callback at first, only to
17170 : // revoke it when returning it causes q2 to be rejected.
17171 : CompileRun(
17172 : "var q_;"
17173 : "var q2 = q0.catch( \n"
17174 : " function() { \n"
17175 : " q_ = Promise.reject('qqq'); \n"
17176 : " return q_; \n"
17177 : " } \n"
17178 : "); \n");
17179 10 : CHECK(GetPromise("q0")->HasHandler());
17180 10 : CHECK(!GetPromise("q1")->HasHandler());
17181 10 : CHECK(!GetPromise("q2")->HasHandler());
17182 10 : CHECK(GetPromise("q_")->HasHandler());
17183 5 : CHECK_EQ(2, promise_reject_counter);
17184 5 : CHECK_EQ(1, promise_revoke_counter);
17185 20 : CHECK(
17186 : GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17187 20 : CHECK(
17188 : GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17189 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17190 :
17191 : // Add a reject handler to the resolved q1, which rejects by throwing.
17192 : CompileRun(
17193 : "var q3 = q1.then( \n"
17194 : " function() { \n"
17195 : " throw 'qqqq'; \n"
17196 : " } \n"
17197 : "); \n");
17198 10 : CHECK(GetPromise("q0")->HasHandler());
17199 10 : CHECK(GetPromise("q1")->HasHandler());
17200 10 : CHECK(!GetPromise("q2")->HasHandler());
17201 10 : CHECK(!GetPromise("q3")->HasHandler());
17202 5 : CHECK_EQ(3, promise_reject_counter);
17203 5 : CHECK_EQ(1, promise_revoke_counter);
17204 20 : CHECK(
17205 : GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17206 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17207 :
17208 5 : ResetPromiseStates();
17209 :
17210 : // Create promise r0, which has three handlers, two of which handle rejects.
17211 : CompileRun(
17212 : "var r0 = new Promise( \n"
17213 : " function(res, rej) { \n"
17214 : " reject = rej; \n"
17215 : " } \n"
17216 : "); \n"
17217 : "var r1 = r0.catch(function() {}); \n"
17218 : "var r2 = r0.then(function() {}); \n"
17219 : "var r3 = r0.then(function() {}, \n"
17220 : " function() {}); \n");
17221 10 : CHECK(GetPromise("r0")->HasHandler());
17222 10 : CHECK(!GetPromise("r1")->HasHandler());
17223 10 : CHECK(!GetPromise("r2")->HasHandler());
17224 10 : CHECK(!GetPromise("r3")->HasHandler());
17225 5 : CHECK_EQ(0, promise_reject_counter);
17226 5 : CHECK_EQ(0, promise_revoke_counter);
17227 :
17228 : // Reject r0.
17229 : CompileRun("reject('rrr')");
17230 10 : CHECK(GetPromise("r0")->HasHandler());
17231 10 : CHECK(!GetPromise("r1")->HasHandler());
17232 10 : CHECK(!GetPromise("r2")->HasHandler());
17233 10 : CHECK(!GetPromise("r3")->HasHandler());
17234 5 : CHECK_EQ(1, promise_reject_counter);
17235 5 : CHECK_EQ(0, promise_revoke_counter);
17236 20 : CHECK(
17237 : GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17238 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17239 :
17240 : // Add reject handler to r2.
17241 : CompileRun("var r4 = r2.catch(function() {});");
17242 10 : CHECK(GetPromise("r0")->HasHandler());
17243 10 : CHECK(!GetPromise("r1")->HasHandler());
17244 10 : CHECK(GetPromise("r2")->HasHandler());
17245 10 : CHECK(!GetPromise("r3")->HasHandler());
17246 10 : CHECK(!GetPromise("r4")->HasHandler());
17247 5 : CHECK_EQ(1, promise_reject_counter);
17248 5 : CHECK_EQ(1, promise_revoke_counter);
17249 20 : CHECK(
17250 : GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17251 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17252 :
17253 : // Add reject handlers to r4.
17254 : CompileRun("var r5 = r4.then(function() {}, function() {});");
17255 10 : CHECK(GetPromise("r0")->HasHandler());
17256 10 : CHECK(!GetPromise("r1")->HasHandler());
17257 10 : CHECK(GetPromise("r2")->HasHandler());
17258 10 : CHECK(!GetPromise("r3")->HasHandler());
17259 10 : CHECK(GetPromise("r4")->HasHandler());
17260 10 : CHECK(!GetPromise("r5")->HasHandler());
17261 5 : CHECK_EQ(1, promise_reject_counter);
17262 5 : CHECK_EQ(1, promise_revoke_counter);
17263 :
17264 5 : ResetPromiseStates();
17265 :
17266 : // Create promise s0, which has three handlers, none of which handle rejects.
17267 : CompileRun(
17268 : "var s0 = new Promise( \n"
17269 : " function(res, rej) { \n"
17270 : " reject = rej; \n"
17271 : " } \n"
17272 : "); \n"
17273 : "var s1 = s0.then(function() {}); \n"
17274 : "var s2 = s0.then(function() {}); \n"
17275 : "var s3 = s0.then(function() {}); \n");
17276 10 : CHECK(GetPromise("s0")->HasHandler());
17277 10 : CHECK(!GetPromise("s1")->HasHandler());
17278 10 : CHECK(!GetPromise("s2")->HasHandler());
17279 10 : CHECK(!GetPromise("s3")->HasHandler());
17280 5 : CHECK_EQ(0, promise_reject_counter);
17281 5 : CHECK_EQ(0, promise_revoke_counter);
17282 :
17283 : // Reject s0.
17284 : CompileRun("reject('sss')");
17285 10 : CHECK(GetPromise("s0")->HasHandler());
17286 10 : CHECK(!GetPromise("s1")->HasHandler());
17287 10 : CHECK(!GetPromise("s2")->HasHandler());
17288 10 : CHECK(!GetPromise("s3")->HasHandler());
17289 5 : CHECK_EQ(3, promise_reject_counter);
17290 5 : CHECK_EQ(0, promise_revoke_counter);
17291 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17292 :
17293 5 : ResetPromiseStates();
17294 :
17295 : // Swallowed exceptions in the Promise constructor.
17296 : CompileRun(
17297 : "var v0 = new Promise(\n"
17298 : " function(res, rej) {\n"
17299 : " res(1);\n"
17300 : " throw new Error();\n"
17301 : " }\n"
17302 : ");\n");
17303 10 : CHECK(!GetPromise("v0")->HasHandler());
17304 5 : CHECK_EQ(0, promise_reject_counter);
17305 5 : CHECK_EQ(0, promise_revoke_counter);
17306 5 : CHECK_EQ(1, promise_reject_after_resolved_counter);
17307 5 : CHECK_EQ(0, promise_resolve_after_resolved_counter);
17308 :
17309 5 : ResetPromiseStates();
17310 :
17311 : // Duplication resolve.
17312 : CompileRun(
17313 : "var r;\n"
17314 : "var y0 = new Promise(\n"
17315 : " function(res, rej) {\n"
17316 : " r = res;\n"
17317 : " throw new Error();\n"
17318 : " }\n"
17319 : ");\n"
17320 : "r(1);\n");
17321 10 : CHECK(!GetPromise("y0")->HasHandler());
17322 5 : CHECK_EQ(1, promise_reject_counter);
17323 5 : CHECK_EQ(0, promise_revoke_counter);
17324 5 : CHECK_EQ(0, promise_reject_after_resolved_counter);
17325 5 : CHECK_EQ(1, promise_resolve_after_resolved_counter);
17326 :
17327 : // Test stack frames.
17328 5 : env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
17329 :
17330 5 : ResetPromiseStates();
17331 :
17332 : // Create promise t0, which is rejected in the constructor with an error.
17333 : CompileRunWithOrigin(
17334 : "var t0 = new Promise( \n"
17335 : " function(res, rej) { \n"
17336 : " reference_error; \n"
17337 : " } \n"
17338 : "); \n",
17339 5 : "pro", 0, 0);
17340 10 : CHECK(!GetPromise("t0")->HasHandler());
17341 5 : CHECK_EQ(1, promise_reject_counter);
17342 5 : CHECK_EQ(0, promise_revoke_counter);
17343 5 : CHECK_EQ(2, promise_reject_frame_count);
17344 5 : CHECK_EQ(3, promise_reject_line_number);
17345 5 : CHECK_EQ(5, promise_reject_column_number);
17346 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17347 5 : CHECK_EQ(5, promise_reject_msg_column_number);
17348 :
17349 5 : ResetPromiseStates();
17350 :
17351 : // Create promise u0 and chain u1 to it, which is rejected via throw.
17352 : CompileRunWithOrigin(
17353 : "var u0 = Promise.resolve(); \n"
17354 : "var u1 = u0.then( \n"
17355 : " function() { \n"
17356 : " (function() { \n"
17357 : " throw new Error(); \n"
17358 : " })(); \n"
17359 : " } \n"
17360 : " ); \n",
17361 5 : "pro", 0, 0);
17362 10 : CHECK(GetPromise("u0")->HasHandler());
17363 10 : CHECK(!GetPromise("u1")->HasHandler());
17364 5 : CHECK_EQ(1, promise_reject_counter);
17365 5 : CHECK_EQ(0, promise_revoke_counter);
17366 5 : CHECK_EQ(2, promise_reject_frame_count);
17367 5 : CHECK_EQ(5, promise_reject_line_number);
17368 5 : CHECK_EQ(23, promise_reject_column_number);
17369 5 : CHECK_EQ(5, promise_reject_msg_line_number);
17370 5 : CHECK_EQ(23, promise_reject_msg_column_number);
17371 :
17372 : // Throw in u3, which handles u1's rejection.
17373 : CompileRunWithOrigin(
17374 : "function f() { \n"
17375 : " return (function() { \n"
17376 : " return new Error(); \n"
17377 : " })(); \n"
17378 : "} \n"
17379 : "var u2 = Promise.reject(f()); \n"
17380 : "var u3 = u1.catch( \n"
17381 : " function() { \n"
17382 : " return u2; \n"
17383 : " } \n"
17384 : " ); \n",
17385 5 : "pro", 0, 0);
17386 10 : CHECK(GetPromise("u0")->HasHandler());
17387 10 : CHECK(GetPromise("u1")->HasHandler());
17388 10 : CHECK(GetPromise("u2")->HasHandler());
17389 10 : CHECK(!GetPromise("u3")->HasHandler());
17390 5 : CHECK_EQ(3, promise_reject_counter);
17391 5 : CHECK_EQ(2, promise_revoke_counter);
17392 5 : CHECK_EQ(3, promise_reject_frame_count);
17393 5 : CHECK_EQ(3, promise_reject_line_number);
17394 5 : CHECK_EQ(12, promise_reject_column_number);
17395 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17396 5 : CHECK_EQ(12, promise_reject_msg_column_number);
17397 :
17398 5 : ResetPromiseStates();
17399 :
17400 : // Create promise rejected promise v0, which is incorrectly handled by v1
17401 : // via chaining cycle.
17402 : CompileRunWithOrigin(
17403 : "var v0 = Promise.reject(); \n"
17404 : "var v1 = v0.catch( \n"
17405 : " function() { \n"
17406 : " return v1; \n"
17407 : " } \n"
17408 : " ); \n",
17409 5 : "pro", 0, 0);
17410 10 : CHECK(GetPromise("v0")->HasHandler());
17411 10 : CHECK(!GetPromise("v1")->HasHandler());
17412 5 : CHECK_EQ(2, promise_reject_counter);
17413 5 : CHECK_EQ(1, promise_revoke_counter);
17414 5 : CHECK_EQ(0, promise_reject_frame_count);
17415 5 : CHECK_EQ(-1, promise_reject_line_number);
17416 5 : CHECK_EQ(-1, promise_reject_column_number);
17417 :
17418 5 : ResetPromiseStates();
17419 :
17420 : // Create promise t1, which rejects by throwing syntax error from eval.
17421 : CompileRunWithOrigin(
17422 : "var t1 = new Promise( \n"
17423 : " function(res, rej) { \n"
17424 : " var content = '\\n\\\n"
17425 : " }'; \n"
17426 : " eval(content); \n"
17427 : " } \n"
17428 : "); \n",
17429 5 : "pro", 0, 0);
17430 10 : CHECK(!GetPromise("t1")->HasHandler());
17431 5 : CHECK_EQ(1, promise_reject_counter);
17432 5 : CHECK_EQ(0, promise_revoke_counter);
17433 5 : CHECK_EQ(2, promise_reject_frame_count);
17434 5 : CHECK_EQ(5, promise_reject_line_number);
17435 5 : CHECK_EQ(10, promise_reject_column_number);
17436 5 : CHECK_EQ(2, promise_reject_msg_line_number);
17437 5 : CHECK_EQ(7, promise_reject_msg_column_number);
17438 5 : }
17439 :
17440 26644 : TEST(PromiseRejectIsSharedCrossOrigin) {
17441 5 : LocalContext env;
17442 5 : v8::Isolate* isolate = env->GetIsolate();
17443 10 : v8::HandleScope scope(isolate);
17444 :
17445 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17446 :
17447 5 : ResetPromiseStates();
17448 :
17449 : // Create promise p0.
17450 : CompileRun(
17451 : "var reject; \n"
17452 : "var p0 = new Promise( \n"
17453 : " function(res, rej) { \n"
17454 : " reject = rej; \n"
17455 : " } \n"
17456 : "); \n");
17457 10 : CHECK(!GetPromise("p0")->HasHandler());
17458 5 : CHECK_EQ(0, promise_reject_counter);
17459 5 : CHECK_EQ(0, promise_revoke_counter);
17460 : // Not set because it's not yet rejected.
17461 5 : CHECK(!promise_reject_is_shared_cross_origin);
17462 :
17463 : // Reject p0.
17464 : CompileRun("reject('ppp');");
17465 5 : CHECK_EQ(1, promise_reject_counter);
17466 5 : CHECK_EQ(0, promise_revoke_counter);
17467 : // Not set because the ScriptOriginOptions is from the script.
17468 5 : CHECK(!promise_reject_is_shared_cross_origin);
17469 :
17470 5 : ResetPromiseStates();
17471 :
17472 : // Create promise p1
17473 : CompileRun(
17474 : "var reject; \n"
17475 : "var p1 = new Promise( \n"
17476 : " function(res, rej) { \n"
17477 : " reject = rej; \n"
17478 : " } \n"
17479 : "); \n");
17480 10 : CHECK(!GetPromise("p1")->HasHandler());
17481 5 : CHECK_EQ(0, promise_reject_counter);
17482 5 : CHECK_EQ(0, promise_revoke_counter);
17483 : // Not set because it's not yet rejected.
17484 5 : CHECK(!promise_reject_is_shared_cross_origin);
17485 :
17486 : // Add resolve handler (and default reject handler) to p1.
17487 : CompileRun("var p2 = p1.then(function(){});");
17488 10 : CHECK(GetPromise("p1")->HasHandler());
17489 10 : CHECK(!GetPromise("p2")->HasHandler());
17490 5 : CHECK_EQ(0, promise_reject_counter);
17491 5 : CHECK_EQ(0, promise_revoke_counter);
17492 :
17493 : // Reject p1.
17494 : CompileRun("reject('ppp');");
17495 5 : CHECK_EQ(1, promise_reject_counter);
17496 5 : CHECK_EQ(0, promise_revoke_counter);
17497 : // Set because the event is from an empty script.
17498 5 : CHECK(promise_reject_is_shared_cross_origin);
17499 5 : }
17500 :
17501 26644 : TEST(PromiseRejectMarkAsHandled) {
17502 5 : LocalContext env;
17503 5 : v8::Isolate* isolate = env->GetIsolate();
17504 10 : v8::HandleScope scope(isolate);
17505 :
17506 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17507 :
17508 5 : ResetPromiseStates();
17509 :
17510 : // Create promise p0.
17511 : CompileRun(
17512 : "var reject; \n"
17513 : "var p0 = new Promise( \n"
17514 : " function(res, rej) { \n"
17515 : " reject = rej; \n"
17516 : " } \n"
17517 : "); \n");
17518 10 : CHECK(!GetPromise("p0")->HasHandler());
17519 5 : CHECK_EQ(0, promise_reject_counter);
17520 5 : CHECK_EQ(0, promise_revoke_counter);
17521 10 : GetPromise("p0")->MarkAsHandled();
17522 :
17523 : // Reject p0. promise_reject_counter shouldn't be incremented because
17524 : // it's marked as handled.
17525 : CompileRun("reject('ppp');");
17526 5 : CHECK_EQ(0, promise_reject_counter);
17527 5 : CHECK_EQ(0, promise_revoke_counter);
17528 5 : }
17529 30 : void PromiseRejectCallbackConstructError(
17530 : v8::PromiseRejectMessage reject_message) {
17531 30 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17532 30 : CHECK_EQ(v8::Promise::PromiseState::kRejected,
17533 : reject_message.GetPromise()->State());
17534 60 : USE(v8::Script::Compile(context, v8_str("new Error('test')"))
17535 : .ToLocalChecked()
17536 : ->Run(context));
17537 30 : }
17538 :
17539 26644 : TEST(PromiseRejectCallbackConstructError) {
17540 5 : i::FLAG_allow_natives_syntax = true;
17541 5 : LocalContext env;
17542 5 : v8::Isolate* isolate = env->GetIsolate();
17543 10 : v8::HandleScope scope(isolate);
17544 :
17545 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallbackConstructError);
17546 :
17547 5 : ResetPromiseStates();
17548 : CompileRun(
17549 : "function f(p) {"
17550 : " p.catch(() => {});"
17551 : "}"
17552 : "f(Promise.reject());"
17553 : "f(Promise.reject());"
17554 : "%OptimizeFunctionOnNextCall(f);"
17555 : "let p = Promise.reject();"
17556 : "f(p);");
17557 5 : }
17558 :
17559 10 : void AnalyzeStackOfEvalWithSourceURL(
17560 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17561 20 : v8::HandleScope scope(args.GetIsolate());
17562 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17563 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17564 10 : CHECK_EQ(5, stackTrace->GetFrameCount());
17565 10 : v8::Local<v8::String> url = v8_str("eval_url");
17566 70 : for (int i = 0; i < 3; i++) {
17567 : v8::Local<v8::String> name =
17568 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17569 30 : CHECK(!name.IsEmpty());
17570 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17571 : }
17572 10 : }
17573 :
17574 :
17575 26644 : TEST(SourceURLInStackTrace) {
17576 5 : v8::Isolate* isolate = CcTest::isolate();
17577 10 : v8::HandleScope scope(isolate);
17578 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17579 15 : templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17580 : v8::FunctionTemplate::New(isolate,
17581 5 : AnalyzeStackOfEvalWithSourceURL));
17582 5 : LocalContext context(nullptr, templ);
17583 :
17584 : const char *source =
17585 : "function outer() {\n"
17586 : "function bar() {\n"
17587 : " AnalyzeStackOfEvalWithSourceURL();\n"
17588 : "}\n"
17589 : "function foo() {\n"
17590 : "\n"
17591 : " bar();\n"
17592 : "}\n"
17593 : "foo();\n"
17594 : "}\n"
17595 : "eval('(' + outer +')()%s');";
17596 :
17597 : i::ScopedVector<char> code(1024);
17598 5 : i::SNPrintF(code, source, "//# sourceURL=eval_url");
17599 5 : CHECK(CompileRun(code.start())->IsUndefined());
17600 5 : i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17601 5 : CHECK(CompileRun(code.start())->IsUndefined());
17602 5 : }
17603 :
17604 :
17605 : static int scriptIdInStack[2];
17606 :
17607 5 : void AnalyzeScriptIdInStack(
17608 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17609 10 : v8::HandleScope scope(args.GetIsolate());
17610 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17611 5 : args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17612 5 : CHECK_EQ(2, stackTrace->GetFrameCount());
17613 25 : for (int i = 0; i < 2; i++) {
17614 : scriptIdInStack[i] =
17615 30 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptId();
17616 : }
17617 5 : }
17618 :
17619 :
17620 26644 : TEST(ScriptIdInStackTrace) {
17621 5 : v8::Isolate* isolate = CcTest::isolate();
17622 10 : v8::HandleScope scope(isolate);
17623 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17624 15 : templ->Set(v8_str("AnalyzeScriptIdInStack"),
17625 5 : v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17626 5 : LocalContext context(nullptr, templ);
17627 :
17628 : v8::Local<v8::String> scriptSource = v8_str(
17629 : "function foo() {\n"
17630 : " AnalyzeScriptIdInStack();"
17631 : "}\n"
17632 5 : "foo();\n");
17633 5 : v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test", false);
17634 5 : script->Run(context.local()).ToLocalChecked();
17635 25 : for (int i = 0; i < 2; i++) {
17636 10 : CHECK_NE(scriptIdInStack[i], v8::Message::kNoScriptIdInfo);
17637 20 : CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17638 : }
17639 5 : }
17640 :
17641 :
17642 10 : void AnalyzeStackOfInlineScriptWithSourceURL(
17643 : const v8::FunctionCallbackInfo<v8::Value>& args) {
17644 20 : v8::HandleScope scope(args.GetIsolate());
17645 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17646 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17647 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
17648 10 : v8::Local<v8::String> url = v8_str("source_url");
17649 70 : for (int i = 0; i < 3; i++) {
17650 : v8::Local<v8::String> name =
17651 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17652 30 : CHECK(!name.IsEmpty());
17653 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17654 : }
17655 10 : }
17656 :
17657 :
17658 26644 : TEST(InlineScriptWithSourceURLInStackTrace) {
17659 5 : v8::Isolate* isolate = CcTest::isolate();
17660 10 : v8::HandleScope scope(isolate);
17661 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17662 15 : templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17663 : v8::FunctionTemplate::New(
17664 5 : CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17665 5 : LocalContext context(nullptr, templ);
17666 :
17667 : const char *source =
17668 : "function outer() {\n"
17669 : "function bar() {\n"
17670 : " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17671 : "}\n"
17672 : "function foo() {\n"
17673 : "\n"
17674 : " bar();\n"
17675 : "}\n"
17676 : "foo();\n"
17677 : "}\n"
17678 : "outer()\n%s";
17679 :
17680 : i::ScopedVector<char> code(1024);
17681 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
17682 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17683 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
17684 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17685 5 : }
17686 :
17687 395 : void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
17688 790 : CcTest::global()
17689 1975 : ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
17690 : .FromJust();
17691 395 : }
17692 :
17693 10 : class PromiseHookData {
17694 : public:
17695 : int before_hook_count = 0;
17696 : int after_hook_count = 0;
17697 : int promise_hook_count = 0;
17698 : int parent_promise_count = 0;
17699 : bool check_value = true;
17700 : std::string promise_hook_value;
17701 :
17702 : void Reset() {
17703 50 : before_hook_count = 0;
17704 50 : after_hook_count = 0;
17705 50 : promise_hook_count = 0;
17706 50 : parent_promise_count = 0;
17707 50 : check_value = true;
17708 50 : promise_hook_value = "";
17709 : }
17710 : };
17711 :
17712 : PromiseHookData* promise_hook_data;
17713 :
17714 350 : void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
17715 : v8::Local<v8::Value> parentPromise) {
17716 350 : promise_hook_data->promise_hook_count++;
17717 350 : switch (type) {
17718 : case v8::PromiseHookType::kInit:
17719 125 : SetPromise("init", promise);
17720 :
17721 125 : if (!parentPromise->IsUndefined()) {
17722 45 : promise_hook_data->parent_promise_count++;
17723 45 : SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
17724 : }
17725 :
17726 : break;
17727 : case v8::PromiseHookType::kResolve:
17728 125 : SetPromise("resolve", promise);
17729 125 : break;
17730 : case v8::PromiseHookType::kBefore:
17731 50 : promise_hook_data->before_hook_count++;
17732 50 : CHECK(promise_hook_data->before_hook_count >
17733 : promise_hook_data->after_hook_count);
17734 300 : CHECK(CcTest::global()
17735 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17736 : .ToLocalChecked()
17737 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
17738 : .FromJust());
17739 50 : SetPromise("before", promise);
17740 50 : break;
17741 : case v8::PromiseHookType::kAfter:
17742 50 : promise_hook_data->after_hook_count++;
17743 50 : CHECK(promise_hook_data->after_hook_count <=
17744 : promise_hook_data->before_hook_count);
17745 50 : if (promise_hook_data->check_value) {
17746 180 : CHECK(
17747 : CcTest::global()
17748 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17749 : .ToLocalChecked()
17750 : ->Equals(CcTest::isolate()->GetCurrentContext(),
17751 : v8_str(promise_hook_data->promise_hook_value.c_str()))
17752 : .FromJust());
17753 : }
17754 50 : SetPromise("after", promise);
17755 50 : break;
17756 : }
17757 350 : }
17758 :
17759 26644 : TEST(PromiseHook) {
17760 5 : LocalContext env;
17761 5 : v8::Isolate* isolate = env->GetIsolate();
17762 10 : v8::HandleScope scope(isolate);
17763 :
17764 5 : v8::Local<v8::Object> global = CcTest::global();
17765 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17766 :
17767 10 : promise_hook_data = new PromiseHookData();
17768 5 : isolate->SetPromiseHook(CustomPromiseHook);
17769 :
17770 : // Test that an initialized promise is passed to init. Other hooks
17771 : // can not have un initialized promise.
17772 5 : promise_hook_data->check_value = false;
17773 : CompileRun("var p = new Promise(() => {});");
17774 :
17775 15 : auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17776 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17777 : auto init_promise_obj = v8::Local<v8::Promise>::Cast(init_promise);
17778 5 : CHECK_EQ(init_promise_obj->State(), v8::Promise::PromiseState::kPending);
17779 5 : CHECK(!init_promise_obj->HasHandler());
17780 :
17781 5 : promise_hook_data->Reset();
17782 5 : promise_hook_data->promise_hook_value = "fulfilled";
17783 : const char* source =
17784 : "var resolve, value = ''; \n"
17785 : "var p = new Promise(r => resolve = r); \n";
17786 :
17787 : CompileRun(source);
17788 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17789 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17790 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17791 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17792 :
17793 : CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
17794 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17795 15 : auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17796 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17797 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17798 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17799 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17800 :
17801 : CompileRun("resolve(); \n");
17802 : auto resolve_promise =
17803 15 : global->Get(context, v8_str("resolve")).ToLocalChecked();
17804 15 : auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17805 15 : auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17806 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17807 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17808 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17809 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17810 :
17811 : CompileRun("value = ''; var p2 = p1.then(() => { value = 'fulfilled' }); \n");
17812 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17813 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17814 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17815 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17816 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17817 15 : CHECK(GetPromise("p2")->Equals(env.local(), init_promise).FromJust());
17818 15 : CHECK(GetPromise("p1")->Equals(env.local(), parent_promise).FromJust());
17819 15 : CHECK(GetPromise("p2")->Equals(env.local(), before_promise).FromJust());
17820 15 : CHECK(GetPromise("p2")->Equals(env.local(), after_promise).FromJust());
17821 15 : CHECK(GetPromise("p2")->Equals(env.local(), resolve_promise).FromJust());
17822 5 : CHECK_EQ(10, promise_hook_data->promise_hook_count);
17823 :
17824 : promise_hook_data->Reset();
17825 5 : promise_hook_data->promise_hook_value = "rejected";
17826 : source =
17827 : "var reject, value = ''; \n"
17828 : "var p = new Promise((_, r) => reject = r); \n";
17829 :
17830 : CompileRun(source);
17831 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17832 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17833 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17834 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17835 :
17836 : CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
17837 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17838 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17839 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17840 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17841 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17842 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17843 :
17844 : CompileRun("reject(); \n");
17845 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17846 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17847 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17848 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17849 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17850 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17851 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17852 :
17853 : promise_hook_data->Reset();
17854 5 : promise_hook_data->promise_hook_value = "Promise.resolve";
17855 : source =
17856 : "var value = ''; \n"
17857 : "var p = Promise.resolve('Promise.resolve'); \n";
17858 :
17859 : CompileRun(source);
17860 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17861 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17862 : // init hook and resolve hook
17863 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17864 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17865 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17866 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17867 :
17868 : CompileRun("var p1 = p.then((v) => { value = v; }); \n");
17869 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17870 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17871 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17872 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17873 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17874 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17875 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17876 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17877 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17878 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17879 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
17880 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
17881 :
17882 : promise_hook_data->Reset();
17883 : source =
17884 : "var resolve, value = ''; \n"
17885 : "var p = new Promise((_, r) => resolve = r); \n";
17886 :
17887 : CompileRun(source);
17888 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17889 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17890 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17891 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17892 :
17893 : CompileRun("resolve(); \n");
17894 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17895 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17896 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17897 :
17898 : promise_hook_data->Reset();
17899 : source =
17900 : "var reject, value = ''; \n"
17901 : "var p = new Promise((_, r) => reject = r); \n";
17902 :
17903 : CompileRun(source);
17904 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17905 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17906 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
17907 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
17908 :
17909 : CompileRun("reject(); \n");
17910 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17911 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17912 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
17913 :
17914 : promise_hook_data->Reset();
17915 : // This test triggers after callbacks right after each other, so
17916 : // lets just check the value at the end.
17917 5 : promise_hook_data->check_value = false;
17918 5 : promise_hook_data->promise_hook_value = "Promise.all";
17919 : source =
17920 : "var resolve, value = ''; \n"
17921 : "var tempPromise = new Promise(r => resolve = r); \n"
17922 : "var p = Promise.all([tempPromise]);\n "
17923 : "var p1 = p.then(v => value = v[0]); \n";
17924 :
17925 : CompileRun(source);
17926 : // 1) init hook (tempPromise)
17927 : // 2) init hook (p)
17928 : // 3) init hook (throwaway Promise in Promise.all, p)
17929 : // 4) init hook (p1, p)
17930 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
17931 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
17932 :
17933 5 : promise_hook_data->promise_hook_value = "Promise.all";
17934 : CompileRun("resolve('Promise.all'); \n");
17935 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17936 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17937 : // 5) resolve hook (tempPromise)
17938 : // 6) resolve hook (throwaway Promise in Promise.all)
17939 : // 6) before hook (throwaway Promise in Promise.all)
17940 : // 7) after hook (throwaway Promise in Promise.all)
17941 : // 8) before hook (p)
17942 : // 9) after hook (p)
17943 : // 10) resolve hook (p1)
17944 : // 11) before hook (p1)
17945 : // 12) after hook (p1)
17946 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
17947 30 : CHECK(CcTest::global()
17948 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17949 : .ToLocalChecked()
17950 : ->Equals(CcTest::isolate()->GetCurrentContext(),
17951 : v8_str(promise_hook_data->promise_hook_value.c_str()))
17952 : .FromJust());
17953 :
17954 5 : promise_hook_data->Reset();
17955 : // This test triggers after callbacks right after each other, so
17956 : // lets just check the value at the end.
17957 5 : promise_hook_data->check_value = false;
17958 5 : promise_hook_data->promise_hook_value = "Promise.race";
17959 : source =
17960 : "var resolve, value = ''; \n"
17961 : "var tempPromise = new Promise(r => resolve = r); \n"
17962 : "var p = Promise.race([tempPromise]);\n "
17963 : "var p1 = p.then(v => value = v); \n";
17964 :
17965 : CompileRun(source);
17966 : // 1) init hook (tempPromise)
17967 : // 2) init hook (p)
17968 : // 3) init hook (throwaway Promise in Promise.race, p)
17969 : // 4) init hook (p1, p)
17970 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
17971 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
17972 :
17973 5 : promise_hook_data->promise_hook_value = "Promise.race";
17974 : CompileRun("resolve('Promise.race'); \n");
17975 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17976 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17977 : // 5) resolve hook (tempPromise)
17978 : // 6) resolve hook (throwaway Promise in Promise.race)
17979 : // 6) before hook (throwaway Promise in Promise.race)
17980 : // 7) after hook (throwaway Promise in Promise.race)
17981 : // 8) before hook (p)
17982 : // 9) after hook (p)
17983 : // 10) resolve hook (p1)
17984 : // 11) before hook (p1)
17985 : // 12) after hook (p1)
17986 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
17987 30 : CHECK(CcTest::global()
17988 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17989 : .ToLocalChecked()
17990 : ->Equals(CcTest::isolate()->GetCurrentContext(),
17991 : v8_str(promise_hook_data->promise_hook_value.c_str()))
17992 : .FromJust());
17993 :
17994 5 : promise_hook_data->Reset();
17995 5 : promise_hook_data->promise_hook_value = "subclass";
17996 : source =
17997 : "var resolve, value = '';\n"
17998 : "class MyPromise extends Promise { \n"
17999 : " then(onFulfilled, onRejected) { \n"
18000 : " return super.then(onFulfilled, onRejected); \n"
18001 : " };\n"
18002 : "};\n"
18003 : "var p = new MyPromise(r => resolve = r);\n";
18004 :
18005 : CompileRun(source);
18006 : // 1) init hook (p)
18007 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18008 :
18009 : CompileRun("var p1 = p.then(() => value = 'subclass');\n");
18010 : // 2) init hook (p1)
18011 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18012 :
18013 : CompileRun("resolve();\n");
18014 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18015 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18016 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18017 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18018 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18019 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18020 : // 3) resolve hook (p)
18021 : // 4) before hook (p)
18022 : // 5) after hook (p)
18023 : // 6) resolve hook (p1)
18024 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18025 :
18026 : promise_hook_data->Reset();
18027 : source =
18028 : "class X extends Promise {\n"
18029 : " static get [Symbol.species]() {\n"
18030 : " return Y;\n"
18031 : " }\n"
18032 : "}\n"
18033 : "class Y {\n"
18034 : " constructor(executor) {\n"
18035 : " return new Proxy(new Promise(executor), {});\n"
18036 : " }\n"
18037 : "}\n"
18038 : "var x = X.resolve().then(() => {});\n";
18039 :
18040 : CompileRun(source);
18041 :
18042 5 : promise_hook_data->Reset();
18043 : source =
18044 : "var resolve, value = '';\n"
18045 : "var p = new Promise(r => resolve = r);\n";
18046 :
18047 : CompileRun(source);
18048 10 : CHECK_EQ(v8::Promise::kPending, GetPromise("p")->State());
18049 : CompileRun("resolve(Promise.resolve(value));\n");
18050 10 : CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State());
18051 5 : CHECK_EQ(9, promise_hook_data->promise_hook_count);
18052 :
18053 10 : delete promise_hook_data;
18054 5 : isolate->SetPromiseHook(nullptr);
18055 5 : }
18056 :
18057 10 : void AnalyzeStackOfDynamicScriptWithSourceURL(
18058 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18059 20 : v8::HandleScope scope(args.GetIsolate());
18060 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18061 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18062 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18063 10 : v8::Local<v8::String> url = v8_str("source_url");
18064 70 : for (int i = 0; i < 3; i++) {
18065 : v8::Local<v8::String> name =
18066 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18067 30 : CHECK(!name.IsEmpty());
18068 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18069 : }
18070 10 : }
18071 :
18072 :
18073 26644 : TEST(DynamicWithSourceURLInStackTrace) {
18074 5 : v8::Isolate* isolate = CcTest::isolate();
18075 10 : v8::HandleScope scope(isolate);
18076 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18077 15 : templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18078 : v8::FunctionTemplate::New(
18079 5 : CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18080 5 : LocalContext context(nullptr, templ);
18081 :
18082 : const char *source =
18083 : "function outer() {\n"
18084 : "function bar() {\n"
18085 : " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18086 : "}\n"
18087 : "function foo() {\n"
18088 : "\n"
18089 : " bar();\n"
18090 : "}\n"
18091 : "foo();\n"
18092 : "}\n"
18093 : "outer()\n%s";
18094 :
18095 : i::ScopedVector<char> code(1024);
18096 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18097 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18098 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18099 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18100 5 : }
18101 :
18102 :
18103 26644 : TEST(DynamicWithSourceURLInStackTraceString) {
18104 5 : LocalContext context;
18105 10 : v8::HandleScope scope(context->GetIsolate());
18106 :
18107 : const char *source =
18108 : "function outer() {\n"
18109 : " function foo() {\n"
18110 : " FAIL.FAIL;\n"
18111 : " }\n"
18112 : " foo();\n"
18113 : "}\n"
18114 : "outer()\n%s";
18115 :
18116 : i::ScopedVector<char> code(1024);
18117 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18118 10 : v8::TryCatch try_catch(context->GetIsolate());
18119 5 : CompileRunWithOrigin(code.start(), "", 0, 0);
18120 5 : CHECK(try_catch.HasCaught());
18121 : v8::String::Utf8Value stack(
18122 : context->GetIsolate(),
18123 15 : try_catch.StackTrace(context.local()).ToLocalChecked());
18124 5 : CHECK_NOT_NULL(strstr(*stack, "at foo (source_url:3:5)"));
18125 5 : }
18126 :
18127 :
18128 26644 : TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18129 5 : LocalContext context;
18130 10 : v8::HandleScope scope(context->GetIsolate());
18131 :
18132 : const char *source =
18133 : "function outer() {\n"
18134 : " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18135 : " //# sourceURL=source_url\";\n"
18136 : " eval(scriptContents);\n"
18137 : " foo(); }\n"
18138 : "outer();\n"
18139 : "//# sourceURL=outer_url";
18140 :
18141 10 : v8::TryCatch try_catch(context->GetIsolate());
18142 : CompileRun(source);
18143 5 : CHECK(try_catch.HasCaught());
18144 :
18145 5 : Local<v8::Message> message = try_catch.Message();
18146 10 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18147 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18148 : "source_url"));
18149 5 : }
18150 :
18151 :
18152 26644 : TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18153 5 : LocalContext context;
18154 10 : v8::HandleScope scope(context->GetIsolate());
18155 :
18156 : const char *source =
18157 : "function outer() {\n"
18158 : " var scriptContents = \"function boo(){ boo(); }\\\n"
18159 : " //# sourceURL=source_url\";\n"
18160 : " eval(scriptContents);\n"
18161 : " boo(); }\n"
18162 : "outer();\n"
18163 : "//# sourceURL=outer_url";
18164 :
18165 10 : v8::TryCatch try_catch(context->GetIsolate());
18166 : CompileRun(source);
18167 5 : CHECK(try_catch.HasCaught());
18168 :
18169 5 : Local<v8::Message> message = try_catch.Message();
18170 10 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18171 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18172 : "source_url"));
18173 5 : }
18174 :
18175 :
18176 5 : static void CreateGarbageInOldSpace() {
18177 : i::Factory* factory = CcTest::i_isolate()->factory();
18178 10 : v8::HandleScope scope(CcTest::isolate());
18179 : i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18180 10005 : for (int i = 0; i < 1000; i++) {
18181 5000 : factory->NewFixedArray(1000, i::AllocationType::kOld);
18182 : }
18183 5 : }
18184 :
18185 :
18186 : // Test that idle notification can be handled and eventually collects garbage.
18187 26644 : TEST(TestIdleNotification) {
18188 5 : if (!i::FLAG_incremental_marking) return;
18189 : ManualGCScope manual_gc_scope;
18190 : const intptr_t MB = 1024 * 1024;
18191 : const double IdlePauseInSeconds = 1.0;
18192 5 : LocalContext env;
18193 10 : v8::HandleScope scope(env->GetIsolate());
18194 5 : intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18195 5 : CreateGarbageInOldSpace();
18196 5 : intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18197 5 : CHECK_GT(size_with_garbage, initial_size + MB);
18198 : bool finished = false;
18199 75 : for (int i = 0; i < 200 && !finished; i++) {
18200 70 : if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
18201 5 : CcTest::heap()->StartIdleIncrementalMarking(
18202 5 : i::GarbageCollectionReason::kTesting);
18203 : }
18204 70 : finished = env->GetIsolate()->IdleNotificationDeadline(
18205 105 : (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
18206 : static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
18207 35 : IdlePauseInSeconds);
18208 70 : if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
18209 10 : CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
18210 : }
18211 : }
18212 5 : intptr_t final_size = CcTest::heap()->SizeOfObjects();
18213 5 : CHECK(finished);
18214 5 : CHECK_LT(final_size, initial_size + 1);
18215 : }
18216 :
18217 26644 : TEST(TestMemorySavingsMode) {
18218 5 : LocalContext context;
18219 5 : v8::Isolate* isolate = context->GetIsolate();
18220 : v8::internal::Isolate* i_isolate =
18221 : reinterpret_cast<v8::internal::Isolate*>(isolate);
18222 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18223 5 : isolate->EnableMemorySavingsMode();
18224 5 : CHECK(i_isolate->IsMemorySavingsModeActive());
18225 5 : isolate->DisableMemorySavingsMode();
18226 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18227 5 : }
18228 :
18229 26644 : TEST(Regress2333) {
18230 5 : LocalContext env;
18231 35 : for (int i = 0; i < 3; i++) {
18232 15 : CcTest::CollectGarbage(i::NEW_SPACE);
18233 : }
18234 5 : }
18235 :
18236 : static uint32_t* stack_limit;
18237 :
18238 10 : static void GetStackLimitCallback(
18239 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18240 : stack_limit = reinterpret_cast<uint32_t*>(
18241 10 : CcTest::i_isolate()->stack_guard()->real_climit());
18242 10 : }
18243 :
18244 :
18245 : // Uses the address of a local variable to determine the stack top now.
18246 : // Given a size, returns an address that is that far from the current
18247 : // top of stack.
18248 : static uint32_t* ComputeStackLimit(uint32_t size) {
18249 : uint32_t* answer = &size - (size / sizeof(size));
18250 : // If the size is very large and the stack is very near the bottom of
18251 : // memory then the calculation above may wrap around and give an address
18252 : // that is above the (downwards-growing) stack. In that case we return
18253 : // a very low address.
18254 : if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18255 : return answer;
18256 : }
18257 :
18258 :
18259 : // We need at least 165kB for an x64 debug build with clang and ASAN.
18260 : static const int stack_breathing_room = 256 * i::KB;
18261 :
18262 :
18263 26644 : TEST(SetStackLimit) {
18264 : uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18265 :
18266 : // Set stack limit.
18267 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18268 :
18269 : // Execute a script.
18270 5 : LocalContext env;
18271 10 : v8::HandleScope scope(env->GetIsolate());
18272 : Local<v8::FunctionTemplate> fun_templ =
18273 5 : v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18274 5 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18275 20 : CHECK(env->Global()
18276 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18277 : .FromJust());
18278 : CompileRun("get_stack_limit();");
18279 :
18280 5 : CHECK(stack_limit == set_limit);
18281 5 : }
18282 :
18283 :
18284 26644 : TEST(SetStackLimitInThread) {
18285 : uint32_t* set_limit;
18286 : {
18287 10 : v8::Locker locker(CcTest::isolate());
18288 : set_limit = ComputeStackLimit(stack_breathing_room);
18289 :
18290 : // Set stack limit.
18291 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18292 :
18293 : // Execute a script.
18294 10 : v8::HandleScope scope(CcTest::isolate());
18295 5 : LocalContext env;
18296 : Local<v8::FunctionTemplate> fun_templ =
18297 5 : v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18298 5 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18299 20 : CHECK(env->Global()
18300 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18301 : .FromJust());
18302 : CompileRun("get_stack_limit();");
18303 :
18304 5 : CHECK(stack_limit == set_limit);
18305 : }
18306 : {
18307 10 : v8::Locker locker(CcTest::isolate());
18308 5 : CHECK(stack_limit == set_limit);
18309 : }
18310 5 : }
18311 :
18312 26645 : THREADED_TEST(GetHeapStatistics) {
18313 6 : LocalContext c1;
18314 12 : v8::HandleScope scope(c1->GetIsolate());
18315 6 : v8::HeapStatistics heap_statistics;
18316 6 : CHECK_EQ(0u, heap_statistics.total_heap_size());
18317 6 : CHECK_EQ(0u, heap_statistics.used_heap_size());
18318 6 : c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18319 6 : CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18320 6 : CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18321 6 : }
18322 :
18323 26644 : TEST(GetHeapSpaceStatistics) {
18324 5 : LocalContext c1;
18325 5 : v8::Isolate* isolate = c1->GetIsolate();
18326 10 : v8::HandleScope scope(isolate);
18327 5 : v8::HeapStatistics heap_statistics;
18328 :
18329 : // Force allocation in LO_SPACE so that every space has non-zero size.
18330 : v8::internal::Isolate* i_isolate =
18331 : reinterpret_cast<v8::internal::Isolate*>(isolate);
18332 : auto unused = i_isolate->factory()->TryNewFixedArray(512 * 1024,
18333 5 : i::AllocationType::kOld);
18334 : USE(unused);
18335 :
18336 5 : isolate->GetHeapStatistics(&heap_statistics);
18337 :
18338 : // Ensure that the sum of all the spaces matches the totals from
18339 : // GetHeapSpaceStatics.
18340 : size_t total_size = 0u;
18341 : size_t total_used_size = 0u;
18342 : size_t total_available_size = 0u;
18343 : size_t total_physical_size = 0u;
18344 85 : for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); ++i) {
18345 40 : v8::HeapSpaceStatistics space_statistics;
18346 40 : isolate->GetHeapSpaceStatistics(&space_statistics, i);
18347 40 : CHECK_NOT_NULL(space_statistics.space_name());
18348 40 : total_size += space_statistics.space_size();
18349 40 : total_used_size += space_statistics.space_used_size();
18350 40 : total_available_size += space_statistics.space_available_size();
18351 40 : total_physical_size += space_statistics.physical_space_size();
18352 : }
18353 10 : total_available_size += CcTest::heap()->memory_allocator()->Available();
18354 :
18355 5 : CHECK_EQ(total_size, heap_statistics.total_heap_size());
18356 5 : CHECK_EQ(total_used_size, heap_statistics.used_heap_size());
18357 5 : CHECK_EQ(total_available_size, heap_statistics.total_available_size());
18358 5 : CHECK_EQ(total_physical_size, heap_statistics.total_physical_size());
18359 5 : }
18360 :
18361 26644 : TEST(NumberOfNativeContexts) {
18362 : static const size_t kNumTestContexts = 10;
18363 : i::Isolate* isolate = CcTest::i_isolate();
18364 : i::HandleScope scope(isolate);
18365 160 : v8::Global<v8::Context> context[kNumTestContexts];
18366 5 : v8::HeapStatistics heap_statistics;
18367 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18368 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18369 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18370 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
18371 : i::HandleScope inner(isolate);
18372 100 : context[i].Reset(CcTest::isolate(), v8::Context::New(CcTest::isolate()));
18373 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18374 50 : CHECK_EQ(i + 1, heap_statistics.number_of_native_contexts());
18375 : }
18376 105 : for (size_t i = 0; i < kNumTestContexts; i++) {
18377 : context[i].Reset();
18378 50 : CcTest::PreciseCollectAllGarbage();
18379 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18380 50 : CHECK_EQ(kNumTestContexts - i - 1u,
18381 : heap_statistics.number_of_native_contexts());
18382 : }
18383 5 : }
18384 :
18385 26644 : TEST(NumberOfDetachedContexts) {
18386 : static const size_t kNumTestContexts = 10;
18387 : i::Isolate* isolate = CcTest::i_isolate();
18388 : i::HandleScope scope(isolate);
18389 160 : v8::Global<v8::Context> context[kNumTestContexts];
18390 5 : v8::HeapStatistics heap_statistics;
18391 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18392 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18393 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18394 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
18395 : i::HandleScope inner(isolate);
18396 50 : v8::Local<v8::Context> local = v8::Context::New(CcTest::isolate());
18397 50 : context[i].Reset(CcTest::isolate(), local);
18398 50 : local->DetachGlobal();
18399 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18400 50 : CHECK_EQ(i + 1, heap_statistics.number_of_detached_contexts());
18401 : }
18402 105 : for (size_t i = 0; i < kNumTestContexts; i++) {
18403 : context[i].Reset();
18404 50 : CcTest::PreciseCollectAllGarbage();
18405 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18406 50 : CHECK_EQ(kNumTestContexts - i - 1u,
18407 : heap_statistics.number_of_detached_contexts());
18408 : }
18409 5 : }
18410 :
18411 : class VisitorImpl : public v8::ExternalResourceVisitor {
18412 : public:
18413 5 : explicit VisitorImpl(TestResource** resource) {
18414 45 : for (int i = 0; i < 4; i++) {
18415 20 : resource_[i] = resource[i];
18416 20 : found_resource_[i] = false;
18417 : }
18418 : }
18419 10 : ~VisitorImpl() override = default;
18420 25 : void VisitExternalString(v8::Local<v8::String> string) override {
18421 25 : if (!string->IsExternal()) {
18422 5 : CHECK(string->IsExternalOneByte());
18423 : return;
18424 : }
18425 : v8::String::ExternalStringResource* resource =
18426 : string->GetExternalStringResource();
18427 20 : CHECK(resource);
18428 180 : for (int i = 0; i < 4; i++) {
18429 80 : if (resource_[i] == resource) {
18430 20 : CHECK(!found_resource_[i]);
18431 20 : found_resource_[i] = true;
18432 : }
18433 : }
18434 : }
18435 5 : void CheckVisitedResources() {
18436 45 : for (int i = 0; i < 4; i++) {
18437 20 : CHECK(found_resource_[i]);
18438 : }
18439 5 : }
18440 :
18441 : private:
18442 : v8::String::ExternalStringResource* resource_[4];
18443 : bool found_resource_[4];
18444 : };
18445 :
18446 :
18447 26644 : TEST(ExternalizeOldSpaceTwoByteCons) {
18448 5 : v8::Isolate* isolate = CcTest::isolate();
18449 5 : LocalContext env;
18450 10 : v8::HandleScope scope(isolate);
18451 : v8::Local<v8::String> cons =
18452 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18453 5 : ->ToString(env.local())
18454 : .ToLocalChecked();
18455 5 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18456 5 : CcTest::CollectAllAvailableGarbage();
18457 10 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18458 :
18459 : TestResource* resource = new TestResource(
18460 5 : AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18461 5 : cons->MakeExternal(resource);
18462 :
18463 5 : CHECK(cons->IsExternal());
18464 5 : CHECK_EQ(resource, cons->GetExternalStringResource());
18465 : String::Encoding encoding;
18466 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18467 5 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18468 5 : }
18469 :
18470 :
18471 26644 : TEST(ExternalizeOldSpaceOneByteCons) {
18472 5 : v8::Isolate* isolate = CcTest::isolate();
18473 5 : LocalContext env;
18474 10 : v8::HandleScope scope(isolate);
18475 : v8::Local<v8::String> cons =
18476 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18477 5 : ->ToString(env.local())
18478 : .ToLocalChecked();
18479 5 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18480 5 : CcTest::CollectAllAvailableGarbage();
18481 10 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18482 :
18483 : TestOneByteResource* resource =
18484 5 : new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18485 5 : cons->MakeExternal(resource);
18486 :
18487 5 : CHECK(cons->IsExternalOneByte());
18488 5 : CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18489 : String::Encoding encoding;
18490 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18491 5 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18492 5 : }
18493 :
18494 :
18495 26644 : TEST(VisitExternalStrings) {
18496 5 : v8::Isolate* isolate = CcTest::isolate();
18497 5 : LocalContext env;
18498 10 : v8::HandleScope scope(isolate);
18499 : const char* string = "Some string";
18500 5 : uint16_t* two_byte_string = AsciiToTwoByteString(string);
18501 : TestResource* resource[4];
18502 10 : resource[0] = new TestResource(two_byte_string);
18503 : v8::Local<v8::String> string0 =
18504 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
18505 : .ToLocalChecked();
18506 10 : resource[1] = new TestResource(two_byte_string, nullptr, false);
18507 : v8::Local<v8::String> string1 =
18508 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
18509 : .ToLocalChecked();
18510 :
18511 : // Externalized symbol.
18512 10 : resource[2] = new TestResource(two_byte_string, nullptr, false);
18513 : v8::Local<v8::String> string2 =
18514 5 : v8::String::NewFromUtf8(env->GetIsolate(), string,
18515 5 : v8::NewStringType::kInternalized)
18516 : .ToLocalChecked();
18517 5 : CHECK(string2->MakeExternal(resource[2]));
18518 :
18519 : // Symbolized External.
18520 10 : resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18521 : v8::Local<v8::String> string3 =
18522 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
18523 : .ToLocalChecked();
18524 5 : CcTest::CollectAllAvailableGarbage(); // Tenure string.
18525 : // Turn into a symbol.
18526 : i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18527 10 : CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18528 : string3_i).is_null());
18529 10 : CHECK(string3_i->IsInternalizedString());
18530 :
18531 : // We need to add usages for string* to avoid warnings in GCC 4.7
18532 5 : CHECK(string0->IsExternal());
18533 5 : CHECK(string1->IsExternal());
18534 5 : CHECK(string2->IsExternal());
18535 5 : CHECK(string3->IsExternal());
18536 :
18537 : VisitorImpl visitor(resource);
18538 5 : isolate->VisitExternalResources(&visitor);
18539 5 : visitor.CheckVisitedResources();
18540 5 : }
18541 :
18542 :
18543 26644 : TEST(ExternalStringCollectedAtTearDown) {
18544 5 : int destroyed = 0;
18545 : v8::Isolate::CreateParams create_params;
18546 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18547 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18548 : { v8::Isolate::Scope isolate_scope(isolate);
18549 10 : v8::HandleScope handle_scope(isolate);
18550 : const char* s = "One string to test them all, one string to find them.";
18551 : TestOneByteResource* inscription =
18552 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18553 : v8::Local<v8::String> ring =
18554 5 : v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
18555 : // Ring is still alive. Orcs are roaming freely across our lands.
18556 5 : CHECK_EQ(0, destroyed);
18557 : USE(ring);
18558 : }
18559 :
18560 5 : isolate->Dispose();
18561 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18562 5 : CHECK_EQ(1, destroyed);
18563 5 : }
18564 :
18565 :
18566 26644 : TEST(ExternalInternalizedStringCollectedAtTearDown) {
18567 5 : int destroyed = 0;
18568 : v8::Isolate::CreateParams create_params;
18569 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18570 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18571 : { v8::Isolate::Scope isolate_scope(isolate);
18572 5 : LocalContext env(isolate);
18573 10 : v8::HandleScope handle_scope(isolate);
18574 : CompileRun("var ring = 'One string to test them all';");
18575 : const char* s = "One string to test them all";
18576 : TestOneByteResource* inscription =
18577 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18578 : v8::Local<v8::String> ring =
18579 5 : CompileRun("ring")->ToString(env.local()).ToLocalChecked();
18580 5 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18581 5 : ring->MakeExternal(inscription);
18582 : // Ring is still alive. Orcs are roaming freely across our lands.
18583 5 : CHECK_EQ(0, destroyed);
18584 : USE(ring);
18585 : }
18586 :
18587 5 : isolate->Dispose();
18588 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18589 5 : CHECK_EQ(1, destroyed);
18590 5 : }
18591 :
18592 :
18593 26644 : TEST(ExternalInternalizedStringCollectedAtGC) {
18594 5 : int destroyed = 0;
18595 5 : { LocalContext env;
18596 10 : v8::HandleScope handle_scope(env->GetIsolate());
18597 : CompileRun("var ring = 'One string to test them all';");
18598 : const char* s = "One string to test them all";
18599 : TestOneByteResource* inscription =
18600 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18601 : v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
18602 10 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18603 5 : ring->MakeExternal(inscription);
18604 : // Ring is still alive. Orcs are roaming freely across our lands.
18605 5 : CHECK_EQ(0, destroyed);
18606 : USE(ring);
18607 : }
18608 :
18609 : // Garbage collector deals swift blows to evil.
18610 5 : CcTest::i_isolate()->compilation_cache()->Clear();
18611 5 : CcTest::CollectAllAvailableGarbage();
18612 :
18613 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18614 5 : CHECK_EQ(1, destroyed);
18615 5 : }
18616 :
18617 :
18618 : static double DoubleFromBits(uint64_t value) {
18619 : double target;
18620 : i::MemCopy(&target, &value, sizeof(target));
18621 : return target;
18622 : }
18623 :
18624 :
18625 : static uint64_t DoubleToBits(double value) {
18626 : uint64_t target;
18627 : i::MemCopy(&target, &value, sizeof(target));
18628 : return target;
18629 : }
18630 :
18631 :
18632 120 : static double DoubleToDateTime(double input) {
18633 : double date_limit = 864e13;
18634 120 : if (std::isnan(input) || input < -date_limit || input > date_limit) {
18635 : return std::numeric_limits<double>::quiet_NaN();
18636 : }
18637 60 : return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18638 : }
18639 :
18640 :
18641 : // We don't have a consistent way to write 64-bit constants syntactically, so we
18642 : // split them into two 32-bit constants and combine them programmatically.
18643 : static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18644 : return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18645 : }
18646 :
18647 :
18648 26645 : THREADED_TEST(QuietSignalingNaNs) {
18649 6 : LocalContext context;
18650 6 : v8::Isolate* isolate = context->GetIsolate();
18651 12 : v8::HandleScope scope(isolate);
18652 12 : v8::TryCatch try_catch(isolate);
18653 :
18654 : // Special double values.
18655 : double snan = DoubleFromBits(0x7FF00000, 0x00000001);
18656 : double qnan = DoubleFromBits(0x7FF80000, 0x00000000);
18657 : double infinity = DoubleFromBits(0x7FF00000, 0x00000000);
18658 : double max_normal = DoubleFromBits(0x7FEFFFFF, 0xFFFFFFFFu);
18659 : double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18660 : double max_denormal = DoubleFromBits(0x000FFFFF, 0xFFFFFFFFu);
18661 : double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18662 :
18663 : // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18664 : // on either side of the epoch.
18665 : double date_limit = 864e13;
18666 :
18667 : double test_values[] = {
18668 : snan,
18669 : qnan,
18670 : infinity,
18671 : max_normal,
18672 : date_limit + 1,
18673 : date_limit,
18674 : min_normal,
18675 : max_denormal,
18676 : min_denormal,
18677 : 0,
18678 : -0,
18679 : -min_denormal,
18680 : -max_denormal,
18681 : -min_normal,
18682 : -date_limit,
18683 : -date_limit - 1,
18684 : -max_normal,
18685 : -infinity,
18686 : -qnan,
18687 : -snan
18688 6 : };
18689 : int num_test_values = 20;
18690 :
18691 246 : for (int i = 0; i < num_test_values; i++) {
18692 120 : double test_value = test_values[i];
18693 :
18694 : // Check that Number::New preserves non-NaNs and quiets SNaNs.
18695 120 : v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
18696 240 : double stored_number = number->NumberValue(context.local()).FromJust();
18697 120 : if (!std::isnan(test_value)) {
18698 96 : CHECK_EQ(test_value, stored_number);
18699 : } else {
18700 : uint64_t stored_bits = DoubleToBits(stored_number);
18701 : // Check if quiet nan (bits 51..62 all set).
18702 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18703 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18704 : !defined(USE_SIMULATOR)
18705 : // Most significant fraction bit for quiet nan is set to 0
18706 : // on MIPS architecture. Allowed by IEEE-754.
18707 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18708 : #else
18709 24 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18710 : #endif
18711 : }
18712 :
18713 : // Check that Date::New preserves non-NaNs in the date range and
18714 : // quiets SNaNs.
18715 : v8::Local<v8::Value> date =
18716 120 : v8::Date::New(context.local(), test_value).ToLocalChecked();
18717 120 : double expected_stored_date = DoubleToDateTime(test_value);
18718 240 : double stored_date = date->NumberValue(context.local()).FromJust();
18719 120 : if (!std::isnan(expected_stored_date)) {
18720 60 : CHECK_EQ(expected_stored_date, stored_date);
18721 : } else {
18722 : uint64_t stored_bits = DoubleToBits(stored_date);
18723 : // Check if quiet nan (bits 51..62 all set).
18724 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18725 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18726 : !defined(USE_SIMULATOR)
18727 : // Most significant fraction bit for quiet nan is set to 0
18728 : // on MIPS architecture. Allowed by IEEE-754.
18729 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18730 : #else
18731 60 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18732 : #endif
18733 : }
18734 : }
18735 6 : }
18736 :
18737 :
18738 66 : static void SpaghettiIncident(
18739 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18740 132 : v8::HandleScope scope(args.GetIsolate());
18741 132 : v8::TryCatch tc(args.GetIsolate());
18742 : v8::MaybeLocal<v8::String> str(
18743 132 : args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
18744 : USE(str);
18745 66 : if (tc.HasCaught())
18746 66 : tc.ReThrow();
18747 66 : }
18748 :
18749 :
18750 : // Test that an exception can be propagated down through a spaghetti
18751 : // stack using ReThrow.
18752 26645 : THREADED_TEST(SpaghettiStackReThrow) {
18753 6 : v8::Isolate* isolate = CcTest::isolate();
18754 12 : v8::HandleScope scope(isolate);
18755 6 : LocalContext context;
18756 12 : context->Global()
18757 12 : ->Set(context.local(), v8_str("s"),
18758 12 : v8::FunctionTemplate::New(isolate, SpaghettiIncident)
18759 6 : ->GetFunction(context.local())
18760 12 : .ToLocalChecked())
18761 : .FromJust();
18762 12 : v8::TryCatch try_catch(isolate);
18763 : CompileRun(
18764 : "var i = 0;"
18765 : "var o = {"
18766 : " toString: function () {"
18767 : " if (i == 10) {"
18768 : " throw 'Hey!';"
18769 : " } else {"
18770 : " i++;"
18771 : " return s(o);"
18772 : " }"
18773 : " }"
18774 : "};"
18775 : "s(o);");
18776 6 : CHECK(try_catch.HasCaught());
18777 12 : v8::String::Utf8Value value(isolate, try_catch.Exception());
18778 6 : CHECK_EQ(0, strcmp(*value, "Hey!"));
18779 6 : }
18780 :
18781 :
18782 26644 : TEST(Regress528) {
18783 : ManualGCScope manual_gc_scope;
18784 5 : v8::V8::Initialize();
18785 5 : v8::Isolate* isolate = CcTest::isolate();
18786 5 : i::FLAG_retain_maps_for_n_gc = 0;
18787 10 : v8::HandleScope scope(isolate);
18788 : v8::Local<Context> other_context;
18789 : int gc_count;
18790 :
18791 : // Create a context used to keep the code from aging in the compilation
18792 : // cache.
18793 5 : other_context = Context::New(isolate);
18794 :
18795 : // Context-dependent context data creates reference from the compilation
18796 : // cache to the global object.
18797 : const char* source_simple = "1";
18798 : {
18799 10 : v8::HandleScope scope(isolate);
18800 5 : v8::Local<Context> context = Context::New(isolate);
18801 :
18802 5 : context->Enter();
18803 5 : Local<v8::String> obj = v8_str("");
18804 5 : context->SetEmbedderData(0, obj);
18805 : CompileRun(source_simple);
18806 5 : context->Exit();
18807 : }
18808 5 : isolate->ContextDisposedNotification();
18809 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18810 5 : other_context->Enter();
18811 : CompileRun(source_simple);
18812 5 : other_context->Exit();
18813 5 : CcTest::CollectAllGarbage();
18814 5 : if (GetGlobalObjectsCount() == 1) break;
18815 : }
18816 5 : CHECK_GE(2, gc_count);
18817 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18818 :
18819 : // Eval in a function creates reference from the compilation cache to the
18820 : // global object.
18821 : const char* source_eval = "function f(){eval('1')}; f()";
18822 : {
18823 10 : v8::HandleScope scope(isolate);
18824 5 : v8::Local<Context> context = Context::New(isolate);
18825 :
18826 5 : context->Enter();
18827 : CompileRun(source_eval);
18828 5 : context->Exit();
18829 : }
18830 5 : isolate->ContextDisposedNotification();
18831 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18832 5 : other_context->Enter();
18833 : CompileRun(source_eval);
18834 5 : other_context->Exit();
18835 5 : CcTest::CollectAllGarbage();
18836 5 : if (GetGlobalObjectsCount() == 1) break;
18837 : }
18838 5 : CHECK_GE(2, gc_count);
18839 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18840 :
18841 : // Looking up the line number for an exception creates reference from the
18842 : // compilation cache to the global object.
18843 : const char* source_exception = "function f(){throw 1;} f()";
18844 : {
18845 10 : v8::HandleScope scope(isolate);
18846 5 : v8::Local<Context> context = Context::New(isolate);
18847 :
18848 5 : context->Enter();
18849 10 : v8::TryCatch try_catch(isolate);
18850 : CompileRun(source_exception);
18851 5 : CHECK(try_catch.HasCaught());
18852 5 : v8::Local<v8::Message> message = try_catch.Message();
18853 5 : CHECK(!message.IsEmpty());
18854 10 : CHECK_EQ(1, message->GetLineNumber(context).FromJust());
18855 5 : context->Exit();
18856 : }
18857 5 : isolate->ContextDisposedNotification();
18858 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
18859 5 : other_context->Enter();
18860 : CompileRun(source_exception);
18861 5 : other_context->Exit();
18862 5 : CcTest::CollectAllGarbage();
18863 5 : if (GetGlobalObjectsCount() == 1) break;
18864 : }
18865 5 : CHECK_GE(2, gc_count);
18866 5 : CHECK_EQ(1, GetGlobalObjectsCount());
18867 :
18868 5 : isolate->ContextDisposedNotification();
18869 5 : }
18870 :
18871 :
18872 26645 : THREADED_TEST(ScriptOrigin) {
18873 6 : LocalContext env;
18874 6 : v8::Isolate* isolate = env->GetIsolate();
18875 12 : v8::HandleScope scope(isolate);
18876 6 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 1));
18877 6 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
18878 6 : array->Set(isolate, 0, symbol);
18879 :
18880 : v8::ScriptOrigin origin = v8::ScriptOrigin(
18881 : v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
18882 : v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
18883 : v8::Local<v8::Integer>(), v8_str("http://sourceMapUrl"),
18884 : v8::True(env->GetIsolate()), v8::False(env->GetIsolate()),
18885 42 : v8::False(env->GetIsolate()), array);
18886 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
18887 6 : v8::Script::Compile(env.local(), script, &origin)
18888 : .ToLocalChecked()
18889 6 : ->Run(env.local())
18890 : .ToLocalChecked();
18891 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18892 24 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18893 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18894 24 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18895 :
18896 6 : v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18897 6 : CHECK_EQ(0, strcmp("test",
18898 : *v8::String::Utf8Value(env->GetIsolate(),
18899 : script_origin_f.ResourceName())));
18900 12 : CHECK_EQ(
18901 : 1,
18902 : script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18903 6 : CHECK(script_origin_f.Options().IsSharedCrossOrigin());
18904 6 : CHECK(script_origin_f.Options().IsOpaque());
18905 6 : printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
18906 12 : CHECK(script_origin_f.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18907 :
18908 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
18909 : *v8::String::Utf8Value(env->GetIsolate(),
18910 : script_origin_f.SourceMapUrl())));
18911 :
18912 6 : v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18913 6 : CHECK_EQ(0, strcmp("test",
18914 : *v8::String::Utf8Value(env->GetIsolate(),
18915 : script_origin_g.ResourceName())));
18916 12 : CHECK_EQ(
18917 : 1,
18918 : script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18919 6 : CHECK(script_origin_g.Options().IsSharedCrossOrigin());
18920 6 : CHECK(script_origin_g.Options().IsOpaque());
18921 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
18922 : *v8::String::Utf8Value(env->GetIsolate(),
18923 : script_origin_g.SourceMapUrl())));
18924 12 : CHECK(script_origin_g.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18925 6 : }
18926 :
18927 :
18928 26645 : THREADED_TEST(FunctionGetInferredName) {
18929 6 : LocalContext env;
18930 12 : v8::HandleScope scope(env->GetIsolate());
18931 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18932 : v8::Local<v8::String> script =
18933 6 : v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18934 6 : v8::Script::Compile(env.local(), script, &origin)
18935 : .ToLocalChecked()
18936 6 : ->Run(env.local())
18937 : .ToLocalChecked();
18938 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18939 24 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18940 12 : CHECK_EQ(0,
18941 : strcmp("foo.bar.baz", *v8::String::Utf8Value(env->GetIsolate(),
18942 : f->GetInferredName())));
18943 6 : }
18944 :
18945 :
18946 26645 : THREADED_TEST(FunctionGetDebugName) {
18947 6 : LocalContext env;
18948 6 : v8::Isolate* isolate = env->GetIsolate();
18949 12 : v8::HandleScope scope(isolate);
18950 : const char* code =
18951 : "var error = false;"
18952 : "function a() { this.x = 1; };"
18953 : "a.displayName = 'display_a';"
18954 : "var b = (function() {"
18955 : " var f = function() { this.x = 2; };"
18956 : " f.displayName = 'display_b';"
18957 : " return f;"
18958 : "})();"
18959 : "var c = function() {};"
18960 : "c.__defineGetter__('displayName', function() {"
18961 : " error = true;"
18962 : " throw new Error();"
18963 : "});"
18964 : "function d() {};"
18965 : "d.__defineGetter__('displayName', function() {"
18966 : " error = true;"
18967 : " return 'wrong_display_name';"
18968 : "});"
18969 : "function e() {};"
18970 : "e.displayName = 'wrong_display_name';"
18971 : "e.__defineSetter__('displayName', function() {"
18972 : " error = true;"
18973 : " throw new Error();"
18974 : "});"
18975 : "function f() {};"
18976 : "f.displayName = { 'foo': 6, toString: function() {"
18977 : " error = true;"
18978 : " return 'wrong_display_name';"
18979 : "}};"
18980 : "var g = function() {"
18981 : " arguments.callee.displayName = 'set_in_runtime';"
18982 : "}; g();"
18983 : "var h = function() {};"
18984 : "h.displayName = 'displayName';"
18985 : "Object.defineProperty(h, 'name', { value: 'function.name' });"
18986 : "var i = function() {};"
18987 : "i.displayName = 239;"
18988 : "Object.defineProperty(i, 'name', { value: 'function.name' });"
18989 : "var j = function() {};"
18990 : "Object.defineProperty(j, 'name', { value: 'function.name' });"
18991 : "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
18992 : "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
18993 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18994 12 : v8::Script::Compile(env.local(), v8_str(code), &origin)
18995 : .ToLocalChecked()
18996 6 : ->Run(env.local())
18997 : .ToLocalChecked();
18998 : v8::Local<v8::Value> error =
18999 24 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19000 6 : CHECK(!error->BooleanValue(isolate));
19001 : const char* functions[] = {"a", "display_a",
19002 : "b", "display_b",
19003 : "c", "c",
19004 : "d", "d",
19005 : "e", "e",
19006 : "f", "f",
19007 : "g", "set_in_runtime",
19008 : "h", "displayName",
19009 : "i", "function.name",
19010 : "j", "function.name",
19011 : "k", "foo.bar.baz",
19012 6 : "l", "baz"};
19013 150 : for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
19014 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19015 144 : env->Global()
19016 72 : ->Get(env.local(),
19017 144 : v8::String::NewFromUtf8(isolate, functions[i * 2],
19018 72 : v8::NewStringType::kNormal)
19019 72 : .ToLocalChecked())
19020 : .ToLocalChecked());
19021 72 : CHECK_EQ(0, strcmp(functions[i * 2 + 1],
19022 : *v8::String::Utf8Value(isolate, f->GetDebugName())));
19023 : }
19024 6 : }
19025 :
19026 :
19027 26645 : THREADED_TEST(FunctionGetDisplayName) {
19028 6 : LocalContext env;
19029 6 : v8::Isolate* isolate = env->GetIsolate();
19030 12 : v8::HandleScope scope(isolate);
19031 : const char* code = "var error = false;"
19032 : "function a() { this.x = 1; };"
19033 : "a.displayName = 'display_a';"
19034 : "var b = (function() {"
19035 : " var f = function() { this.x = 2; };"
19036 : " f.displayName = 'display_b';"
19037 : " return f;"
19038 : "})();"
19039 : "var c = function() {};"
19040 : "c.__defineGetter__('displayName', function() {"
19041 : " error = true;"
19042 : " throw new Error();"
19043 : "});"
19044 : "function d() {};"
19045 : "d.__defineGetter__('displayName', function() {"
19046 : " error = true;"
19047 : " return 'wrong_display_name';"
19048 : "});"
19049 : "function e() {};"
19050 : "e.displayName = 'wrong_display_name';"
19051 : "e.__defineSetter__('displayName', function() {"
19052 : " error = true;"
19053 : " throw new Error();"
19054 : "});"
19055 : "function f() {};"
19056 : "f.displayName = { 'foo': 6, toString: function() {"
19057 : " error = true;"
19058 : " return 'wrong_display_name';"
19059 : "}};"
19060 : "var g = function() {"
19061 : " arguments.callee.displayName = 'set_in_runtime';"
19062 : "}; g();";
19063 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19064 12 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19065 : .ToLocalChecked()
19066 6 : ->Run(env.local())
19067 : .ToLocalChecked();
19068 : v8::Local<v8::Value> error =
19069 24 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19070 : v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19071 24 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
19072 : v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19073 24 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
19074 : v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19075 24 : env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
19076 : v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19077 24 : env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
19078 : v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19079 24 : env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
19080 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19081 24 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19082 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19083 24 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19084 6 : CHECK(!error->BooleanValue(isolate));
19085 6 : CHECK_EQ(0, strcmp("display_a",
19086 : *v8::String::Utf8Value(isolate, a->GetDisplayName())));
19087 6 : CHECK_EQ(0, strcmp("display_b",
19088 : *v8::String::Utf8Value(isolate, b->GetDisplayName())));
19089 12 : CHECK(c->GetDisplayName()->IsUndefined());
19090 12 : CHECK(d->GetDisplayName()->IsUndefined());
19091 12 : CHECK(e->GetDisplayName()->IsUndefined());
19092 12 : CHECK(f->GetDisplayName()->IsUndefined());
19093 6 : CHECK_EQ(0, strcmp("set_in_runtime",
19094 : *v8::String::Utf8Value(isolate, g->GetDisplayName())));
19095 6 : }
19096 :
19097 :
19098 26645 : THREADED_TEST(ScriptLineNumber) {
19099 6 : LocalContext env;
19100 12 : v8::HandleScope scope(env->GetIsolate());
19101 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19102 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19103 6 : v8::Script::Compile(env.local(), script, &origin)
19104 : .ToLocalChecked()
19105 6 : ->Run(env.local())
19106 : .ToLocalChecked();
19107 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19108 24 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19109 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19110 24 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19111 6 : CHECK_EQ(0, f->GetScriptLineNumber());
19112 6 : CHECK_EQ(2, g->GetScriptLineNumber());
19113 6 : }
19114 :
19115 :
19116 26645 : THREADED_TEST(ScriptColumnNumber) {
19117 6 : LocalContext env;
19118 6 : v8::Isolate* isolate = env->GetIsolate();
19119 12 : v8::HandleScope scope(isolate);
19120 : v8::ScriptOrigin origin =
19121 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19122 6 : v8::Integer::New(isolate, 2));
19123 : v8::Local<v8::String> script =
19124 6 : v8_str("function foo() {}\n\n function bar() {}");
19125 6 : v8::Script::Compile(env.local(), script, &origin)
19126 : .ToLocalChecked()
19127 6 : ->Run(env.local())
19128 : .ToLocalChecked();
19129 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19130 24 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19131 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19132 24 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19133 6 : CHECK_EQ(14, foo->GetScriptColumnNumber());
19134 6 : CHECK_EQ(17, bar->GetScriptColumnNumber());
19135 6 : }
19136 :
19137 :
19138 26645 : THREADED_TEST(FunctionGetScriptId) {
19139 6 : LocalContext env;
19140 6 : v8::Isolate* isolate = env->GetIsolate();
19141 12 : v8::HandleScope scope(isolate);
19142 : v8::ScriptOrigin origin =
19143 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19144 6 : v8::Integer::New(isolate, 2));
19145 : v8::Local<v8::String> scriptSource =
19146 6 : v8_str("function foo() {}\n\n function bar() {}");
19147 : v8::Local<v8::Script> script(
19148 6 : v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
19149 6 : script->Run(env.local()).ToLocalChecked();
19150 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19151 24 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19152 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19153 24 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19154 12 : CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19155 12 : CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19156 6 : }
19157 :
19158 :
19159 26645 : THREADED_TEST(FunctionGetBoundFunction) {
19160 6 : LocalContext env;
19161 12 : v8::HandleScope scope(env->GetIsolate());
19162 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19163 : v8::Local<v8::String> script = v8_str(
19164 : "var a = new Object();\n"
19165 : "a.x = 1;\n"
19166 : "function f () { return this.x };\n"
19167 : "var g = f.bind(a);\n"
19168 6 : "var b = g();");
19169 6 : v8::Script::Compile(env.local(), script, &origin)
19170 : .ToLocalChecked()
19171 6 : ->Run(env.local())
19172 : .ToLocalChecked();
19173 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19174 24 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19175 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19176 24 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19177 12 : CHECK(g->GetBoundFunction()->IsFunction());
19178 : Local<v8::Function> original_function = Local<v8::Function>::Cast(
19179 6 : g->GetBoundFunction());
19180 24 : CHECK(f->GetName()
19181 : ->Equals(env.local(), original_function->GetName())
19182 : .FromJust());
19183 6 : CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19184 6 : CHECK_EQ(f->GetScriptColumnNumber(),
19185 : original_function->GetScriptColumnNumber());
19186 6 : }
19187 :
19188 :
19189 330 : static void GetterWhichReturns42(
19190 : Local<String> name,
19191 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19192 330 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19193 330 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19194 330 : info.GetReturnValue().Set(v8_num(42));
19195 330 : }
19196 :
19197 :
19198 270 : static void SetterWhichSetsYOnThisTo23(
19199 : Local<String> name,
19200 : Local<Value> value,
19201 : const v8::PropertyCallbackInfo<void>& info) {
19202 270 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19203 270 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19204 : Local<Object>::Cast(info.This())
19205 1080 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19206 : .FromJust();
19207 270 : }
19208 :
19209 :
19210 120 : void FooGetInterceptor(Local<Name> name,
19211 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19212 120 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19213 120 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19214 480 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19215 : .FromJust()) {
19216 : return;
19217 : }
19218 96 : info.GetReturnValue().Set(v8_num(42));
19219 : }
19220 :
19221 :
19222 336 : void FooSetInterceptor(Local<Name> name, Local<Value> value,
19223 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19224 336 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19225 336 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19226 1344 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19227 : .FromJust()) {
19228 : return;
19229 : }
19230 : Local<Object>::Cast(info.This())
19231 384 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19232 : .FromJust();
19233 96 : info.GetReturnValue().Set(v8_num(23));
19234 : }
19235 :
19236 :
19237 26644 : TEST(SetterOnConstructorPrototype) {
19238 5 : v8::Isolate* isolate = CcTest::isolate();
19239 10 : v8::HandleScope scope(isolate);
19240 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19241 10 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19242 5 : SetterWhichSetsYOnThisTo23);
19243 5 : LocalContext context;
19244 25 : CHECK(context->Global()
19245 : ->Set(context.local(), v8_str("P"),
19246 : templ->NewInstance(context.local()).ToLocalChecked())
19247 : .FromJust());
19248 : CompileRun("function C1() {"
19249 : " this.x = 23;"
19250 : "};"
19251 : "C1.prototype = P;"
19252 : "function C2() {"
19253 : " this.x = 23"
19254 : "};"
19255 : "C2.prototype = { };"
19256 : "C2.prototype.__proto__ = P;");
19257 :
19258 : v8::Local<v8::Script> script;
19259 : script = v8_compile("new C1();");
19260 105 : for (int i = 0; i < 10; i++) {
19261 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19262 50 : script->Run(context.local()).ToLocalChecked());
19263 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19264 : .ToLocalChecked()
19265 : ->Int32Value(context.local())
19266 : .FromJust());
19267 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19268 : .ToLocalChecked()
19269 : ->Int32Value(context.local())
19270 : .FromJust());
19271 : }
19272 :
19273 : script = v8_compile("new C2();");
19274 105 : for (int i = 0; i < 10; i++) {
19275 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19276 50 : script->Run(context.local()).ToLocalChecked());
19277 200 : CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
19278 : .ToLocalChecked()
19279 : ->Int32Value(context.local())
19280 : .FromJust());
19281 200 : CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
19282 : .ToLocalChecked()
19283 : ->Int32Value(context.local())
19284 : .FromJust());
19285 : }
19286 5 : }
19287 :
19288 :
19289 0 : static void NamedPropertySetterWhichSetsYOnThisTo23(
19290 : Local<Name> name, Local<Value> value,
19291 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19292 0 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
19293 : .FromJust()) {
19294 : Local<Object>::Cast(info.This())
19295 0 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19296 : .FromJust();
19297 : }
19298 0 : }
19299 :
19300 :
19301 26645 : THREADED_TEST(InterceptorOnConstructorPrototype) {
19302 6 : v8::Isolate* isolate = CcTest::isolate();
19303 12 : v8::HandleScope scope(isolate);
19304 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19305 6 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19306 : NamedPropertyGetterWhichReturns42,
19307 6 : NamedPropertySetterWhichSetsYOnThisTo23));
19308 6 : LocalContext context;
19309 30 : CHECK(context->Global()
19310 : ->Set(context.local(), v8_str("P"),
19311 : templ->NewInstance(context.local()).ToLocalChecked())
19312 : .FromJust());
19313 : CompileRun("function C1() {"
19314 : " this.x = 23;"
19315 : "};"
19316 : "C1.prototype = P;"
19317 : "function C2() {"
19318 : " this.x = 23"
19319 : "};"
19320 : "C2.prototype = { };"
19321 : "C2.prototype.__proto__ = P;");
19322 :
19323 : v8::Local<v8::Script> script;
19324 : script = v8_compile("new C1();");
19325 126 : for (int i = 0; i < 10; i++) {
19326 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19327 60 : script->Run(context.local()).ToLocalChecked());
19328 240 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19329 : .ToLocalChecked()
19330 : ->Int32Value(context.local())
19331 : .FromJust());
19332 240 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19333 : .ToLocalChecked()
19334 : ->Int32Value(context.local())
19335 : .FromJust());
19336 : }
19337 :
19338 : script = v8_compile("new C2();");
19339 126 : for (int i = 0; i < 10; i++) {
19340 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19341 60 : script->Run(context.local()).ToLocalChecked());
19342 240 : CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
19343 : .ToLocalChecked()
19344 : ->Int32Value(context.local())
19345 : .FromJust());
19346 240 : CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
19347 : .ToLocalChecked()
19348 : ->Int32Value(context.local())
19349 : .FromJust());
19350 : }
19351 6 : }
19352 :
19353 :
19354 26644 : TEST(Regress618) {
19355 : const char* source = "function C1() {"
19356 : " this.x = 23;"
19357 : "};"
19358 : "C1.prototype = P;";
19359 :
19360 5 : LocalContext context;
19361 5 : v8::Isolate* isolate = context->GetIsolate();
19362 10 : v8::HandleScope scope(isolate);
19363 : v8::Local<v8::Script> script;
19364 :
19365 : // Use a simple object as prototype.
19366 5 : v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19367 15 : prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
19368 20 : CHECK(context->Global()
19369 : ->Set(context.local(), v8_str("P"), prototype)
19370 : .FromJust());
19371 :
19372 : // This compile will add the code to the compilation cache.
19373 : CompileRun(source);
19374 :
19375 : script = v8_compile("new C1();");
19376 : // Allow enough iterations for the inobject slack tracking logic
19377 : // to finalize instance size and install the fast construct stub.
19378 2565 : for (int i = 0; i < 256; i++) {
19379 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19380 1280 : script->Run(context.local()).ToLocalChecked());
19381 5120 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19382 : .ToLocalChecked()
19383 : ->Int32Value(context.local())
19384 : .FromJust());
19385 5120 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19386 : .ToLocalChecked()
19387 : ->Int32Value(context.local())
19388 : .FromJust());
19389 : }
19390 :
19391 : // Use an API object with accessors as prototype.
19392 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19393 10 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19394 5 : SetterWhichSetsYOnThisTo23);
19395 25 : CHECK(context->Global()
19396 : ->Set(context.local(), v8_str("P"),
19397 : templ->NewInstance(context.local()).ToLocalChecked())
19398 : .FromJust());
19399 :
19400 : // This compile will get the code from the compilation cache.
19401 : CompileRun(source);
19402 :
19403 : script = v8_compile("new C1();");
19404 105 : for (int i = 0; i < 10; i++) {
19405 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19406 50 : script->Run(context.local()).ToLocalChecked());
19407 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19408 : .ToLocalChecked()
19409 : ->Int32Value(context.local())
19410 : .FromJust());
19411 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19412 : .ToLocalChecked()
19413 : ->Int32Value(context.local())
19414 : .FromJust());
19415 : }
19416 5 : }
19417 :
19418 : v8::Isolate* gc_callbacks_isolate = nullptr;
19419 : int prologue_call_count = 0;
19420 : int epilogue_call_count = 0;
19421 : int prologue_call_count_second = 0;
19422 : int epilogue_call_count_second = 0;
19423 : int prologue_call_count_alloc = 0;
19424 : int epilogue_call_count_alloc = 0;
19425 :
19426 20 : void PrologueCallback(v8::Isolate* isolate,
19427 : v8::GCType,
19428 : v8::GCCallbackFlags flags) {
19429 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19430 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19431 20 : ++prologue_call_count;
19432 20 : }
19433 :
19434 20 : void EpilogueCallback(v8::Isolate* isolate,
19435 : v8::GCType,
19436 : v8::GCCallbackFlags flags) {
19437 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19438 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19439 20 : ++epilogue_call_count;
19440 20 : }
19441 :
19442 :
19443 20 : void PrologueCallbackSecond(v8::Isolate* isolate,
19444 : v8::GCType,
19445 : v8::GCCallbackFlags flags) {
19446 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19447 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19448 20 : ++prologue_call_count_second;
19449 20 : }
19450 :
19451 :
19452 20 : void EpilogueCallbackSecond(v8::Isolate* isolate,
19453 : v8::GCType,
19454 : v8::GCCallbackFlags flags) {
19455 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19456 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19457 20 : ++epilogue_call_count_second;
19458 20 : }
19459 :
19460 20 : void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
19461 : v8::GCCallbackFlags flags, void* data) {
19462 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19463 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19464 20 : ++*static_cast<int*>(data);
19465 20 : }
19466 :
19467 20 : void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
19468 : v8::GCCallbackFlags flags, void* data) {
19469 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19470 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19471 20 : ++*static_cast<int*>(data);
19472 20 : }
19473 :
19474 5 : void PrologueCallbackAlloc(v8::Isolate* isolate,
19475 : v8::GCType,
19476 : v8::GCCallbackFlags flags) {
19477 10 : v8::HandleScope scope(isolate);
19478 :
19479 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19480 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19481 5 : ++prologue_call_count_alloc;
19482 :
19483 : // Simulate full heap to see if we will reenter this callback
19484 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19485 :
19486 5 : Local<Object> obj = Object::New(isolate);
19487 5 : CHECK(!obj.IsEmpty());
19488 :
19489 5 : CcTest::PreciseCollectAllGarbage();
19490 5 : }
19491 :
19492 :
19493 5 : void EpilogueCallbackAlloc(v8::Isolate* isolate,
19494 : v8::GCType,
19495 : v8::GCCallbackFlags flags) {
19496 10 : v8::HandleScope scope(isolate);
19497 :
19498 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19499 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19500 5 : ++epilogue_call_count_alloc;
19501 :
19502 : // Simulate full heap to see if we will reenter this callback
19503 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19504 :
19505 5 : Local<Object> obj = Object::New(isolate);
19506 5 : CHECK(!obj.IsEmpty());
19507 :
19508 5 : CcTest::PreciseCollectAllGarbage();
19509 5 : }
19510 :
19511 :
19512 26644 : TEST(GCCallbacksOld) {
19513 5 : LocalContext context;
19514 :
19515 5 : gc_callbacks_isolate = context->GetIsolate();
19516 :
19517 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
19518 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
19519 5 : CHECK_EQ(0, prologue_call_count);
19520 5 : CHECK_EQ(0, epilogue_call_count);
19521 5 : CcTest::CollectAllGarbage();
19522 5 : CHECK_EQ(1, prologue_call_count);
19523 5 : CHECK_EQ(1, epilogue_call_count);
19524 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
19525 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
19526 5 : CcTest::CollectAllGarbage();
19527 5 : CHECK_EQ(2, prologue_call_count);
19528 5 : CHECK_EQ(2, epilogue_call_count);
19529 5 : CHECK_EQ(1, prologue_call_count_second);
19530 5 : CHECK_EQ(1, epilogue_call_count_second);
19531 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
19532 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
19533 5 : CcTest::CollectAllGarbage();
19534 5 : CHECK_EQ(2, prologue_call_count);
19535 5 : CHECK_EQ(2, epilogue_call_count);
19536 5 : CHECK_EQ(2, prologue_call_count_second);
19537 5 : CHECK_EQ(2, epilogue_call_count_second);
19538 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
19539 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19540 5 : CcTest::CollectAllGarbage();
19541 5 : CHECK_EQ(2, prologue_call_count);
19542 5 : CHECK_EQ(2, epilogue_call_count);
19543 5 : CHECK_EQ(2, prologue_call_count_second);
19544 5 : CHECK_EQ(2, epilogue_call_count_second);
19545 5 : }
19546 :
19547 26644 : TEST(GCCallbacksWithData) {
19548 5 : LocalContext context;
19549 :
19550 5 : gc_callbacks_isolate = context->GetIsolate();
19551 5 : int prologue1 = 0;
19552 5 : int epilogue1 = 0;
19553 5 : int prologue2 = 0;
19554 5 : int epilogue2 = 0;
19555 :
19556 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
19557 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
19558 5 : CHECK_EQ(0, prologue1);
19559 5 : CHECK_EQ(0, epilogue1);
19560 5 : CHECK_EQ(0, prologue2);
19561 5 : CHECK_EQ(0, epilogue2);
19562 5 : CcTest::CollectAllGarbage();
19563 5 : CHECK_EQ(1, prologue1);
19564 5 : CHECK_EQ(1, epilogue1);
19565 5 : CHECK_EQ(0, prologue2);
19566 5 : CHECK_EQ(0, epilogue2);
19567 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
19568 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
19569 5 : CcTest::CollectAllGarbage();
19570 5 : CHECK_EQ(2, prologue1);
19571 5 : CHECK_EQ(2, epilogue1);
19572 5 : CHECK_EQ(1, prologue2);
19573 5 : CHECK_EQ(1, epilogue2);
19574 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19575 5 : &prologue1);
19576 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19577 5 : &epilogue1);
19578 5 : CcTest::CollectAllGarbage();
19579 5 : CHECK_EQ(2, prologue1);
19580 5 : CHECK_EQ(2, epilogue1);
19581 5 : CHECK_EQ(2, prologue2);
19582 5 : CHECK_EQ(2, epilogue2);
19583 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19584 5 : &prologue2);
19585 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19586 5 : &epilogue2);
19587 5 : CcTest::CollectAllGarbage();
19588 5 : CHECK_EQ(2, prologue1);
19589 5 : CHECK_EQ(2, epilogue1);
19590 5 : CHECK_EQ(2, prologue2);
19591 5 : CHECK_EQ(2, epilogue2);
19592 5 : }
19593 :
19594 26644 : TEST(GCCallbacks) {
19595 5 : LocalContext context;
19596 5 : v8::Isolate* isolate = context->GetIsolate();
19597 5 : gc_callbacks_isolate = isolate;
19598 5 : isolate->AddGCPrologueCallback(PrologueCallback);
19599 5 : isolate->AddGCEpilogueCallback(EpilogueCallback);
19600 5 : CHECK_EQ(0, prologue_call_count);
19601 5 : CHECK_EQ(0, epilogue_call_count);
19602 5 : CcTest::CollectAllGarbage();
19603 5 : CHECK_EQ(1, prologue_call_count);
19604 5 : CHECK_EQ(1, epilogue_call_count);
19605 5 : isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19606 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19607 5 : CcTest::CollectAllGarbage();
19608 5 : CHECK_EQ(2, prologue_call_count);
19609 5 : CHECK_EQ(2, epilogue_call_count);
19610 5 : CHECK_EQ(1, prologue_call_count_second);
19611 5 : CHECK_EQ(1, epilogue_call_count_second);
19612 5 : isolate->RemoveGCPrologueCallback(PrologueCallback);
19613 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19614 5 : CcTest::CollectAllGarbage();
19615 5 : CHECK_EQ(2, prologue_call_count);
19616 5 : CHECK_EQ(2, epilogue_call_count);
19617 5 : CHECK_EQ(2, prologue_call_count_second);
19618 5 : CHECK_EQ(2, epilogue_call_count_second);
19619 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19620 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19621 5 : CcTest::CollectAllGarbage();
19622 5 : CHECK_EQ(2, prologue_call_count);
19623 5 : CHECK_EQ(2, epilogue_call_count);
19624 5 : CHECK_EQ(2, prologue_call_count_second);
19625 5 : CHECK_EQ(2, epilogue_call_count_second);
19626 :
19627 5 : CHECK_EQ(0, prologue_call_count_alloc);
19628 5 : CHECK_EQ(0, epilogue_call_count_alloc);
19629 5 : isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19630 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19631 5 : CcTest::PreciseCollectAllGarbage();
19632 5 : CHECK_EQ(1, prologue_call_count_alloc);
19633 5 : CHECK_EQ(1, epilogue_call_count_alloc);
19634 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19635 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19636 5 : }
19637 :
19638 :
19639 26645 : THREADED_TEST(TwoByteStringInOneByteCons) {
19640 : // See Chromium issue 47824.
19641 6 : LocalContext context;
19642 12 : v8::HandleScope scope(context->GetIsolate());
19643 :
19644 : const char* init_code =
19645 : "var str1 = 'abelspendabel';"
19646 : "var str2 = str1 + str1 + str1;"
19647 : "str2;";
19648 : Local<Value> result = CompileRun(init_code);
19649 :
19650 6 : Local<Value> indexof = CompileRun("str2.indexOf('els')");
19651 6 : Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19652 :
19653 6 : CHECK(result->IsString());
19654 : i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19655 : int length = string->length();
19656 6 : CHECK(string->IsOneByteRepresentation());
19657 :
19658 6 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
19659 6 : i::Handle<i::String> flat_string = i::String::Flatten(i_isolate, string);
19660 :
19661 6 : CHECK(string->IsOneByteRepresentation());
19662 6 : CHECK(flat_string->IsOneByteRepresentation());
19663 :
19664 : // Create external resource.
19665 6 : uint16_t* uc16_buffer = new uint16_t[length + 1];
19666 :
19667 6 : i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19668 6 : uc16_buffer[length] = 0;
19669 :
19670 6 : TestResource resource(uc16_buffer);
19671 :
19672 6 : flat_string->MakeExternal(&resource);
19673 :
19674 6 : CHECK(flat_string->IsTwoByteRepresentation());
19675 :
19676 : // If the cons string has been short-circuited, skip the following checks.
19677 6 : if (!string.is_identical_to(flat_string)) {
19678 : // At this point, we should have a Cons string which is flat and one-byte,
19679 : // with a first half that is a two-byte string (although it only contains
19680 : // one-byte characters). This is a valid sequence of steps, and it can
19681 : // happen in real pages.
19682 6 : CHECK(string->IsOneByteRepresentation());
19683 : i::ConsString cons = i::ConsString::cast(*string);
19684 6 : CHECK_EQ(0, cons->second()->length());
19685 6 : CHECK(cons->first()->IsTwoByteRepresentation());
19686 : }
19687 :
19688 : // Check that some string operations work.
19689 :
19690 : // Atom RegExp.
19691 : Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19692 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19693 :
19694 : // Nonatom RegExp.
19695 : reresult = CompileRun("str2.match(/abe./g).length;");
19696 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19697 :
19698 : reresult = CompileRun("str2.search(/bel/g);");
19699 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19700 :
19701 : reresult = CompileRun("str2.search(/be./g);");
19702 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19703 :
19704 : ExpectTrue("/bel/g.test(str2);");
19705 :
19706 : ExpectTrue("/be./g.test(str2);");
19707 :
19708 : reresult = CompileRun("/bel/g.exec(str2);");
19709 6 : CHECK(!reresult->IsNull());
19710 :
19711 : reresult = CompileRun("/be./g.exec(str2);");
19712 6 : CHECK(!reresult->IsNull());
19713 :
19714 6 : ExpectString("str2.substring(2, 10);", "elspenda");
19715 :
19716 6 : ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19717 :
19718 6 : ExpectString("str2.charAt(2);", "e");
19719 :
19720 6 : ExpectObject("str2.indexOf('els');", indexof);
19721 :
19722 6 : ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19723 :
19724 : reresult = CompileRun("str2.charCodeAt(2);");
19725 12 : CHECK_EQ(static_cast<int32_t>('e'),
19726 : reresult->Int32Value(context.local()).FromJust());
19727 : // This avoids the GC from trying to free stack allocated resources.
19728 : i::Handle<i::ExternalTwoByteString>::cast(flat_string)
19729 6 : ->SetResource(i_isolate, nullptr);
19730 6 : }
19731 :
19732 :
19733 26644 : TEST(ContainsOnlyOneByte) {
19734 5 : v8::V8::Initialize();
19735 5 : v8::Isolate* isolate = CcTest::isolate();
19736 10 : v8::HandleScope scope(isolate);
19737 : // Make a buffer long enough that it won't automatically be converted.
19738 : const int length = 512;
19739 : // Ensure word aligned assignment.
19740 : const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19741 5 : std::unique_ptr<uintptr_t[]> aligned_contents(new uintptr_t[aligned_length]);
19742 : uint16_t* string_contents =
19743 : reinterpret_cast<uint16_t*>(aligned_contents.get());
19744 : // Set to contain only one byte.
19745 5115 : for (int i = 0; i < length-1; i++) {
19746 2555 : string_contents[i] = 0x41;
19747 : }
19748 5 : string_contents[length-1] = 0;
19749 : // Simple case.
19750 : Local<String> string =
19751 5 : String::NewExternalTwoByte(
19752 5 : isolate, new TestResource(string_contents, nullptr, false))
19753 : .ToLocalChecked();
19754 5 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19755 : // Counter example.
19756 5 : string = String::NewFromTwoByte(isolate, string_contents,
19757 : v8::NewStringType::kNormal)
19758 : .ToLocalChecked();
19759 5 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19760 : // Test left right and balanced cons strings.
19761 5 : Local<String> base = v8_str("a");
19762 5 : Local<String> left = base;
19763 5 : Local<String> right = base;
19764 10005 : for (int i = 0; i < 1000; i++) {
19765 5000 : left = String::Concat(isolate, base, left);
19766 5000 : right = String::Concat(isolate, right, base);
19767 : }
19768 5 : Local<String> balanced = String::Concat(isolate, left, base);
19769 5 : balanced = String::Concat(isolate, balanced, right);
19770 5 : Local<String> cons_strings[] = {left, balanced, right};
19771 : Local<String> two_byte =
19772 5 : String::NewExternalTwoByte(
19773 5 : isolate, new TestResource(string_contents, nullptr, false))
19774 5 : .ToLocalChecked();
19775 : USE(two_byte); USE(cons_strings);
19776 35 : for (size_t i = 0; i < arraysize(cons_strings); i++) {
19777 : // Base assumptions.
19778 15 : string = cons_strings[i];
19779 15 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19780 : // Test left and right concatentation.
19781 15 : string = String::Concat(isolate, two_byte, cons_strings[i]);
19782 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19783 15 : string = String::Concat(isolate, cons_strings[i], two_byte);
19784 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19785 : }
19786 : // Set bits in different positions
19787 : // for strings of different lengths and alignments.
19788 75 : for (int alignment = 0; alignment < 7; alignment++) {
19789 595 : for (int size = 2; alignment + size < length; size *= 2) {
19790 : int zero_offset = size + alignment;
19791 280 : string_contents[zero_offset] = 0;
19792 35980 : for (int i = 0; i < size; i++) {
19793 17850 : int shift = 8 + (i % 7);
19794 17850 : string_contents[alignment + i] = 1 << shift;
19795 17850 : string = String::NewExternalTwoByte(
19796 : isolate, new TestResource(string_contents + alignment,
19797 17850 : nullptr, false))
19798 : .ToLocalChecked();
19799 17850 : CHECK_EQ(size, string->Length());
19800 17850 : CHECK(!string->ContainsOnlyOneByte());
19801 17850 : string_contents[alignment + i] = 0x41;
19802 : }
19803 280 : string_contents[zero_offset] = 0x41;
19804 : }
19805 : }
19806 5 : }
19807 :
19808 :
19809 : // Failed access check callback that performs a GC on each invocation.
19810 75 : void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19811 : v8::AccessType type,
19812 : Local<v8::Value> data) {
19813 75 : CcTest::CollectAllGarbage();
19814 : CcTest::isolate()->ThrowException(
19815 75 : v8::Exception::Error(v8_str("cross context")));
19816 75 : }
19817 :
19818 :
19819 26644 : TEST(GCInFailedAccessCheckCallback) {
19820 : // Install a failed access check callback that performs a GC on each
19821 : // invocation. Then force the callback to be called from va
19822 :
19823 5 : v8::V8::Initialize();
19824 5 : v8::Isolate* isolate = CcTest::isolate();
19825 :
19826 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19827 :
19828 10 : v8::HandleScope scope(isolate);
19829 :
19830 : // Create an ObjectTemplate for global objects and install access
19831 : // check callbacks that will block access.
19832 : v8::Local<v8::ObjectTemplate> global_template =
19833 5 : v8::ObjectTemplate::New(isolate);
19834 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
19835 :
19836 : // Create a context and set an x property on it's global object.
19837 5 : LocalContext context0(nullptr, global_template);
19838 20 : CHECK(context0->Global()
19839 : ->Set(context0.local(), v8_str("x"), v8_num(42))
19840 : .FromJust());
19841 5 : v8::Local<v8::Object> global0 = context0->Global();
19842 :
19843 : // Create a context with a different security token so that the
19844 : // failed access check callback will be called on each access.
19845 5 : LocalContext context1(nullptr, global_template);
19846 20 : CHECK(context1->Global()
19847 : ->Set(context1.local(), v8_str("other"), global0)
19848 : .FromJust());
19849 :
19850 10 : v8::TryCatch try_catch(isolate);
19851 :
19852 : // Get property with failed access check.
19853 5 : CHECK(CompileRun("other.x").IsEmpty());
19854 5 : CHECK(try_catch.HasCaught());
19855 5 : try_catch.Reset();
19856 :
19857 : // Get element with failed access check.
19858 5 : CHECK(CompileRun("other[0]").IsEmpty());
19859 5 : CHECK(try_catch.HasCaught());
19860 5 : try_catch.Reset();
19861 :
19862 : // Set property with failed access check.
19863 5 : CHECK(CompileRun("other.x = new Object()").IsEmpty());
19864 5 : CHECK(try_catch.HasCaught());
19865 5 : try_catch.Reset();
19866 :
19867 : // Set element with failed access check.
19868 5 : CHECK(CompileRun("other[0] = new Object()").IsEmpty());
19869 5 : CHECK(try_catch.HasCaught());
19870 5 : try_catch.Reset();
19871 :
19872 : // Get property attribute with failed access check.
19873 5 : CHECK(CompileRun("\'x\' in other").IsEmpty());
19874 5 : CHECK(try_catch.HasCaught());
19875 5 : try_catch.Reset();
19876 :
19877 : // Get property attribute for element with failed access check.
19878 5 : CHECK(CompileRun("0 in other").IsEmpty());
19879 5 : CHECK(try_catch.HasCaught());
19880 5 : try_catch.Reset();
19881 :
19882 : // Delete property.
19883 5 : CHECK(CompileRun("delete other.x").IsEmpty());
19884 5 : CHECK(try_catch.HasCaught());
19885 5 : try_catch.Reset();
19886 :
19887 : // Delete element.
19888 10 : CHECK(global0->Delete(context1.local(), 0).IsNothing());
19889 5 : CHECK(try_catch.HasCaught());
19890 5 : try_catch.Reset();
19891 :
19892 : // DefineAccessor.
19893 20 : CHECK(global0
19894 : ->SetAccessor(context1.local(), v8_str("x"), GetXValue, nullptr,
19895 : v8_str("x"))
19896 : .IsNothing());
19897 5 : CHECK(try_catch.HasCaught());
19898 5 : try_catch.Reset();
19899 :
19900 : // Define JavaScript accessor.
19901 5 : CHECK(CompileRun(
19902 : "Object.prototype.__defineGetter__.call("
19903 : " other, \'x\', function() { return 42; })").IsEmpty());
19904 5 : CHECK(try_catch.HasCaught());
19905 5 : try_catch.Reset();
19906 :
19907 : // LookupAccessor.
19908 5 : CHECK(CompileRun(
19909 : "Object.prototype.__lookupGetter__.call("
19910 : " other, \'x\')").IsEmpty());
19911 5 : CHECK(try_catch.HasCaught());
19912 5 : try_catch.Reset();
19913 :
19914 : // HasOwnElement.
19915 5 : CHECK(CompileRun(
19916 : "Object.prototype.hasOwnProperty.call("
19917 : "other, \'0\')").IsEmpty());
19918 5 : CHECK(try_catch.HasCaught());
19919 5 : try_catch.Reset();
19920 :
19921 10 : CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
19922 5 : CHECK(try_catch.HasCaught());
19923 5 : try_catch.Reset();
19924 :
19925 15 : CHECK(
19926 : global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
19927 5 : CHECK(try_catch.HasCaught());
19928 5 : try_catch.Reset();
19929 :
19930 15 : CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
19931 : .IsNothing());
19932 5 : CHECK(try_catch.HasCaught());
19933 5 : try_catch.Reset();
19934 :
19935 : // Reset the failed access check callback so it does not influence
19936 : // the other tests.
19937 5 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
19938 5 : }
19939 :
19940 :
19941 26644 : TEST(IsolateNewDispose) {
19942 5 : v8::Isolate* current_isolate = CcTest::isolate();
19943 : v8::Isolate::CreateParams create_params;
19944 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19945 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
19946 5 : CHECK_NOT_NULL(isolate);
19947 5 : CHECK(current_isolate != isolate);
19948 5 : CHECK(current_isolate == CcTest::isolate());
19949 10 : CHECK(isolate->GetArrayBufferAllocator() == CcTest::array_buffer_allocator());
19950 :
19951 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
19952 5 : last_location = last_message = nullptr;
19953 5 : isolate->Dispose();
19954 5 : CHECK(!last_location);
19955 5 : CHECK(!last_message);
19956 5 : }
19957 :
19958 :
19959 26644 : UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19960 : v8::Isolate::CreateParams create_params;
19961 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19962 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
19963 : {
19964 : v8::Isolate::Scope i_scope(isolate);
19965 10 : v8::HandleScope scope(isolate);
19966 5 : LocalContext context(isolate);
19967 : // Run something in this isolate.
19968 : ExpectTrue("true");
19969 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
19970 5 : last_location = last_message = nullptr;
19971 : // Still entered, should fail.
19972 5 : isolate->Dispose();
19973 5 : CHECK(last_location);
19974 5 : CHECK(last_message);
19975 : }
19976 5 : isolate->Dispose();
19977 5 : }
19978 :
19979 :
19980 40 : static void BreakArrayGuarantees(const char* script) {
19981 : v8::Isolate::CreateParams create_params;
19982 40 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19983 40 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
19984 40 : isolate1->Enter();
19985 : v8::Persistent<v8::Context> context1;
19986 : {
19987 80 : v8::HandleScope scope(isolate1);
19988 80 : context1.Reset(isolate1, Context::New(isolate1));
19989 : }
19990 :
19991 : {
19992 80 : v8::HandleScope scope(isolate1);
19993 : v8::Local<v8::Context> context =
19994 : v8::Local<v8::Context>::New(isolate1, context1);
19995 : v8::Context::Scope context_scope(context);
19996 : v8::internal::Isolate* i_isolate =
19997 : reinterpret_cast<v8::internal::Isolate*>(isolate1);
19998 40 : CHECK(i_isolate->IsNoElementsProtectorIntact());
19999 : // Run something in new isolate.
20000 : CompileRun(script);
20001 40 : CHECK(!i_isolate->IsNoElementsProtectorIntact());
20002 : }
20003 40 : isolate1->Exit();
20004 40 : isolate1->Dispose();
20005 40 : }
20006 :
20007 :
20008 26644 : TEST(VerifyArrayPrototypeGuarantees) {
20009 : // Break fast array hole handling by element changes.
20010 5 : BreakArrayGuarantees("[].__proto__[1] = 3;");
20011 5 : BreakArrayGuarantees("Object.prototype[3] = 'three';");
20012 5 : BreakArrayGuarantees("Array.prototype.push(1);");
20013 5 : BreakArrayGuarantees("Array.prototype.unshift(1);");
20014 : // Break fast array hole handling by changing length.
20015 5 : BreakArrayGuarantees("Array.prototype.length = 30;");
20016 : // Break fast array hole handling by prototype structure changes.
20017 5 : BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
20018 : // By sending elements to dictionary mode.
20019 : BreakArrayGuarantees(
20020 : "Object.defineProperty(Array.prototype, 0, {"
20021 5 : " get: function() { return 3; }});");
20022 : BreakArrayGuarantees(
20023 : "Object.defineProperty(Object.prototype, 0, {"
20024 5 : " get: function() { return 3; }});");
20025 5 : }
20026 :
20027 :
20028 26644 : TEST(RunTwoIsolatesOnSingleThread) {
20029 : // Run isolate 1.
20030 : v8::Isolate::CreateParams create_params;
20031 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20032 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20033 5 : isolate1->Enter();
20034 : v8::Persistent<v8::Context> context1;
20035 : {
20036 10 : v8::HandleScope scope(isolate1);
20037 10 : context1.Reset(isolate1, Context::New(isolate1));
20038 : }
20039 :
20040 : {
20041 10 : v8::HandleScope scope(isolate1);
20042 : v8::Local<v8::Context> context =
20043 : v8::Local<v8::Context>::New(isolate1, context1);
20044 : v8::Context::Scope context_scope(context);
20045 : // Run something in new isolate.
20046 : CompileRun("var foo = 'isolate 1';");
20047 5 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20048 : }
20049 :
20050 : // Run isolate 2.
20051 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
20052 : v8::Persistent<v8::Context> context2;
20053 :
20054 : {
20055 : v8::Isolate::Scope iscope(isolate2);
20056 10 : v8::HandleScope scope(isolate2);
20057 10 : context2.Reset(isolate2, Context::New(isolate2));
20058 : v8::Local<v8::Context> context =
20059 : v8::Local<v8::Context>::New(isolate2, context2);
20060 : v8::Context::Scope context_scope(context);
20061 :
20062 : // Run something in new isolate.
20063 : CompileRun("var foo = 'isolate 2';");
20064 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20065 : }
20066 :
20067 : {
20068 10 : v8::HandleScope scope(isolate1);
20069 : v8::Local<v8::Context> context =
20070 : v8::Local<v8::Context>::New(isolate1, context1);
20071 : v8::Context::Scope context_scope(context);
20072 : // Now again in isolate 1
20073 5 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20074 : }
20075 :
20076 5 : isolate1->Exit();
20077 :
20078 : // Run some stuff in default isolate.
20079 : v8::Persistent<v8::Context> context_default;
20080 : {
20081 5 : v8::Isolate* isolate = CcTest::isolate();
20082 : v8::Isolate::Scope iscope(isolate);
20083 10 : v8::HandleScope scope(isolate);
20084 10 : context_default.Reset(isolate, Context::New(isolate));
20085 : }
20086 :
20087 : {
20088 10 : v8::HandleScope scope(CcTest::isolate());
20089 : v8::Local<v8::Context> context =
20090 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20091 : v8::Context::Scope context_scope(context);
20092 : // Variables in other isolates should be not available, verify there
20093 : // is an exception.
20094 : ExpectTrue("function f() {"
20095 : " try {"
20096 : " foo;"
20097 : " return false;"
20098 : " } catch(e) {"
20099 : " return true;"
20100 : " }"
20101 : "};"
20102 : "var isDefaultIsolate = true;"
20103 : "f()");
20104 : }
20105 :
20106 5 : isolate1->Enter();
20107 :
20108 : {
20109 : v8::Isolate::Scope iscope(isolate2);
20110 10 : v8::HandleScope scope(isolate2);
20111 : v8::Local<v8::Context> context =
20112 : v8::Local<v8::Context>::New(isolate2, context2);
20113 : v8::Context::Scope context_scope(context);
20114 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20115 : }
20116 :
20117 : {
20118 10 : v8::HandleScope scope(v8::Isolate::GetCurrent());
20119 : v8::Local<v8::Context> context =
20120 5 : v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20121 : v8::Context::Scope context_scope(context);
20122 5 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20123 : }
20124 :
20125 : {
20126 : v8::Isolate::Scope iscope(isolate2);
20127 : context2.Reset();
20128 : }
20129 :
20130 : context1.Reset();
20131 5 : isolate1->Exit();
20132 :
20133 5 : isolate2->SetFatalErrorHandler(StoringErrorCallback);
20134 5 : last_location = last_message = nullptr;
20135 :
20136 5 : isolate1->Dispose();
20137 5 : CHECK(!last_location);
20138 5 : CHECK(!last_message);
20139 :
20140 5 : isolate2->Dispose();
20141 5 : CHECK(!last_location);
20142 5 : CHECK(!last_message);
20143 :
20144 : // Check that default isolate still runs.
20145 : {
20146 10 : v8::HandleScope scope(CcTest::isolate());
20147 : v8::Local<v8::Context> context =
20148 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20149 : v8::Context::Scope context_scope(context);
20150 : ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20151 : }
20152 5 : }
20153 :
20154 :
20155 20 : static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20156 : v8::Isolate::Scope isolate_scope(isolate);
20157 39 : v8::HandleScope scope(isolate);
20158 20 : LocalContext context(isolate);
20159 : i::ScopedVector<char> code(1024);
20160 : i::SNPrintF(code, "function fib(n) {"
20161 : " if (n <= 2) return 1;"
20162 : " return fib(n-1) + fib(n-2);"
20163 : "}"
20164 20 : "fib(%d)", limit);
20165 : Local<Value> value = CompileRun(code.start());
20166 20 : CHECK(value->IsNumber());
20167 60 : return static_cast<int>(value->NumberValue(context.local()).FromJust());
20168 : }
20169 :
20170 5 : class IsolateThread : public v8::base::Thread {
20171 : public:
20172 : explicit IsolateThread(int fib_limit)
20173 10 : : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20174 :
20175 10 : void Run() override {
20176 : v8::Isolate::CreateParams create_params;
20177 10 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20178 10 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20179 10 : result_ = CalcFibonacci(isolate, fib_limit_);
20180 10 : isolate->Dispose();
20181 10 : }
20182 :
20183 : int result() { return result_; }
20184 :
20185 : private:
20186 : int fib_limit_;
20187 : int result_;
20188 : };
20189 :
20190 :
20191 26644 : TEST(MultipleIsolatesOnIndividualThreads) {
20192 : IsolateThread thread1(21);
20193 : IsolateThread thread2(12);
20194 :
20195 : // Compute some fibonacci numbers on 3 threads in 3 isolates.
20196 5 : thread1.Start();
20197 5 : thread2.Start();
20198 :
20199 5 : int result1 = CalcFibonacci(CcTest::isolate(), 21);
20200 5 : int result2 = CalcFibonacci(CcTest::isolate(), 12);
20201 :
20202 5 : thread1.Join();
20203 5 : thread2.Join();
20204 :
20205 : // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20206 : // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20207 5 : CHECK_EQ(result1, 10946);
20208 5 : CHECK_EQ(result2, 144);
20209 5 : CHECK_EQ(result1, thread1.result());
20210 5 : CHECK_EQ(result2, thread2.result());
20211 5 : }
20212 :
20213 :
20214 26644 : TEST(IsolateDifferentContexts) {
20215 : v8::Isolate::CreateParams create_params;
20216 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20217 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20218 : Local<v8::Context> context;
20219 : {
20220 : v8::Isolate::Scope isolate_scope(isolate);
20221 10 : v8::HandleScope handle_scope(isolate);
20222 5 : context = v8::Context::New(isolate);
20223 : v8::Context::Scope context_scope(context);
20224 : Local<Value> v = CompileRun("2");
20225 5 : CHECK(v->IsNumber());
20226 10 : CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
20227 : }
20228 : {
20229 : v8::Isolate::Scope isolate_scope(isolate);
20230 10 : v8::HandleScope handle_scope(isolate);
20231 5 : context = v8::Context::New(isolate);
20232 : v8::Context::Scope context_scope(context);
20233 : Local<Value> v = CompileRun("22");
20234 5 : CHECK(v->IsNumber());
20235 10 : CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
20236 : }
20237 5 : isolate->Dispose();
20238 5 : }
20239 :
20240 20 : class InitDefaultIsolateThread : public v8::base::Thread {
20241 : public:
20242 : enum TestCase {
20243 : SetFatalHandler,
20244 : SetCounterFunction,
20245 : SetCreateHistogramFunction,
20246 : SetAddHistogramSampleFunction
20247 : };
20248 :
20249 : explicit InitDefaultIsolateThread(TestCase testCase)
20250 : : Thread(Options("InitDefaultIsolateThread")),
20251 : testCase_(testCase),
20252 20 : result_(false) {}
20253 :
20254 20 : void Run() override {
20255 : v8::Isolate::CreateParams create_params;
20256 20 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20257 20 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20258 20 : isolate->Enter();
20259 20 : switch (testCase_) {
20260 : case SetFatalHandler:
20261 5 : isolate->SetFatalErrorHandler(nullptr);
20262 5 : break;
20263 :
20264 : case SetCounterFunction:
20265 5 : CcTest::isolate()->SetCounterFunction(nullptr);
20266 5 : break;
20267 :
20268 : case SetCreateHistogramFunction:
20269 5 : CcTest::isolate()->SetCreateHistogramFunction(nullptr);
20270 5 : break;
20271 :
20272 : case SetAddHistogramSampleFunction:
20273 5 : CcTest::isolate()->SetAddHistogramSampleFunction(nullptr);
20274 5 : break;
20275 : }
20276 20 : isolate->Exit();
20277 20 : isolate->Dispose();
20278 20 : result_ = true;
20279 20 : }
20280 :
20281 : bool result() { return result_; }
20282 :
20283 : private:
20284 : TestCase testCase_;
20285 : bool result_;
20286 : };
20287 :
20288 :
20289 20 : static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20290 : InitDefaultIsolateThread thread(testCase);
20291 20 : thread.Start();
20292 20 : thread.Join();
20293 20 : CHECK(thread.result());
20294 20 : }
20295 :
20296 26644 : TEST(InitializeDefaultIsolateOnSecondaryThread_FatalHandler) {
20297 5 : InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20298 5 : }
20299 :
20300 26644 : TEST(InitializeDefaultIsolateOnSecondaryThread_CounterFunction) {
20301 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20302 5 : }
20303 :
20304 26644 : TEST(InitializeDefaultIsolateOnSecondaryThread_CreateHistogramFunction) {
20305 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20306 5 : }
20307 :
20308 26644 : TEST(InitializeDefaultIsolateOnSecondaryThread_AddHistogramSampleFunction) {
20309 5 : InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20310 5 : }
20311 :
20312 :
20313 26644 : TEST(StringCheckMultipleContexts) {
20314 : const char* code =
20315 : "(function() { return \"a\".charAt(0); })()";
20316 :
20317 : {
20318 : // Run the code twice in the first context to initialize the call IC.
20319 5 : LocalContext context1;
20320 10 : v8::HandleScope scope(context1->GetIsolate());
20321 5 : ExpectString(code, "a");
20322 5 : ExpectString(code, "a");
20323 : }
20324 :
20325 : {
20326 : // Change the String.prototype in the second context and check
20327 : // that the right function gets called.
20328 5 : LocalContext context2;
20329 10 : v8::HandleScope scope(context2->GetIsolate());
20330 : CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20331 5 : ExpectString(code, "not a");
20332 : }
20333 5 : }
20334 :
20335 :
20336 26644 : TEST(NumberCheckMultipleContexts) {
20337 : const char* code =
20338 : "(function() { return (42).toString(); })()";
20339 :
20340 : {
20341 : // Run the code twice in the first context to initialize the call IC.
20342 5 : LocalContext context1;
20343 10 : v8::HandleScope scope(context1->GetIsolate());
20344 5 : ExpectString(code, "42");
20345 5 : ExpectString(code, "42");
20346 : }
20347 :
20348 : {
20349 : // Change the Number.prototype in the second context and check
20350 : // that the right function gets called.
20351 5 : LocalContext context2;
20352 10 : v8::HandleScope scope(context2->GetIsolate());
20353 : CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20354 5 : ExpectString(code, "not 42");
20355 : }
20356 5 : }
20357 :
20358 :
20359 26644 : TEST(BooleanCheckMultipleContexts) {
20360 : const char* code =
20361 : "(function() { return true.toString(); })()";
20362 :
20363 : {
20364 : // Run the code twice in the first context to initialize the call IC.
20365 5 : LocalContext context1;
20366 10 : v8::HandleScope scope(context1->GetIsolate());
20367 5 : ExpectString(code, "true");
20368 5 : ExpectString(code, "true");
20369 : }
20370 :
20371 : {
20372 : // Change the Boolean.prototype in the second context and check
20373 : // that the right function gets called.
20374 5 : LocalContext context2;
20375 10 : v8::HandleScope scope(context2->GetIsolate());
20376 : CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20377 5 : ExpectString(code, "");
20378 : }
20379 5 : }
20380 :
20381 :
20382 26644 : TEST(DontDeleteCellLoadIC) {
20383 : const char* function_code =
20384 : "function readCell() { while (true) { return cell; } }";
20385 :
20386 : {
20387 : // Run the code twice in the first context to initialize the load
20388 : // IC for a don't delete cell.
20389 5 : LocalContext context1;
20390 10 : v8::HandleScope scope(context1->GetIsolate());
20391 : CompileRun("var cell = \"first\";");
20392 5 : ExpectBoolean("delete cell", false);
20393 : CompileRun(function_code);
20394 5 : ExpectString("readCell()", "first");
20395 5 : ExpectString("readCell()", "first");
20396 : }
20397 :
20398 : {
20399 : // Use a deletable cell in the second context.
20400 5 : LocalContext context2;
20401 10 : v8::HandleScope scope(context2->GetIsolate());
20402 : CompileRun("cell = \"second\";");
20403 : CompileRun(function_code);
20404 5 : ExpectString("readCell()", "second");
20405 5 : ExpectBoolean("delete cell", true);
20406 : ExpectString("(function() {"
20407 : " try {"
20408 : " return readCell();"
20409 : " } catch(e) {"
20410 : " return e.toString();"
20411 : " }"
20412 : "})()",
20413 5 : "ReferenceError: cell is not defined");
20414 : CompileRun("cell = \"new_second\";");
20415 5 : CcTest::CollectAllGarbage();
20416 5 : ExpectString("readCell()", "new_second");
20417 5 : ExpectString("readCell()", "new_second");
20418 : }
20419 5 : }
20420 :
20421 :
20422 10 : class Visitor42 : public v8::PersistentHandleVisitor {
20423 : public:
20424 : explicit Visitor42(v8::Persistent<v8::Object>* object)
20425 5 : : counter_(0), object_(object) { }
20426 :
20427 5 : void VisitPersistentHandle(Persistent<Value>* value,
20428 : uint16_t class_id) override {
20429 5 : if (class_id != 42) return;
20430 5 : CHECK_EQ(42, value->WrapperClassId());
20431 5 : v8::Isolate* isolate = CcTest::isolate();
20432 10 : v8::HandleScope handle_scope(isolate);
20433 : v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20434 5 : v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
20435 5 : CHECK(handle->IsObject());
20436 10 : CHECK(Local<Object>::Cast(handle)
20437 : ->Equals(isolate->GetCurrentContext(), object)
20438 : .FromJust());
20439 5 : ++counter_;
20440 : }
20441 :
20442 : int counter_;
20443 : v8::Persistent<v8::Object>* object_;
20444 : };
20445 :
20446 :
20447 26644 : TEST(PersistentHandleVisitor) {
20448 5 : LocalContext context;
20449 5 : v8::Isolate* isolate = context->GetIsolate();
20450 10 : v8::HandleScope scope(isolate);
20451 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20452 5 : CHECK_EQ(0, object.WrapperClassId());
20453 : object.SetWrapperClassId(42);
20454 5 : CHECK_EQ(42, object.WrapperClassId());
20455 :
20456 : Visitor42 visitor(&object);
20457 5 : isolate->VisitHandlesWithClassIds(&visitor);
20458 5 : CHECK_EQ(1, visitor.counter_);
20459 :
20460 : object.Reset();
20461 5 : }
20462 :
20463 :
20464 26644 : TEST(WrapperClassId) {
20465 5 : LocalContext context;
20466 5 : v8::Isolate* isolate = context->GetIsolate();
20467 10 : v8::HandleScope scope(isolate);
20468 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20469 5 : CHECK_EQ(0, object.WrapperClassId());
20470 : object.SetWrapperClassId(65535);
20471 5 : CHECK_EQ(65535, object.WrapperClassId());
20472 : object.Reset();
20473 5 : }
20474 :
20475 26644 : TEST(RegExp) {
20476 5 : LocalContext context;
20477 10 : v8::HandleScope scope(context->GetIsolate());
20478 :
20479 : v8::Local<v8::RegExp> re =
20480 10 : v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
20481 : .ToLocalChecked();
20482 5 : CHECK(re->IsRegExp());
20483 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
20484 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20485 :
20486 5 : re = v8::RegExp::New(context.local(), v8_str("bar"),
20487 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20488 5 : v8::RegExp::kGlobal))
20489 : .ToLocalChecked();
20490 5 : CHECK(re->IsRegExp());
20491 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
20492 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20493 : static_cast<int>(re->GetFlags()));
20494 :
20495 5 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20496 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20497 5 : v8::RegExp::kMultiline))
20498 : .ToLocalChecked();
20499 5 : CHECK(re->IsRegExp());
20500 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20501 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20502 : static_cast<int>(re->GetFlags()));
20503 :
20504 5 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20505 : static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
20506 5 : v8::RegExp::kSticky))
20507 : .ToLocalChecked();
20508 5 : CHECK(re->IsRegExp());
20509 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20510 5 : CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
20511 : static_cast<int>(re->GetFlags()));
20512 :
20513 : re = CompileRun("/quux/").As<v8::RegExp>();
20514 5 : CHECK(re->IsRegExp());
20515 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20516 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20517 :
20518 : re = CompileRun("/quux/gm").As<v8::RegExp>();
20519 5 : CHECK(re->IsRegExp());
20520 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20521 5 : CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20522 : static_cast<int>(re->GetFlags()));
20523 :
20524 : // Override the RegExp constructor and check the API constructor
20525 : // still works.
20526 : CompileRun("RegExp = function() {}");
20527 :
20528 10 : re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
20529 : .ToLocalChecked();
20530 5 : CHECK(re->IsRegExp());
20531 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
20532 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20533 :
20534 5 : re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
20535 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20536 5 : v8::RegExp::kMultiline))
20537 : .ToLocalChecked();
20538 5 : CHECK(re->IsRegExp());
20539 20 : CHECK(
20540 : re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
20541 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20542 : static_cast<int>(re->GetFlags()));
20543 :
20544 20 : CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
20545 : ExpectTrue("re.test('FoobarbaZ')");
20546 :
20547 : // RegExps are objects on which you can set properties.
20548 10 : re->Set(context.local(), v8_str("property"),
20549 15 : v8::Integer::New(context->GetIsolate(), 32))
20550 : .FromJust();
20551 : v8::Local<v8::Value> value(CompileRun("re.property"));
20552 10 : CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
20553 :
20554 10 : v8::TryCatch try_catch(context->GetIsolate());
20555 15 : CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
20556 : .IsEmpty());
20557 5 : CHECK(try_catch.HasCaught());
20558 20 : CHECK(context->Global()
20559 : ->Set(context.local(), v8_str("ex"), try_catch.Exception())
20560 : .FromJust());
20561 : ExpectTrue("ex instanceof SyntaxError");
20562 5 : }
20563 :
20564 :
20565 26645 : THREADED_TEST(Equals) {
20566 6 : LocalContext localContext;
20567 12 : v8::HandleScope handleScope(localContext->GetIsolate());
20568 :
20569 6 : v8::Local<v8::Object> globalProxy = localContext->Global();
20570 6 : v8::Local<Value> global = globalProxy->GetPrototype();
20571 :
20572 6 : CHECK(global->StrictEquals(global));
20573 6 : CHECK(!global->StrictEquals(globalProxy));
20574 6 : CHECK(!globalProxy->StrictEquals(global));
20575 6 : CHECK(globalProxy->StrictEquals(globalProxy));
20576 :
20577 12 : CHECK(global->Equals(localContext.local(), global).FromJust());
20578 12 : CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
20579 12 : CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
20580 12 : CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
20581 6 : }
20582 :
20583 :
20584 5 : static void Getter(v8::Local<v8::Name> property,
20585 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20586 5 : info.GetReturnValue().Set(v8_str("42!"));
20587 5 : }
20588 :
20589 :
20590 5 : static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20591 5 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
20592 10 : result->Set(info.GetIsolate()->GetCurrentContext(), 0,
20593 15 : v8_str("universalAnswer"))
20594 : .FromJust();
20595 : info.GetReturnValue().Set(result);
20596 5 : }
20597 :
20598 :
20599 26644 : TEST(NamedEnumeratorAndForIn) {
20600 5 : LocalContext context;
20601 5 : v8::Isolate* isolate = context->GetIsolate();
20602 10 : v8::HandleScope handle_scope(isolate);
20603 : v8::Context::Scope context_scope(context.local());
20604 :
20605 5 : v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20606 5 : tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
20607 5 : Getter, nullptr, nullptr, nullptr, Enumerator));
20608 25 : CHECK(context->Global()
20609 : ->Set(context.local(), v8_str("o"),
20610 : tmpl->NewInstance(context.local()).ToLocalChecked())
20611 : .FromJust());
20612 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
20613 : CompileRun("var result = []; for (var k in o) result.push(k); result"));
20614 5 : CHECK_EQ(1u, result->Length());
20615 20 : CHECK(v8_str("universalAnswer")
20616 : ->Equals(context.local(),
20617 : result->Get(context.local(), 0).ToLocalChecked())
20618 : .FromJust());
20619 5 : }
20620 :
20621 :
20622 26644 : TEST(DefinePropertyPostDetach) {
20623 5 : LocalContext context;
20624 10 : v8::HandleScope scope(context->GetIsolate());
20625 5 : v8::Local<v8::Object> proxy = context->Global();
20626 : v8::Local<v8::Function> define_property =
20627 : CompileRun(
20628 : "(function() {"
20629 : " Object.defineProperty("
20630 : " this,"
20631 : " 1,"
20632 : " { configurable: true, enumerable: true, value: 3 });"
20633 : "})")
20634 : .As<Function>();
20635 5 : context->DetachGlobal();
20636 10 : CHECK(define_property->Call(context.local(), proxy, 0, nullptr).IsEmpty());
20637 5 : }
20638 :
20639 :
20640 36 : static void InstallContextId(v8::Local<Context> context, int id) {
20641 : Context::Scope scope(context);
20642 144 : CHECK(CompileRun("Object.prototype")
20643 : .As<Object>()
20644 : ->Set(context, v8_str("context_id"),
20645 : v8::Integer::New(context->GetIsolate(), id))
20646 : .FromJust());
20647 36 : }
20648 :
20649 :
20650 126 : static void CheckContextId(v8::Local<Object> object, int expected) {
20651 126 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20652 504 : CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
20653 : .ToLocalChecked()
20654 : ->Int32Value(context)
20655 : .FromJust());
20656 126 : }
20657 :
20658 :
20659 26645 : THREADED_TEST(CreationContext) {
20660 6 : v8::Isolate* isolate = CcTest::isolate();
20661 12 : HandleScope handle_scope(isolate);
20662 6 : Local<Context> context1 = Context::New(isolate);
20663 6 : InstallContextId(context1, 1);
20664 6 : Local<Context> context2 = Context::New(isolate);
20665 6 : InstallContextId(context2, 2);
20666 6 : Local<Context> context3 = Context::New(isolate);
20667 6 : InstallContextId(context3, 3);
20668 :
20669 6 : Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20670 :
20671 : Local<Object> object1;
20672 : Local<Function> func1;
20673 : {
20674 : Context::Scope scope(context1);
20675 6 : object1 = Object::New(isolate);
20676 6 : func1 = tmpl->GetFunction(context1).ToLocalChecked();
20677 : }
20678 :
20679 : Local<Object> object2;
20680 : Local<Function> func2;
20681 : {
20682 : Context::Scope scope(context2);
20683 6 : object2 = Object::New(isolate);
20684 6 : func2 = tmpl->GetFunction(context2).ToLocalChecked();
20685 : }
20686 :
20687 : Local<Object> instance1;
20688 : Local<Object> instance2;
20689 :
20690 : {
20691 : Context::Scope scope(context3);
20692 : instance1 = func1->NewInstance(context3).ToLocalChecked();
20693 : instance2 = func2->NewInstance(context3).ToLocalChecked();
20694 : }
20695 :
20696 : {
20697 6 : Local<Context> other_context = Context::New(isolate);
20698 : Context::Scope scope(other_context);
20699 12 : CHECK(object1->CreationContext() == context1);
20700 6 : CheckContextId(object1, 1);
20701 12 : CHECK(func1->CreationContext() == context1);
20702 6 : CheckContextId(func1, 1);
20703 12 : CHECK(instance1->CreationContext() == context1);
20704 6 : CheckContextId(instance1, 1);
20705 12 : CHECK(object2->CreationContext() == context2);
20706 6 : CheckContextId(object2, 2);
20707 12 : CHECK(func2->CreationContext() == context2);
20708 6 : CheckContextId(func2, 2);
20709 12 : CHECK(instance2->CreationContext() == context2);
20710 6 : CheckContextId(instance2, 2);
20711 : }
20712 :
20713 : {
20714 : Context::Scope scope(context1);
20715 12 : CHECK(object1->CreationContext() == context1);
20716 6 : CheckContextId(object1, 1);
20717 12 : CHECK(func1->CreationContext() == context1);
20718 6 : CheckContextId(func1, 1);
20719 12 : CHECK(instance1->CreationContext() == context1);
20720 6 : CheckContextId(instance1, 1);
20721 12 : CHECK(object2->CreationContext() == context2);
20722 6 : CheckContextId(object2, 2);
20723 12 : CHECK(func2->CreationContext() == context2);
20724 6 : CheckContextId(func2, 2);
20725 12 : CHECK(instance2->CreationContext() == context2);
20726 6 : CheckContextId(instance2, 2);
20727 : }
20728 :
20729 : {
20730 : Context::Scope scope(context2);
20731 12 : CHECK(object1->CreationContext() == context1);
20732 6 : CheckContextId(object1, 1);
20733 12 : CHECK(func1->CreationContext() == context1);
20734 6 : CheckContextId(func1, 1);
20735 12 : CHECK(instance1->CreationContext() == context1);
20736 6 : CheckContextId(instance1, 1);
20737 12 : CHECK(object2->CreationContext() == context2);
20738 6 : CheckContextId(object2, 2);
20739 12 : CHECK(func2->CreationContext() == context2);
20740 6 : CheckContextId(func2, 2);
20741 12 : CHECK(instance2->CreationContext() == context2);
20742 6 : CheckContextId(instance2, 2);
20743 : }
20744 6 : }
20745 :
20746 :
20747 26645 : THREADED_TEST(CreationContextOfJsFunction) {
20748 12 : HandleScope handle_scope(CcTest::isolate());
20749 6 : Local<Context> context = Context::New(CcTest::isolate());
20750 6 : InstallContextId(context, 1);
20751 :
20752 : Local<Object> function;
20753 : {
20754 : Context::Scope scope(context);
20755 : function = CompileRun("function foo() {}; foo").As<Object>();
20756 : }
20757 :
20758 6 : Local<Context> other_context = Context::New(CcTest::isolate());
20759 : Context::Scope scope(other_context);
20760 12 : CHECK(function->CreationContext() == context);
20761 6 : CheckContextId(function, 1);
20762 6 : }
20763 :
20764 :
20765 26645 : THREADED_TEST(CreationContextOfJsBoundFunction) {
20766 12 : HandleScope handle_scope(CcTest::isolate());
20767 6 : Local<Context> context1 = Context::New(CcTest::isolate());
20768 6 : InstallContextId(context1, 1);
20769 6 : Local<Context> context2 = Context::New(CcTest::isolate());
20770 6 : InstallContextId(context2, 2);
20771 :
20772 : Local<Function> target_function;
20773 : {
20774 : Context::Scope scope(context1);
20775 : target_function = CompileRun("function foo() {}; foo").As<Function>();
20776 : }
20777 :
20778 : Local<Function> bound_function1, bound_function2;
20779 : {
20780 : Context::Scope scope(context2);
20781 24 : CHECK(context2->Global()
20782 : ->Set(context2, v8_str("foo"), target_function)
20783 : .FromJust());
20784 : bound_function1 = CompileRun("foo.bind(1)").As<Function>();
20785 : bound_function2 =
20786 : CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
20787 : }
20788 :
20789 6 : Local<Context> other_context = Context::New(CcTest::isolate());
20790 : Context::Scope scope(other_context);
20791 12 : CHECK(bound_function1->CreationContext() == context1);
20792 6 : CheckContextId(bound_function1, 1);
20793 12 : CHECK(bound_function2->CreationContext() == context1);
20794 6 : CheckContextId(bound_function2, 1);
20795 6 : }
20796 :
20797 :
20798 20 : void HasOwnPropertyIndexedPropertyGetter(
20799 : uint32_t index,
20800 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20801 20 : if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20802 20 : }
20803 :
20804 :
20805 10 : void HasOwnPropertyNamedPropertyGetter(
20806 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20807 40 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20808 : .FromJust()) {
20809 5 : info.GetReturnValue().Set(v8_str("yes"));
20810 : }
20811 10 : }
20812 :
20813 :
20814 50 : void HasOwnPropertyIndexedPropertyQuery(
20815 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20816 50 : if (index == 42) info.GetReturnValue().Set(1);
20817 50 : }
20818 :
20819 :
20820 10 : void HasOwnPropertyNamedPropertyQuery(
20821 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20822 40 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20823 : .FromJust()) {
20824 : info.GetReturnValue().Set(1);
20825 : }
20826 10 : }
20827 :
20828 :
20829 10 : void HasOwnPropertyNamedPropertyQuery2(
20830 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20831 40 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
20832 : .FromJust()) {
20833 : info.GetReturnValue().Set(1);
20834 : }
20835 10 : }
20836 :
20837 0 : void HasOwnPropertyAccessorGetter(
20838 : Local<String> property,
20839 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20840 0 : info.GetReturnValue().Set(v8_str("yes"));
20841 0 : }
20842 :
20843 5 : void HasOwnPropertyAccessorNameGetter(
20844 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20845 5 : info.GetReturnValue().Set(v8_str("yes"));
20846 5 : }
20847 :
20848 26644 : TEST(HasOwnProperty) {
20849 5 : LocalContext env;
20850 5 : v8::Isolate* isolate = env->GetIsolate();
20851 10 : v8::HandleScope scope(isolate);
20852 : { // Check normal properties and defined getters.
20853 : Local<Value> value = CompileRun(
20854 : "function Foo() {"
20855 : " this.foo = 11;"
20856 : " this.__defineGetter__('baz', function() { return 1; });"
20857 : "};"
20858 : "function Bar() { "
20859 : " this.bar = 13;"
20860 : " this.__defineGetter__('bla', function() { return 2; });"
20861 : "};"
20862 : "Bar.prototype = new Foo();"
20863 : "new Bar();");
20864 5 : CHECK(value->IsObject());
20865 5 : Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
20866 15 : CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
20867 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20868 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20869 15 : CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
20870 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
20871 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
20872 : }
20873 : { // Check named getter interceptors.
20874 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20875 5 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20876 5 : HasOwnPropertyNamedPropertyGetter));
20877 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20878 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20879 10 : CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
20880 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20881 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20882 : }
20883 : { // Check indexed getter interceptors.
20884 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20885 5 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20886 5 : HasOwnPropertyIndexedPropertyGetter));
20887 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20888 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20889 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20890 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
20891 10 : CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
20892 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20893 : }
20894 : { // Check named query interceptors.
20895 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20896 5 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20897 5 : nullptr, nullptr, HasOwnPropertyNamedPropertyQuery));
20898 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20899 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20900 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20901 : }
20902 : { // Check indexed query interceptors.
20903 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20904 5 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20905 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
20906 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20907 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20908 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20909 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
20910 10 : CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
20911 : }
20912 : { // Check callbacks.
20913 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20914 5 : templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20915 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20916 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20917 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20918 : }
20919 : { // Check that query wins on disagreement.
20920 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20921 5 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20922 : HasOwnPropertyNamedPropertyGetter, nullptr,
20923 5 : HasOwnPropertyNamedPropertyQuery2));
20924 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20925 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20926 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20927 : }
20928 : { // Check that non-internalized keys are handled correctly.
20929 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20930 5 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20931 5 : HasOwnPropertyAccessorNameGetter));
20932 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20933 20 : env->Global()->Set(env.local(), v8_str("obj"), instance).FromJust();
20934 : const char* src =
20935 : "var dyn_string = 'this string ';"
20936 : "dyn_string += 'does not exist elsewhere';"
20937 : "({}).hasOwnProperty.call(obj, dyn_string)";
20938 5 : CHECK(CompileRun(src)->BooleanValue(isolate));
20939 : }
20940 5 : }
20941 :
20942 :
20943 26644 : TEST(IndexedInterceptorWithStringProto) {
20944 5 : v8::Isolate* isolate = CcTest::isolate();
20945 10 : v8::HandleScope scope(isolate);
20946 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20947 5 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20948 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
20949 5 : LocalContext context;
20950 25 : CHECK(context->Global()
20951 : ->Set(context.local(), v8_str("obj"),
20952 : templ->NewInstance(context.local()).ToLocalChecked())
20953 : .FromJust());
20954 : CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20955 : // These should be intercepted.
20956 5 : CHECK(CompileRun("42 in obj")->BooleanValue(isolate));
20957 5 : CHECK(CompileRun("'42' in obj")->BooleanValue(isolate));
20958 : // These should fall through to the String prototype.
20959 5 : CHECK(CompileRun("0 in obj")->BooleanValue(isolate));
20960 5 : CHECK(CompileRun("'0' in obj")->BooleanValue(isolate));
20961 : // And these should both fail.
20962 5 : CHECK(!CompileRun("32 in obj")->BooleanValue(isolate));
20963 5 : CHECK(!CompileRun("'32' in obj")->BooleanValue(isolate));
20964 5 : }
20965 :
20966 :
20967 18 : void CheckCodeGenerationAllowed() {
20968 18 : Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20969 : Local<Value> result = CompileRun("eval('42')");
20970 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
20971 : result = CompileRun("(function(e) { return e('42'); })(eval)");
20972 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
20973 : result = CompileRun("var f = new Function('return 42'); f()");
20974 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
20975 18 : }
20976 :
20977 :
20978 12 : void CheckCodeGenerationDisallowed() {
20979 24 : TryCatch try_catch(CcTest::isolate());
20980 :
20981 : Local<Value> result = CompileRun("eval('42')");
20982 12 : CHECK(result.IsEmpty());
20983 12 : CHECK(try_catch.HasCaught());
20984 12 : try_catch.Reset();
20985 :
20986 : result = CompileRun("(function(e) { return e('42'); })(eval)");
20987 12 : CHECK(result.IsEmpty());
20988 12 : CHECK(try_catch.HasCaught());
20989 12 : try_catch.Reset();
20990 :
20991 : result = CompileRun("var f = new Function('return 42'); f()");
20992 12 : CHECK(result.IsEmpty());
20993 12 : CHECK(try_catch.HasCaught());
20994 12 : }
20995 :
20996 : char first_fourty_bytes[41];
20997 :
20998 23 : bool CodeGenerationAllowed(Local<Context> context, Local<String> source) {
20999 46 : String::Utf8Value str(CcTest::isolate(), source);
21000 : size_t len = std::min(sizeof(first_fourty_bytes) - 1,
21001 46 : static_cast<size_t>(str.length()));
21002 : strncpy(first_fourty_bytes, *str, len);
21003 23 : first_fourty_bytes[len] = 0;
21004 23 : ApiTestFuzzer::Fuzz();
21005 23 : return true;
21006 : }
21007 :
21008 23 : bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) {
21009 23 : ApiTestFuzzer::Fuzz();
21010 23 : return false;
21011 : }
21012 :
21013 :
21014 26645 : THREADED_TEST(AllowCodeGenFromStrings) {
21015 6 : LocalContext context;
21016 12 : v8::HandleScope scope(context->GetIsolate());
21017 :
21018 : // eval and the Function constructor allowed by default.
21019 6 : CHECK(context->IsCodeGenerationFromStringsAllowed());
21020 6 : CheckCodeGenerationAllowed();
21021 :
21022 : // Disallow eval and the Function constructor.
21023 6 : context->AllowCodeGenerationFromStrings(false);
21024 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21025 6 : CheckCodeGenerationDisallowed();
21026 :
21027 : // Allow again.
21028 6 : context->AllowCodeGenerationFromStrings(true);
21029 6 : CheckCodeGenerationAllowed();
21030 :
21031 : // Disallow but setting a global callback that will allow the calls.
21032 6 : context->AllowCodeGenerationFromStrings(false);
21033 6 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21034 6 : &CodeGenerationAllowed);
21035 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21036 6 : CheckCodeGenerationAllowed();
21037 :
21038 : // Set a callback that disallows the code generation.
21039 6 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21040 6 : &CodeGenerationDisallowed);
21041 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21042 6 : CheckCodeGenerationDisallowed();
21043 6 : }
21044 :
21045 :
21046 26644 : TEST(SetErrorMessageForCodeGenFromStrings) {
21047 5 : LocalContext context;
21048 10 : v8::HandleScope scope(context->GetIsolate());
21049 10 : TryCatch try_catch(context->GetIsolate());
21050 :
21051 5 : Local<String> message = v8_str("Message");
21052 5 : Local<String> expected_message = v8_str("Uncaught EvalError: Message");
21053 5 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21054 5 : &CodeGenerationDisallowed);
21055 5 : context->AllowCodeGenerationFromStrings(false);
21056 5 : context->SetErrorMessageForCodeGenerationFromStrings(message);
21057 : Local<Value> result = CompileRun("eval('42')");
21058 5 : CHECK(result.IsEmpty());
21059 5 : CHECK(try_catch.HasCaught());
21060 10 : Local<String> actual_message = try_catch.Message()->Get();
21061 10 : CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
21062 5 : }
21063 :
21064 26644 : TEST(CaptureSourceForCodeGenFromStrings) {
21065 5 : LocalContext context;
21066 10 : v8::HandleScope scope(context->GetIsolate());
21067 10 : TryCatch try_catch(context->GetIsolate());
21068 :
21069 5 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21070 5 : &CodeGenerationAllowed);
21071 5 : context->AllowCodeGenerationFromStrings(false);
21072 : CompileRun("eval('42')");
21073 5 : CHECK(!strcmp(first_fourty_bytes, "42"));
21074 5 : }
21075 :
21076 6 : static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21077 6 : }
21078 :
21079 :
21080 26645 : THREADED_TEST(CallAPIFunctionOnNonObject) {
21081 6 : LocalContext context;
21082 6 : v8::Isolate* isolate = context->GetIsolate();
21083 12 : v8::HandleScope scope(isolate);
21084 : Local<FunctionTemplate> templ =
21085 6 : v8::FunctionTemplate::New(isolate, NonObjectThis);
21086 : Local<Function> function =
21087 6 : templ->GetFunction(context.local()).ToLocalChecked();
21088 24 : CHECK(context->Global()
21089 : ->Set(context.local(), v8_str("f"), function)
21090 : .FromJust());
21091 12 : TryCatch try_catch(isolate);
21092 : CompileRun("f.call(2)");
21093 6 : }
21094 :
21095 :
21096 : // Regression test for issue 1470.
21097 26645 : THREADED_TEST(ReadOnlyIndexedProperties) {
21098 6 : v8::Isolate* isolate = CcTest::isolate();
21099 12 : v8::HandleScope scope(isolate);
21100 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21101 :
21102 6 : LocalContext context;
21103 6 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
21104 24 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
21105 12 : obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
21106 18 : v8::ReadOnly)
21107 : .FromJust();
21108 24 : obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
21109 30 : CHECK(v8_str("DONT_CHANGE")
21110 : ->Equals(context.local(),
21111 : obj->Get(context.local(), v8_str("1")).ToLocalChecked())
21112 : .FromJust());
21113 12 : obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
21114 18 : v8::ReadOnly)
21115 : .FromJust();
21116 24 : obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
21117 30 : CHECK(v8_str("DONT_CHANGE")
21118 : ->Equals(context.local(),
21119 : obj->Get(context.local(), v8_num(2)).ToLocalChecked())
21120 : .FromJust());
21121 :
21122 : // Test non-smi case.
21123 12 : obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
21124 18 : v8_str("DONT_CHANGE"), v8::ReadOnly)
21125 : .FromJust();
21126 24 : obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
21127 30 : CHECK(v8_str("DONT_CHANGE")
21128 : ->Equals(context.local(),
21129 : obj->Get(context.local(), v8_str("2000000000"))
21130 : .ToLocalChecked())
21131 : .FromJust());
21132 6 : }
21133 :
21134 12 : static int CountLiveMapsInMapCache(i::Context context) {
21135 12 : i::WeakFixedArray map_cache = i::WeakFixedArray::cast(context->map_cache());
21136 : int length = map_cache->length();
21137 : int count = 0;
21138 3084 : for (int i = 0; i < length; i++) {
21139 1536 : if (map_cache->Get(i)->IsWeak()) count++;
21140 : }
21141 12 : return count;
21142 : }
21143 :
21144 :
21145 26645 : THREADED_TEST(Regress1516) {
21146 6 : LocalContext context;
21147 12 : v8::HandleScope scope(context->GetIsolate());
21148 :
21149 : // Object with 20 properties is not a common case, so it should be removed
21150 : // from the cache after GC.
21151 12 : { v8::HandleScope temp_scope(context->GetIsolate());
21152 : CompileRun(
21153 : "({"
21154 : "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21155 : "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21156 : "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21157 : "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21158 : "})");
21159 : }
21160 :
21161 6 : int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21162 6 : CHECK_LE(1, elements);
21163 :
21164 : // We have to abort incremental marking here to abandon black pages.
21165 6 : CcTest::PreciseCollectAllGarbage();
21166 :
21167 6 : CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21168 6 : }
21169 :
21170 :
21171 84 : static void TestReceiver(Local<Value> expected_result,
21172 : Local<Value> expected_receiver,
21173 : const char* code) {
21174 : Local<Value> result = CompileRun(code);
21175 84 : Local<Context> context = CcTest::isolate()->GetCurrentContext();
21176 84 : CHECK(result->IsObject());
21177 252 : CHECK(expected_receiver
21178 : ->Equals(context,
21179 : result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
21180 : .FromJust());
21181 252 : CHECK(expected_result
21182 : ->Equals(context,
21183 : result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
21184 : .FromJust());
21185 84 : }
21186 :
21187 :
21188 26645 : THREADED_TEST(ForeignFunctionReceiver) {
21189 6 : v8::Isolate* isolate = CcTest::isolate();
21190 12 : HandleScope scope(isolate);
21191 :
21192 : // Create two contexts with different "id" properties ('i' and 'o').
21193 : // Call a function both from its own context and from a the foreign
21194 : // context, and see what "this" is bound to (returning both "this"
21195 : // and "this.id" for comparison).
21196 :
21197 6 : Local<Context> foreign_context = v8::Context::New(isolate);
21198 6 : foreign_context->Enter();
21199 : Local<Value> foreign_function =
21200 : CompileRun("function func() { return { 0: this.id, "
21201 : " 1: this, "
21202 : " toString: function() { "
21203 : " return this[0];"
21204 : " }"
21205 : " };"
21206 : "}"
21207 : "var id = 'i';"
21208 : "func;");
21209 6 : CHECK(foreign_function->IsFunction());
21210 6 : foreign_context->Exit();
21211 :
21212 6 : LocalContext context;
21213 :
21214 6 : Local<String> password = v8_str("Password");
21215 : // Don't get hit by security checks when accessing foreign_context's
21216 : // global receiver (aka. global proxy).
21217 6 : context->SetSecurityToken(password);
21218 6 : foreign_context->SetSecurityToken(password);
21219 :
21220 6 : Local<String> i = v8_str("i");
21221 6 : Local<String> o = v8_str("o");
21222 6 : Local<String> id = v8_str("id");
21223 :
21224 : CompileRun("function ownfunc() { return { 0: this.id, "
21225 : " 1: this, "
21226 : " toString: function() { "
21227 : " return this[0];"
21228 : " }"
21229 : " };"
21230 : "}"
21231 : "var id = 'o';"
21232 : "ownfunc");
21233 24 : CHECK(context->Global()
21234 : ->Set(context.local(), v8_str("func"), foreign_function)
21235 : .FromJust());
21236 :
21237 : // Sanity check the contexts.
21238 24 : CHECK(
21239 : i->Equals(
21240 : context.local(),
21241 : foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
21242 : .FromJust());
21243 24 : CHECK(o->Equals(context.local(),
21244 : context->Global()->Get(context.local(), id).ToLocalChecked())
21245 : .FromJust());
21246 :
21247 : // Checking local function's receiver.
21248 : // Calling function using its call/apply methods.
21249 12 : TestReceiver(o, context->Global(), "ownfunc.call()");
21250 12 : TestReceiver(o, context->Global(), "ownfunc.apply()");
21251 : // Making calls through built-in functions.
21252 12 : TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21253 12 : CHECK(
21254 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
21255 : .FromJust());
21256 12 : CHECK(
21257 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
21258 : .FromJust());
21259 12 : CHECK(
21260 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
21261 : .FromJust());
21262 : // Calling with environment record as base.
21263 12 : TestReceiver(o, context->Global(), "ownfunc()");
21264 : // Calling with no base.
21265 12 : TestReceiver(o, context->Global(), "(1,ownfunc)()");
21266 :
21267 : // Checking foreign function return value.
21268 : // Calling function using its call/apply methods.
21269 12 : TestReceiver(i, foreign_context->Global(), "func.call()");
21270 12 : TestReceiver(i, foreign_context->Global(), "func.apply()");
21271 : // Calling function using another context's call/apply methods.
21272 12 : TestReceiver(i, foreign_context->Global(),
21273 6 : "Function.prototype.call.call(func)");
21274 12 : TestReceiver(i, foreign_context->Global(),
21275 6 : "Function.prototype.call.apply(func)");
21276 12 : TestReceiver(i, foreign_context->Global(),
21277 6 : "Function.prototype.apply.call(func)");
21278 12 : TestReceiver(i, foreign_context->Global(),
21279 6 : "Function.prototype.apply.apply(func)");
21280 : // Making calls through built-in functions.
21281 12 : TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21282 : // ToString(func()) is func()[0], i.e., the returned this.id.
21283 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
21284 : .FromJust());
21285 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
21286 : .FromJust());
21287 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
21288 : .FromJust());
21289 :
21290 : // Calling with environment record as base.
21291 12 : TestReceiver(i, foreign_context->Global(), "func()");
21292 : // Calling with no base.
21293 12 : TestReceiver(i, foreign_context->Global(), "(1,func)()");
21294 6 : }
21295 :
21296 :
21297 : uint8_t callback_fired = 0;
21298 : uint8_t before_call_entered_callback_count1 = 0;
21299 : uint8_t before_call_entered_callback_count2 = 0;
21300 :
21301 :
21302 5 : void CallCompletedCallback1(v8::Isolate*) {
21303 5 : v8::base::OS::Print("Firing callback 1.\n");
21304 5 : callback_fired ^= 1; // Toggle first bit.
21305 5 : }
21306 :
21307 :
21308 15 : void CallCompletedCallback2(v8::Isolate*) {
21309 15 : v8::base::OS::Print("Firing callback 2.\n");
21310 15 : callback_fired ^= 2; // Toggle second bit.
21311 15 : }
21312 :
21313 :
21314 20 : void BeforeCallEnteredCallback1(v8::Isolate*) {
21315 20 : v8::base::OS::Print("Firing before call entered callback 1.\n");
21316 20 : before_call_entered_callback_count1++;
21317 20 : }
21318 :
21319 :
21320 60 : void BeforeCallEnteredCallback2(v8::Isolate*) {
21321 60 : v8::base::OS::Print("Firing before call entered callback 2.\n");
21322 60 : before_call_entered_callback_count2++;
21323 60 : }
21324 :
21325 :
21326 60 : void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21327 : int32_t level =
21328 180 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
21329 60 : if (level < 3) {
21330 45 : level++;
21331 45 : v8::base::OS::Print("Entering recursion level %d.\n", level);
21332 : char script[64];
21333 : i::Vector<char> script_vector(script, sizeof(script));
21334 45 : i::SNPrintF(script_vector, "recursion(%d)", level);
21335 : CompileRun(script_vector.start());
21336 45 : v8::base::OS::Print("Leaving recursion level %d.\n", level);
21337 90 : CHECK_EQ(0, callback_fired);
21338 : } else {
21339 15 : v8::base::OS::Print("Recursion ends.\n");
21340 30 : CHECK_EQ(0, callback_fired);
21341 : }
21342 60 : }
21343 :
21344 :
21345 26644 : TEST(CallCompletedCallback) {
21346 5 : LocalContext env;
21347 10 : v8::HandleScope scope(env->GetIsolate());
21348 : v8::Local<v8::FunctionTemplate> recursive_runtime =
21349 5 : v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21350 10 : env->Global()
21351 10 : ->Set(env.local(), v8_str("recursion"),
21352 15 : recursive_runtime->GetFunction(env.local()).ToLocalChecked())
21353 : .FromJust();
21354 : // Adding the same callback a second time has no effect.
21355 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21356 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21357 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21358 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21359 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
21360 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21361 5 : v8::base::OS::Print("--- Script (1) ---\n");
21362 5 : callback_fired = 0;
21363 5 : before_call_entered_callback_count1 = 0;
21364 5 : before_call_entered_callback_count2 = 0;
21365 : Local<Script> script =
21366 10 : v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
21367 5 : script->Run(env.local()).ToLocalChecked();
21368 10 : CHECK_EQ(3, callback_fired);
21369 10 : CHECK_EQ(4, before_call_entered_callback_count1);
21370 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21371 :
21372 5 : v8::base::OS::Print("\n--- Script (2) ---\n");
21373 5 : callback_fired = 0;
21374 5 : before_call_entered_callback_count1 = 0;
21375 5 : before_call_entered_callback_count2 = 0;
21376 5 : env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21377 5 : env->GetIsolate()->RemoveBeforeCallEnteredCallback(
21378 5 : BeforeCallEnteredCallback1);
21379 5 : script->Run(env.local()).ToLocalChecked();
21380 10 : CHECK_EQ(2, callback_fired);
21381 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21382 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21383 :
21384 5 : v8::base::OS::Print("\n--- Function ---\n");
21385 5 : callback_fired = 0;
21386 5 : before_call_entered_callback_count1 = 0;
21387 5 : before_call_entered_callback_count2 = 0;
21388 : Local<Function> recursive_function = Local<Function>::Cast(
21389 20 : env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
21390 5 : v8::Local<Value> args[] = {v8_num(0)};
21391 15 : recursive_function->Call(env.local(), env->Global(), 1, args)
21392 : .ToLocalChecked();
21393 10 : CHECK_EQ(2, callback_fired);
21394 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21395 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21396 5 : }
21397 :
21398 :
21399 5 : void CallCompletedCallbackNoException(v8::Isolate*) {
21400 10 : v8::HandleScope scope(CcTest::isolate());
21401 : CompileRun("1+1;");
21402 5 : }
21403 :
21404 :
21405 5 : void CallCompletedCallbackException(v8::Isolate*) {
21406 10 : v8::HandleScope scope(CcTest::isolate());
21407 : CompileRun("throw 'second exception';");
21408 5 : }
21409 :
21410 :
21411 26644 : TEST(CallCompletedCallbackOneException) {
21412 5 : LocalContext env;
21413 10 : v8::HandleScope scope(env->GetIsolate());
21414 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21415 : CompileRun("throw 'exception';");
21416 5 : }
21417 :
21418 :
21419 26644 : TEST(CallCompletedCallbackTwoExceptions) {
21420 5 : LocalContext env;
21421 10 : v8::HandleScope scope(env->GetIsolate());
21422 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21423 : CompileRun("throw 'first exception';");
21424 5 : }
21425 :
21426 :
21427 45 : static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21428 45 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21429 90 : v8::HandleScope scope(info.GetIsolate());
21430 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21431 90 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21432 : CompileRun("ext1Calls++;");
21433 45 : }
21434 :
21435 :
21436 50 : static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21437 50 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21438 100 : v8::HandleScope scope(info.GetIsolate());
21439 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21440 100 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21441 : CompileRun("ext2Calls++;");
21442 50 : }
21443 :
21444 : void* g_passed_to_three = nullptr;
21445 :
21446 10 : static void MicrotaskThree(void* data) {
21447 10 : g_passed_to_three = data;
21448 10 : }
21449 :
21450 :
21451 26644 : TEST(EnqueueMicrotask) {
21452 5 : LocalContext env;
21453 10 : v8::HandleScope scope(env->GetIsolate());
21454 5 : CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
21455 : CompileRun(
21456 : "var ext1Calls = 0;"
21457 : "var ext2Calls = 0;");
21458 : CompileRun("1+1;");
21459 10 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21460 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21461 :
21462 5 : env->GetIsolate()->EnqueueMicrotask(
21463 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21464 : CompileRun("1+1;");
21465 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21466 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21467 :
21468 5 : env->GetIsolate()->EnqueueMicrotask(
21469 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21470 5 : env->GetIsolate()->EnqueueMicrotask(
21471 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21472 : CompileRun("1+1;");
21473 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21474 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21475 :
21476 5 : env->GetIsolate()->EnqueueMicrotask(
21477 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21478 : CompileRun("1+1;");
21479 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21480 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21481 :
21482 : CompileRun("1+1;");
21483 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21484 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21485 :
21486 5 : g_passed_to_three = nullptr;
21487 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21488 : CompileRun("1+1;");
21489 5 : CHECK(!g_passed_to_three);
21490 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21491 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21492 :
21493 : int dummy;
21494 5 : env->GetIsolate()->EnqueueMicrotask(
21495 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21496 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21497 5 : env->GetIsolate()->EnqueueMicrotask(
21498 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21499 : CompileRun("1+1;");
21500 5 : CHECK_EQ(&dummy, g_passed_to_three);
21501 10 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21502 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21503 5 : g_passed_to_three = nullptr;
21504 5 : }
21505 :
21506 :
21507 5 : static void MicrotaskExceptionOne(
21508 : const v8::FunctionCallbackInfo<Value>& info) {
21509 10 : v8::HandleScope scope(info.GetIsolate());
21510 : CompileRun("exception1Calls++;");
21511 : info.GetIsolate()->ThrowException(
21512 10 : v8::Exception::Error(v8_str("first")));
21513 5 : }
21514 :
21515 :
21516 5 : static void MicrotaskExceptionTwo(
21517 : const v8::FunctionCallbackInfo<Value>& info) {
21518 10 : v8::HandleScope scope(info.GetIsolate());
21519 : CompileRun("exception2Calls++;");
21520 : info.GetIsolate()->ThrowException(
21521 10 : v8::Exception::Error(v8_str("second")));
21522 5 : }
21523 :
21524 :
21525 26644 : TEST(RunMicrotasksIgnoresThrownExceptions) {
21526 5 : LocalContext env;
21527 5 : v8::Isolate* isolate = env->GetIsolate();
21528 10 : v8::HandleScope scope(isolate);
21529 : CompileRun(
21530 : "var exception1Calls = 0;"
21531 : "var exception2Calls = 0;");
21532 : isolate->EnqueueMicrotask(
21533 10 : Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
21534 : isolate->EnqueueMicrotask(
21535 10 : Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
21536 10 : TryCatch try_catch(isolate);
21537 : CompileRun("1+1;");
21538 5 : CHECK(!try_catch.HasCaught());
21539 10 : CHECK_EQ(1,
21540 : CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
21541 10 : CHECK_EQ(1,
21542 : CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
21543 5 : }
21544 :
21545 5 : static void ThrowExceptionMicrotask(void* data) {
21546 10 : CcTest::isolate()->ThrowException(v8_str("exception"));
21547 5 : }
21548 :
21549 : int microtask_callback_count = 0;
21550 :
21551 5 : static void IncrementCounterMicrotask(void* data) {
21552 5 : microtask_callback_count++;
21553 5 : }
21554 :
21555 26644 : TEST(RunMicrotasksIgnoresThrownExceptionsFromApi) {
21556 5 : LocalContext env;
21557 5 : v8::Isolate* isolate = CcTest::isolate();
21558 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21559 10 : v8::HandleScope scope(isolate);
21560 10 : v8::TryCatch try_catch(isolate);
21561 : {
21562 5 : CHECK(!isolate->IsExecutionTerminating());
21563 5 : isolate->EnqueueMicrotask(ThrowExceptionMicrotask);
21564 5 : isolate->EnqueueMicrotask(IncrementCounterMicrotask);
21565 5 : isolate->RunMicrotasks();
21566 5 : CHECK_EQ(1, microtask_callback_count);
21567 5 : CHECK(!try_catch.HasCaught());
21568 : }
21569 5 : }
21570 :
21571 : uint8_t microtasks_completed_callback_count = 0;
21572 :
21573 25 : static void MicrotasksCompletedCallback(v8::Isolate* isolate, void*) {
21574 25 : ++microtasks_completed_callback_count;
21575 25 : }
21576 :
21577 26644 : TEST(SetAutorunMicrotasks) {
21578 5 : LocalContext env;
21579 10 : v8::HandleScope scope(env->GetIsolate());
21580 5 : env->GetIsolate()->AddMicrotasksCompletedCallback(
21581 5 : &MicrotasksCompletedCallback);
21582 : CompileRun(
21583 : "var ext1Calls = 0;"
21584 : "var ext2Calls = 0;");
21585 : CompileRun("1+1;");
21586 10 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21587 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21588 5 : CHECK_EQ(0u, microtasks_completed_callback_count);
21589 :
21590 5 : env->GetIsolate()->EnqueueMicrotask(
21591 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21592 : CompileRun("1+1;");
21593 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21594 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21595 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
21596 :
21597 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21598 5 : env->GetIsolate()->EnqueueMicrotask(
21599 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21600 5 : env->GetIsolate()->EnqueueMicrotask(
21601 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21602 : CompileRun("1+1;");
21603 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21604 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21605 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
21606 :
21607 5 : env->GetIsolate()->RunMicrotasks();
21608 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21609 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21610 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
21611 :
21612 5 : env->GetIsolate()->EnqueueMicrotask(
21613 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21614 : CompileRun("1+1;");
21615 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21616 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21617 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
21618 :
21619 5 : env->GetIsolate()->RunMicrotasks();
21620 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21621 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21622 5 : CHECK_EQ(3u, microtasks_completed_callback_count);
21623 :
21624 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21625 5 : env->GetIsolate()->EnqueueMicrotask(
21626 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21627 : CompileRun("1+1;");
21628 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21629 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21630 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
21631 :
21632 5 : env->GetIsolate()->EnqueueMicrotask(
21633 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21634 : {
21635 10 : v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21636 : CompileRun("1+1;");
21637 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21638 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21639 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
21640 : }
21641 :
21642 : CompileRun("1+1;");
21643 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21644 10 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21645 5 : CHECK_EQ(5u, microtasks_completed_callback_count);
21646 :
21647 5 : env->GetIsolate()->RemoveMicrotasksCompletedCallback(
21648 5 : &MicrotasksCompletedCallback);
21649 5 : env->GetIsolate()->EnqueueMicrotask(
21650 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21651 : CompileRun("1+1;");
21652 10 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21653 10 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21654 5 : CHECK_EQ(5u, microtasks_completed_callback_count);
21655 5 : }
21656 :
21657 :
21658 26644 : TEST(RunMicrotasksWithoutEnteringContext) {
21659 5 : v8::Isolate* isolate = CcTest::isolate();
21660 10 : HandleScope handle_scope(isolate);
21661 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21662 5 : Local<Context> context = Context::New(isolate);
21663 : {
21664 : Context::Scope context_scope(context);
21665 : CompileRun("var ext1Calls = 0;");
21666 : isolate->EnqueueMicrotask(
21667 10 : Function::New(context, MicrotaskOne).ToLocalChecked());
21668 : }
21669 5 : isolate->RunMicrotasks();
21670 : {
21671 : Context::Scope context_scope(context);
21672 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
21673 : }
21674 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21675 5 : }
21676 :
21677 6 : static void Regress808911_MicrotaskCallback(void* data) {
21678 : // So here we expect "current context" to be context1 and
21679 : // "entered or microtask context" to be context2.
21680 : v8::Isolate* isolate = static_cast<v8::Isolate*>(data);
21681 12 : CHECK(isolate->GetCurrentContext() !=
21682 : isolate->GetEnteredOrMicrotaskContext());
21683 6 : }
21684 :
21685 6 : static void Regress808911_CurrentContextWrapper(
21686 : const v8::FunctionCallbackInfo<Value>& info) {
21687 : // So here we expect "current context" to be context1 and
21688 : // "entered or microtask context" to be context2.
21689 : v8::Isolate* isolate = info.GetIsolate();
21690 12 : CHECK(isolate->GetCurrentContext() !=
21691 : isolate->GetEnteredOrMicrotaskContext());
21692 6 : isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
21693 6 : isolate->RunMicrotasks();
21694 6 : }
21695 :
21696 26645 : THREADED_TEST(Regress808911) {
21697 6 : v8::Isolate* isolate = CcTest::isolate();
21698 12 : HandleScope handle_scope(isolate);
21699 6 : Local<Context> context1 = Context::New(isolate);
21700 : Local<Function> function;
21701 : {
21702 : Context::Scope context_scope(context1);
21703 12 : function = Function::New(context1, Regress808911_CurrentContextWrapper)
21704 : .ToLocalChecked();
21705 : }
21706 6 : Local<Context> context2 = Context::New(isolate);
21707 : Context::Scope context_scope(context2);
21708 12 : function->CallAsFunction(context2, v8::Undefined(isolate), 0, nullptr)
21709 : .ToLocalChecked();
21710 6 : }
21711 :
21712 26644 : TEST(ScopedMicrotasks) {
21713 5 : LocalContext env;
21714 10 : v8::HandleScope handles(env->GetIsolate());
21715 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
21716 : {
21717 : v8::MicrotasksScope scope1(env->GetIsolate(),
21718 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21719 5 : env->GetIsolate()->EnqueueMicrotask(
21720 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21721 : CompileRun(
21722 : "var ext1Calls = 0;"
21723 : "var ext2Calls = 0;");
21724 : CompileRun("1+1;");
21725 10 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21726 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21727 : {
21728 : v8::MicrotasksScope scope2(env->GetIsolate(),
21729 10 : v8::MicrotasksScope::kRunMicrotasks);
21730 : CompileRun("1+1;");
21731 10 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21732 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21733 : {
21734 : v8::MicrotasksScope scope3(env->GetIsolate(),
21735 10 : v8::MicrotasksScope::kRunMicrotasks);
21736 : CompileRun("1+1;");
21737 10 : CHECK_EQ(0,
21738 : CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21739 10 : CHECK_EQ(0,
21740 : CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21741 : }
21742 10 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21743 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21744 : }
21745 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21746 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21747 5 : env->GetIsolate()->EnqueueMicrotask(
21748 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21749 : }
21750 :
21751 : {
21752 : v8::MicrotasksScope scope(env->GetIsolate(),
21753 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21754 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21755 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21756 : }
21757 :
21758 : {
21759 : v8::MicrotasksScope scope1(env->GetIsolate(),
21760 10 : v8::MicrotasksScope::kRunMicrotasks);
21761 : CompileRun("1+1;");
21762 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21763 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21764 : {
21765 : v8::MicrotasksScope scope2(env->GetIsolate(),
21766 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21767 : }
21768 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21769 10 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21770 : }
21771 :
21772 : {
21773 : v8::MicrotasksScope scope(env->GetIsolate(),
21774 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21775 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21776 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21777 5 : env->GetIsolate()->EnqueueMicrotask(
21778 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21779 : }
21780 :
21781 : {
21782 10 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21783 : {
21784 : v8::MicrotasksScope scope2(env->GetIsolate(),
21785 5 : v8::MicrotasksScope::kRunMicrotasks);
21786 : }
21787 : v8::MicrotasksScope scope3(env->GetIsolate(),
21788 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21789 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21790 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21791 : }
21792 :
21793 : {
21794 : v8::MicrotasksScope scope1(env->GetIsolate(),
21795 10 : v8::MicrotasksScope::kRunMicrotasks);
21796 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21797 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21798 10 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21799 : }
21800 :
21801 : {
21802 : v8::MicrotasksScope scope(env->GetIsolate(),
21803 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21804 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21805 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21806 : }
21807 :
21808 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21809 :
21810 : {
21811 : v8::MicrotasksScope scope(env->GetIsolate(),
21812 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21813 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21814 10 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21815 5 : env->GetIsolate()->EnqueueMicrotask(
21816 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21817 : }
21818 :
21819 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21820 :
21821 : {
21822 : v8::MicrotasksScope scope(env->GetIsolate(),
21823 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21824 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21825 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21826 : }
21827 :
21828 5 : env->GetIsolate()->EnqueueMicrotask(
21829 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21830 : {
21831 10 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21832 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21833 : v8::MicrotasksScope scope2(env->GetIsolate(),
21834 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21835 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21836 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21837 : }
21838 :
21839 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21840 :
21841 : {
21842 : v8::MicrotasksScope scope(env->GetIsolate(),
21843 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21844 10 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21845 10 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21846 : }
21847 :
21848 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21849 5 : }
21850 :
21851 : namespace {
21852 :
21853 35 : void AssertCowElements(bool expected, const char* source) {
21854 : Local<Value> object = CompileRun(source);
21855 : i::Handle<i::JSObject> array =
21856 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*object.As<Object>()));
21857 35 : CHECK_EQ(expected, array->elements()->IsCowArray());
21858 35 : }
21859 :
21860 : } // namespace
21861 :
21862 26644 : TEST(CheckCOWArraysCreatedRuntimeCounter) {
21863 5 : LocalContext env;
21864 10 : v8::HandleScope scope(env->GetIsolate());
21865 5 : AssertCowElements(true, "[1, 2, 3]");
21866 5 : AssertCowElements(false, "[[1], 2, 3]");
21867 5 : AssertCowElements(true, "[[1], 2, 3][0]");
21868 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.foo)");
21869 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.bar)");
21870 5 : AssertCowElements(false, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo)");
21871 5 : AssertCowElements(true, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo[3])");
21872 5 : }
21873 :
21874 :
21875 26644 : TEST(StaticGetters) {
21876 5 : LocalContext context;
21877 : i::Factory* factory = CcTest::i_isolate()->factory();
21878 5 : v8::Isolate* isolate = CcTest::isolate();
21879 10 : v8::HandleScope scope(isolate);
21880 : i::Handle<i::Object> undefined_value = factory->undefined_value();
21881 5 : CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21882 : i::Handle<i::Object> null_value = factory->null_value();
21883 5 : CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21884 : i::Handle<i::Object> true_value = factory->true_value();
21885 5 : CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21886 : i::Handle<i::Object> false_value = factory->false_value();
21887 5 : CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21888 5 : }
21889 :
21890 :
21891 26644 : UNINITIALIZED_TEST(IsolateEmbedderData) {
21892 5 : CcTest::DisableAutomaticDispose();
21893 : v8::Isolate::CreateParams create_params;
21894 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21895 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
21896 5 : isolate->Enter();
21897 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21898 45 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21899 20 : CHECK(!isolate->GetData(slot));
21900 20 : CHECK(!i_isolate->GetData(slot));
21901 : }
21902 45 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21903 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21904 : isolate->SetData(slot, data);
21905 : }
21906 45 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21907 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21908 20 : CHECK_EQ(data, isolate->GetData(slot));
21909 20 : CHECK_EQ(data, i_isolate->GetData(slot));
21910 : }
21911 45 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21912 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
21913 : isolate->SetData(slot, data);
21914 : }
21915 45 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21916 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
21917 20 : CHECK_EQ(data, isolate->GetData(slot));
21918 20 : CHECK_EQ(data, i_isolate->GetData(slot));
21919 : }
21920 5 : isolate->Exit();
21921 5 : isolate->Dispose();
21922 5 : }
21923 :
21924 :
21925 26644 : TEST(StringEmpty) {
21926 5 : LocalContext context;
21927 : i::Factory* factory = CcTest::i_isolate()->factory();
21928 5 : v8::Isolate* isolate = CcTest::isolate();
21929 10 : v8::HandleScope scope(isolate);
21930 : i::Handle<i::Object> empty_string = factory->empty_string();
21931 5 : CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21932 5 : }
21933 :
21934 :
21935 : static int instance_checked_getter_count = 0;
21936 120 : static void InstanceCheckedGetter(
21937 : Local<String> name,
21938 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21939 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21940 : .FromJust());
21941 120 : instance_checked_getter_count++;
21942 120 : info.GetReturnValue().Set(v8_num(11));
21943 120 : }
21944 :
21945 :
21946 : static int instance_checked_setter_count = 0;
21947 120 : static void InstanceCheckedSetter(Local<String> name,
21948 : Local<Value> value,
21949 : const v8::PropertyCallbackInfo<void>& info) {
21950 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21951 : .FromJust());
21952 480 : CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
21953 : .FromJust());
21954 120 : instance_checked_setter_count++;
21955 120 : }
21956 :
21957 :
21958 420 : static void CheckInstanceCheckedResult(int getters, int setters,
21959 : bool expects_callbacks,
21960 : TryCatch* try_catch) {
21961 420 : if (expects_callbacks) {
21962 240 : CHECK(!try_catch->HasCaught());
21963 240 : CHECK_EQ(getters, instance_checked_getter_count);
21964 240 : CHECK_EQ(setters, instance_checked_setter_count);
21965 : } else {
21966 180 : CHECK(try_catch->HasCaught());
21967 180 : CHECK_EQ(0, instance_checked_getter_count);
21968 180 : CHECK_EQ(0, instance_checked_setter_count);
21969 : }
21970 420 : try_catch->Reset();
21971 420 : }
21972 :
21973 :
21974 42 : static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21975 42 : instance_checked_getter_count = 0;
21976 42 : instance_checked_setter_count = 0;
21977 84 : TryCatch try_catch(CcTest::isolate());
21978 :
21979 : // Test path through generic runtime code.
21980 : CompileRun("obj.foo");
21981 42 : CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21982 : CompileRun("obj.foo = 23");
21983 42 : CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21984 :
21985 : // Test path through generated LoadIC and StoredIC.
21986 : CompileRun("function test_get(o) { o.foo; }"
21987 : "test_get(obj);");
21988 42 : CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21989 : CompileRun("test_get(obj);");
21990 42 : CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21991 : CompileRun("test_get(obj);");
21992 42 : CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21993 : CompileRun("function test_set(o) { o.foo = 23; }"
21994 : "test_set(obj);");
21995 42 : CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21996 : CompileRun("test_set(obj);");
21997 42 : CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21998 : CompileRun("test_set(obj);");
21999 42 : CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22000 :
22001 : // Test path through optimized code.
22002 : CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22003 : "test_get(obj);");
22004 42 : CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22005 : CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22006 : "test_set(obj);");
22007 42 : CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22008 :
22009 : // Cleanup so that closures start out fresh in next check.
22010 : CompileRun(
22011 : "%DeoptimizeFunction(test_get);"
22012 : "%ClearFunctionFeedback(test_get);"
22013 : "%DeoptimizeFunction(test_set);"
22014 : "%ClearFunctionFeedback(test_set);");
22015 42 : }
22016 :
22017 :
22018 26645 : THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22019 6 : v8::internal::FLAG_allow_natives_syntax = true;
22020 6 : LocalContext context;
22021 12 : v8::HandleScope scope(context->GetIsolate());
22022 :
22023 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22024 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22025 18 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22026 : Local<Value>(), v8::DEFAULT, v8::None,
22027 6 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22028 30 : CHECK(context->Global()
22029 : ->Set(context.local(), v8_str("f"),
22030 : templ->GetFunction(context.local()).ToLocalChecked())
22031 : .FromJust());
22032 :
22033 : printf("Testing positive ...\n");
22034 : CompileRun("var obj = new f();");
22035 24 : CHECK(templ->HasInstance(
22036 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22037 6 : CheckInstanceCheckedAccessors(true);
22038 :
22039 : printf("Testing negative ...\n");
22040 : CompileRun("var obj = {};"
22041 : "obj.__proto__ = new f();");
22042 24 : CHECK(!templ->HasInstance(
22043 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22044 6 : CheckInstanceCheckedAccessors(false);
22045 6 : }
22046 :
22047 90 : static void EmptyInterceptorGetter(
22048 90 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22049 :
22050 30 : static void EmptyInterceptorSetter(
22051 : Local<Name> name, Local<Value> value,
22052 30 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
22053 :
22054 26645 : THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22055 6 : v8::internal::FLAG_allow_natives_syntax = true;
22056 6 : LocalContext context;
22057 12 : v8::HandleScope scope(context->GetIsolate());
22058 :
22059 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22060 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22061 12 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
22062 6 : EmptyInterceptorGetter, EmptyInterceptorSetter));
22063 18 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22064 : Local<Value>(), v8::DEFAULT, v8::None,
22065 6 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22066 30 : CHECK(context->Global()
22067 : ->Set(context.local(), v8_str("f"),
22068 : templ->GetFunction(context.local()).ToLocalChecked())
22069 : .FromJust());
22070 :
22071 : printf("Testing positive ...\n");
22072 : CompileRun("var obj = new f();");
22073 24 : CHECK(templ->HasInstance(
22074 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22075 6 : CheckInstanceCheckedAccessors(true);
22076 :
22077 : printf("Testing negative ...\n");
22078 : CompileRun("var obj = {};"
22079 : "obj.__proto__ = new f();");
22080 24 : CHECK(!templ->HasInstance(
22081 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22082 6 : CheckInstanceCheckedAccessors(false);
22083 6 : }
22084 :
22085 :
22086 26645 : THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22087 6 : v8::internal::FLAG_allow_natives_syntax = true;
22088 6 : LocalContext context;
22089 12 : v8::HandleScope scope(context->GetIsolate());
22090 :
22091 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22092 6 : Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22093 18 : proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22094 : InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
22095 : v8::None,
22096 6 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22097 30 : CHECK(context->Global()
22098 : ->Set(context.local(), v8_str("f"),
22099 : templ->GetFunction(context.local()).ToLocalChecked())
22100 : .FromJust());
22101 :
22102 : printf("Testing positive ...\n");
22103 : CompileRun("var obj = new f();");
22104 24 : CHECK(templ->HasInstance(
22105 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22106 6 : CheckInstanceCheckedAccessors(true);
22107 :
22108 : printf("Testing negative ...\n");
22109 : CompileRun("var obj = {};"
22110 : "obj.__proto__ = new f();");
22111 24 : CHECK(!templ->HasInstance(
22112 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22113 6 : CheckInstanceCheckedAccessors(false);
22114 :
22115 : printf("Testing positive with modified prototype chain ...\n");
22116 : CompileRun("var obj = new f();"
22117 : "var pro = {};"
22118 : "pro.__proto__ = obj.__proto__;"
22119 : "obj.__proto__ = pro;");
22120 24 : CHECK(templ->HasInstance(
22121 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22122 6 : CheckInstanceCheckedAccessors(true);
22123 6 : }
22124 :
22125 :
22126 26644 : TEST(TryFinallyMessage) {
22127 5 : LocalContext context;
22128 10 : v8::HandleScope scope(context->GetIsolate());
22129 : {
22130 : // Test that the original error message is not lost if there is a
22131 : // recursive call into Javascript is done in the finally block, e.g. to
22132 : // initialize an IC. (crbug.com/129171)
22133 10 : TryCatch try_catch(context->GetIsolate());
22134 : const char* trigger_ic =
22135 : "try { \n"
22136 : " throw new Error('test'); \n"
22137 : "} finally { \n"
22138 : " var x = 0; \n"
22139 : " x++; \n" // Trigger an IC initialization here.
22140 : "} \n";
22141 : CompileRun(trigger_ic);
22142 5 : CHECK(try_catch.HasCaught());
22143 5 : Local<Message> message = try_catch.Message();
22144 5 : CHECK(!message.IsEmpty());
22145 10 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
22146 : }
22147 :
22148 : {
22149 : // Test that the original exception message is indeed overwritten if
22150 : // a new error is thrown in the finally block.
22151 10 : TryCatch try_catch(context->GetIsolate());
22152 : const char* throw_again =
22153 : "try { \n"
22154 : " throw new Error('test'); \n"
22155 : "} finally { \n"
22156 : " var x = 0; \n"
22157 : " x++; \n"
22158 : " throw new Error('again'); \n" // This is the new uncaught error.
22159 : "} \n";
22160 : CompileRun(throw_again);
22161 5 : CHECK(try_catch.HasCaught());
22162 5 : Local<Message> message = try_catch.Message();
22163 5 : CHECK(!message.IsEmpty());
22164 10 : CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
22165 : }
22166 5 : }
22167 :
22168 :
22169 96 : static void Helper137002(bool do_store,
22170 : bool polymorphic,
22171 : bool remove_accessor,
22172 : bool interceptor) {
22173 96 : LocalContext context;
22174 96 : Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22175 96 : if (interceptor) {
22176 48 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22177 48 : FooSetInterceptor));
22178 : } else {
22179 96 : templ->SetAccessor(v8_str("foo"),
22180 : GetterWhichReturns42,
22181 48 : SetterWhichSetsYOnThisTo23);
22182 : }
22183 480 : CHECK(context->Global()
22184 : ->Set(context.local(), v8_str("obj"),
22185 : templ->NewInstance(context.local()).ToLocalChecked())
22186 : .FromJust());
22187 :
22188 : // Turn monomorphic on slow object with native accessor, then turn
22189 : // polymorphic, finally optimize to create negative lookup and fail.
22190 : CompileRun(do_store ?
22191 : "function f(x) { x.foo = void 0; }" :
22192 96 : "function f(x) { return x.foo; }");
22193 : CompileRun("obj.y = void 0;");
22194 96 : if (!interceptor) {
22195 : CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22196 : }
22197 : CompileRun("obj.__proto__ = null;"
22198 : "f(obj); f(obj); f(obj);");
22199 96 : if (polymorphic) {
22200 : CompileRun("f({});");
22201 : }
22202 : CompileRun("obj.y = void 0;"
22203 : "%OptimizeFunctionOnNextCall(f);");
22204 96 : if (remove_accessor) {
22205 : CompileRun("delete obj.foo;");
22206 : }
22207 : CompileRun("var result = f(obj);");
22208 96 : if (do_store) {
22209 : CompileRun("result = obj.y;");
22210 : }
22211 96 : if (remove_accessor && !interceptor) {
22212 96 : CHECK(context->Global()
22213 : ->Get(context.local(), v8_str("result"))
22214 : .ToLocalChecked()
22215 : ->IsUndefined());
22216 : } else {
22217 360 : CHECK_EQ(do_store ? 23 : 42, context->Global()
22218 : ->Get(context.local(), v8_str("result"))
22219 : .ToLocalChecked()
22220 : ->Int32Value(context.local())
22221 : .FromJust());
22222 : }
22223 96 : }
22224 :
22225 :
22226 26645 : THREADED_TEST(Regress137002a) {
22227 6 : i::FLAG_allow_natives_syntax = true;
22228 6 : i::FLAG_compilation_cache = false;
22229 12 : v8::HandleScope scope(CcTest::isolate());
22230 198 : for (int i = 0; i < 16; i++) {
22231 96 : Helper137002(i & 8, i & 4, i & 2, i & 1);
22232 : }
22233 6 : }
22234 :
22235 :
22236 26645 : THREADED_TEST(Regress137002b) {
22237 6 : i::FLAG_allow_natives_syntax = true;
22238 6 : LocalContext context;
22239 6 : v8::Isolate* isolate = context->GetIsolate();
22240 12 : v8::HandleScope scope(isolate);
22241 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22242 12 : templ->SetAccessor(v8_str("foo"),
22243 : GetterWhichReturns42,
22244 6 : SetterWhichSetsYOnThisTo23);
22245 30 : CHECK(context->Global()
22246 : ->Set(context.local(), v8_str("obj"),
22247 : templ->NewInstance(context.local()).ToLocalChecked())
22248 : .FromJust());
22249 :
22250 : // Turn monomorphic on slow object with native accessor, then just
22251 : // delete the property and fail.
22252 : CompileRun("function load(x) { return x.foo; }"
22253 : "function store(x) { x.foo = void 0; }"
22254 : "function keyed_load(x, key) { return x[key]; }"
22255 : // Second version of function has a different source (add void 0)
22256 : // so that it does not share code with the first version. This
22257 : // ensures that the ICs are monomorphic.
22258 : "function load2(x) { void 0; return x.foo; }"
22259 : "function store2(x) { void 0; x.foo = void 0; }"
22260 : "function keyed_load2(x, key) { void 0; return x[key]; }"
22261 :
22262 : "obj.y = void 0;"
22263 : "obj.__proto__ = null;"
22264 : "var subobj = {};"
22265 : "subobj.y = void 0;"
22266 : "subobj.__proto__ = obj;"
22267 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22268 :
22269 : // Make the ICs monomorphic.
22270 : "load(obj); load(obj);"
22271 : "load2(subobj); load2(subobj);"
22272 : "store(obj); store(obj);"
22273 : "store2(subobj); store2(subobj);"
22274 : "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22275 : "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22276 :
22277 : // Actually test the shiny new ICs and better not crash. This
22278 : // serves as a regression test for issue 142088 as well.
22279 : "load(obj);"
22280 : "load2(subobj);"
22281 : "store(obj);"
22282 : "store2(subobj);"
22283 : "keyed_load(obj, 'foo');"
22284 : "keyed_load2(subobj, 'foo');"
22285 :
22286 : // Delete the accessor. It better not be called any more now.
22287 : "delete obj.foo;"
22288 : "obj.y = void 0;"
22289 : "subobj.y = void 0;"
22290 :
22291 : "var load_result = load(obj);"
22292 : "var load_result2 = load2(subobj);"
22293 : "var keyed_load_result = keyed_load(obj, 'foo');"
22294 : "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22295 : "store(obj);"
22296 : "store2(subobj);"
22297 : "var y_from_obj = obj.y;"
22298 : "var y_from_subobj = subobj.y;");
22299 24 : CHECK(context->Global()
22300 : ->Get(context.local(), v8_str("load_result"))
22301 : .ToLocalChecked()
22302 : ->IsUndefined());
22303 24 : CHECK(context->Global()
22304 : ->Get(context.local(), v8_str("load_result2"))
22305 : .ToLocalChecked()
22306 : ->IsUndefined());
22307 24 : CHECK(context->Global()
22308 : ->Get(context.local(), v8_str("keyed_load_result"))
22309 : .ToLocalChecked()
22310 : ->IsUndefined());
22311 24 : CHECK(context->Global()
22312 : ->Get(context.local(), v8_str("keyed_load_result2"))
22313 : .ToLocalChecked()
22314 : ->IsUndefined());
22315 24 : CHECK(context->Global()
22316 : ->Get(context.local(), v8_str("y_from_obj"))
22317 : .ToLocalChecked()
22318 : ->IsUndefined());
22319 24 : CHECK(context->Global()
22320 : ->Get(context.local(), v8_str("y_from_subobj"))
22321 : .ToLocalChecked()
22322 : ->IsUndefined());
22323 6 : }
22324 :
22325 :
22326 26645 : THREADED_TEST(Regress142088) {
22327 6 : i::FLAG_allow_natives_syntax = true;
22328 6 : LocalContext context;
22329 6 : v8::Isolate* isolate = context->GetIsolate();
22330 12 : v8::HandleScope scope(isolate);
22331 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22332 12 : templ->SetAccessor(v8_str("foo"),
22333 : GetterWhichReturns42,
22334 6 : SetterWhichSetsYOnThisTo23);
22335 30 : CHECK(context->Global()
22336 : ->Set(context.local(), v8_str("obj"),
22337 : templ->NewInstance(context.local()).ToLocalChecked())
22338 : .FromJust());
22339 :
22340 : CompileRun("function load(x) { return x.foo; }"
22341 : "var o = Object.create(obj);"
22342 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22343 : "load(o); load(o); load(o); load(o);");
22344 6 : }
22345 :
22346 :
22347 26645 : THREADED_TEST(Regress137496) {
22348 6 : i::FLAG_expose_gc = true;
22349 6 : LocalContext context;
22350 12 : v8::HandleScope scope(context->GetIsolate());
22351 :
22352 : // Compile a try-finally clause where the finally block causes a GC
22353 : // while there still is a message pending for external reporting.
22354 12 : TryCatch try_catch(context->GetIsolate());
22355 6 : try_catch.SetVerbose(true);
22356 : CompileRun("try { throw new Error(); } finally { gc(); }");
22357 6 : CHECK(try_catch.HasCaught());
22358 6 : }
22359 :
22360 :
22361 26645 : THREADED_TEST(Regress157124) {
22362 6 : LocalContext context;
22363 6 : v8::Isolate* isolate = context->GetIsolate();
22364 12 : v8::HandleScope scope(isolate);
22365 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22366 6 : Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
22367 6 : obj->GetIdentityHash();
22368 12 : obj->DeletePrivate(context.local(),
22369 6 : v8::Private::ForApi(isolate, v8_str("Bug")))
22370 : .FromJust();
22371 6 : }
22372 :
22373 :
22374 26645 : THREADED_TEST(Regress2535) {
22375 6 : LocalContext context;
22376 12 : v8::HandleScope scope(context->GetIsolate());
22377 : Local<Value> set_value = CompileRun("new Set();");
22378 : Local<Object> set_object(Local<Object>::Cast(set_value));
22379 6 : CHECK_EQ(0, set_object->InternalFieldCount());
22380 : Local<Value> map_value = CompileRun("new Map();");
22381 : Local<Object> map_object(Local<Object>::Cast(map_value));
22382 6 : CHECK_EQ(0, map_object->InternalFieldCount());
22383 6 : }
22384 :
22385 :
22386 26645 : THREADED_TEST(Regress2746) {
22387 6 : LocalContext context;
22388 6 : v8::Isolate* isolate = context->GetIsolate();
22389 12 : v8::HandleScope scope(isolate);
22390 6 : Local<Object> obj = Object::New(isolate);
22391 6 : Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
22392 12 : CHECK(
22393 : obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
22394 6 : Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
22395 6 : CHECK(!value.IsEmpty());
22396 6 : CHECK(value->IsUndefined());
22397 6 : }
22398 :
22399 :
22400 26645 : THREADED_TEST(Regress260106) {
22401 6 : LocalContext context;
22402 6 : v8::Isolate* isolate = context->GetIsolate();
22403 12 : v8::HandleScope scope(isolate);
22404 : Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22405 6 : DummyCallHandler);
22406 : CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22407 : Local<Function> function =
22408 6 : templ->GetFunction(context.local()).ToLocalChecked();
22409 6 : CHECK(!function.IsEmpty());
22410 6 : CHECK(function->IsFunction());
22411 6 : }
22412 :
22413 26645 : THREADED_TEST(JSONParseObject) {
22414 6 : LocalContext context;
22415 12 : HandleScope scope(context->GetIsolate());
22416 : Local<Value> obj =
22417 18 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22418 6 : Local<Object> global = context->Global();
22419 18 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22420 6 : ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22421 6 : }
22422 :
22423 26645 : THREADED_TEST(JSONParseNumber) {
22424 6 : LocalContext context;
22425 12 : HandleScope scope(context->GetIsolate());
22426 : Local<Value> obj =
22427 18 : v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
22428 6 : Local<Object> global = context->Global();
22429 18 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22430 6 : ExpectString("JSON.stringify(obj)", "42");
22431 6 : }
22432 :
22433 : namespace {
22434 42 : void TestJSONParseArray(Local<Context> context, const char* input_str,
22435 : const char* expected_output_str,
22436 : i::ElementsKind expected_elements_kind) {
22437 : Local<Value> obj =
22438 42 : v8::JSON::Parse(context, v8_str(input_str)).ToLocalChecked();
22439 :
22440 : i::Handle<i::JSArray> a =
22441 : i::Handle<i::JSArray>::cast(v8::Utils::OpenHandle(*obj));
22442 42 : CHECK_EQ(expected_elements_kind, a->GetElementsKind());
22443 :
22444 42 : Local<Object> global = context->Global();
22445 126 : global->Set(context, v8_str("obj"), obj).FromJust();
22446 42 : ExpectString("JSON.stringify(obj)", expected_output_str);
22447 42 : }
22448 : } // namespace
22449 :
22450 26645 : THREADED_TEST(JSONParseArray) {
22451 6 : LocalContext context;
22452 12 : HandleScope scope(context->GetIsolate());
22453 :
22454 : TestJSONParseArray(context.local(), "[0, 1, 2]", "[0,1,2]",
22455 6 : i::PACKED_SMI_ELEMENTS);
22456 : TestJSONParseArray(context.local(), "[0, 1.2, 2]", "[0,1.2,2]",
22457 6 : i::PACKED_DOUBLE_ELEMENTS);
22458 : TestJSONParseArray(context.local(), "[0.2, 1, 2]", "[0.2,1,2]",
22459 6 : i::PACKED_DOUBLE_ELEMENTS);
22460 : TestJSONParseArray(context.local(), "[0, \"a\", 2]", "[0,\"a\",2]",
22461 6 : i::PACKED_ELEMENTS);
22462 : TestJSONParseArray(context.local(), "[\"a\", 1, 2]", "[\"a\",1,2]",
22463 6 : i::PACKED_ELEMENTS);
22464 : TestJSONParseArray(context.local(), "[\"a\", 1.2, 2]", "[\"a\",1.2,2]",
22465 6 : i::PACKED_ELEMENTS);
22466 : TestJSONParseArray(context.local(), "[0, 1.2, \"a\"]", "[0,1.2,\"a\"]",
22467 6 : i::PACKED_ELEMENTS);
22468 6 : }
22469 :
22470 26645 : THREADED_TEST(JSONStringifyObject) {
22471 6 : LocalContext context;
22472 12 : HandleScope scope(context->GetIsolate());
22473 : Local<Value> value =
22474 12 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22475 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22476 6 : Local<Object> global = context->Global();
22477 18 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22478 : Local<String> json =
22479 12 : v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
22480 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
22481 6 : ExpectString("JSON.stringify(obj)", *utf8);
22482 6 : }
22483 :
22484 26645 : THREADED_TEST(JSONStringifyObjectWithGap) {
22485 6 : LocalContext context;
22486 12 : HandleScope scope(context->GetIsolate());
22487 : Local<Value> value =
22488 12 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22489 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22490 6 : Local<Object> global = context->Global();
22491 18 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22492 : Local<String> json =
22493 18 : v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
22494 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
22495 6 : ExpectString("JSON.stringify(obj, null, '*')", *utf8);
22496 6 : }
22497 :
22498 : #if V8_OS_POSIX
22499 : class ThreadInterruptTest {
22500 : public:
22501 6 : ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22502 6 : ~ThreadInterruptTest() = default;
22503 :
22504 6 : void RunTest() {
22505 : InterruptThread i_thread(this);
22506 6 : i_thread.Start();
22507 :
22508 6 : sem_.Wait();
22509 6 : CHECK_EQ(kExpectedValue, sem_value_);
22510 6 : }
22511 :
22512 : private:
22513 : static const int kExpectedValue = 1;
22514 :
22515 6 : class InterruptThread : public v8::base::Thread {
22516 : public:
22517 : explicit InterruptThread(ThreadInterruptTest* test)
22518 6 : : Thread(Options("InterruptThread")), test_(test) {}
22519 :
22520 6 : void Run() override {
22521 : struct sigaction action;
22522 :
22523 : // Ensure that we'll enter waiting condition
22524 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22525 :
22526 : // Setup signal handler
22527 : memset(&action, 0, sizeof(action));
22528 6 : action.sa_handler = SignalHandler;
22529 6 : sigaction(SIGCHLD, &action, nullptr);
22530 :
22531 : // Send signal
22532 6 : kill(getpid(), SIGCHLD);
22533 :
22534 : // Ensure that if wait has returned because of error
22535 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22536 :
22537 : // Set value and signal semaphore
22538 6 : test_->sem_value_ = 1;
22539 6 : test_->sem_.Signal();
22540 6 : }
22541 :
22542 6 : static void SignalHandler(int signal) {
22543 6 : }
22544 :
22545 : private:
22546 : ThreadInterruptTest* test_;
22547 : };
22548 :
22549 : v8::base::Semaphore sem_;
22550 : volatile int sem_value_;
22551 : };
22552 :
22553 :
22554 26645 : THREADED_TEST(SemaphoreInterruption) {
22555 12 : ThreadInterruptTest().RunTest();
22556 6 : }
22557 :
22558 :
22559 : #endif // V8_OS_POSIX
22560 :
22561 :
22562 0 : void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22563 0 : UNREACHABLE();
22564 : }
22565 :
22566 :
22567 26644 : TEST(JSONStringifyAccessCheck) {
22568 5 : v8::V8::Initialize();
22569 5 : v8::Isolate* isolate = CcTest::isolate();
22570 10 : v8::HandleScope scope(isolate);
22571 :
22572 : // Create an ObjectTemplate for global objects and install access
22573 : // check callbacks that will block access.
22574 : v8::Local<v8::ObjectTemplate> global_template =
22575 5 : v8::ObjectTemplate::New(isolate);
22576 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22577 :
22578 : // Create a context and set an x property on it's global object.
22579 5 : LocalContext context0(nullptr, global_template);
22580 5 : v8::Local<v8::Object> global0 = context0->Global();
22581 15 : global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
22582 5 : ExpectString("JSON.stringify(this)", "{\"x\":42}");
22583 :
22584 25 : for (int i = 0; i < 2; i++) {
22585 10 : if (i == 1) {
22586 : // Install a toJSON function on the second run.
22587 : v8::Local<v8::FunctionTemplate> toJSON =
22588 5 : v8::FunctionTemplate::New(isolate, UnreachableCallback);
22589 :
22590 10 : global0->Set(context0.local(), v8_str("toJSON"),
22591 15 : toJSON->GetFunction(context0.local()).ToLocalChecked())
22592 : .FromJust();
22593 : }
22594 : // Create a context with a different security token so that the
22595 : // failed access check callback will be called on each access.
22596 10 : LocalContext context1(nullptr, global_template);
22597 40 : CHECK(context1->Global()
22598 : ->Set(context1.local(), v8_str("other"), global0)
22599 : .FromJust());
22600 :
22601 10 : CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22602 10 : CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22603 10 : CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22604 : }
22605 5 : }
22606 :
22607 :
22608 : bool access_check_fail_thrown = false;
22609 : bool catch_callback_called = false;
22610 :
22611 :
22612 : // Failed access check callback that performs a GC on each invocation.
22613 80 : void FailedAccessCheckThrows(Local<v8::Object> target,
22614 : v8::AccessType type,
22615 : Local<v8::Value> data) {
22616 80 : access_check_fail_thrown = true;
22617 80 : i::PrintF("Access check failed. Error thrown.\n");
22618 : CcTest::isolate()->ThrowException(
22619 80 : v8::Exception::Error(v8_str("cross context")));
22620 80 : }
22621 :
22622 :
22623 75 : void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22624 225 : for (int i = 0; i < args.Length(); i++) {
22625 75 : i::PrintF("%s\n", *String::Utf8Value(args.GetIsolate(), args[i]));
22626 : }
22627 75 : catch_callback_called = true;
22628 75 : }
22629 :
22630 :
22631 5 : void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22632 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
22633 20 : CHECK(
22634 : args[0]
22635 : ->ToObject(context)
22636 : .ToLocalChecked()
22637 : ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
22638 : .IsNothing());
22639 5 : }
22640 :
22641 :
22642 75 : void CheckCorrectThrow(const char* script) {
22643 : // Test that the script, when wrapped into a try-catch, triggers the catch
22644 : // clause due to failed access check throwing an exception.
22645 : // The subsequent try-catch should run without any exception.
22646 75 : access_check_fail_thrown = false;
22647 75 : catch_callback_called = false;
22648 : i::ScopedVector<char> source(1024);
22649 75 : i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22650 : CompileRun(source.start());
22651 75 : CHECK(access_check_fail_thrown);
22652 75 : CHECK(catch_callback_called);
22653 :
22654 75 : access_check_fail_thrown = false;
22655 75 : catch_callback_called = false;
22656 : CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22657 75 : CHECK(!access_check_fail_thrown);
22658 75 : CHECK(!catch_callback_called);
22659 75 : }
22660 :
22661 :
22662 26644 : TEST(AccessCheckThrows) {
22663 5 : i::FLAG_allow_natives_syntax = true;
22664 5 : v8::V8::Initialize();
22665 5 : v8::Isolate* isolate = CcTest::isolate();
22666 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22667 10 : v8::HandleScope scope(isolate);
22668 :
22669 : // Create an ObjectTemplate for global objects and install access
22670 : // check callbacks that will block access.
22671 : v8::Local<v8::ObjectTemplate> global_template =
22672 5 : v8::ObjectTemplate::New(isolate);
22673 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22674 :
22675 : // Create a context and set an x property on it's global object.
22676 5 : LocalContext context0(nullptr, global_template);
22677 5 : v8::Local<v8::Object> global0 = context0->Global();
22678 15 : CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
22679 :
22680 : // Create a context with a different security token so that the
22681 : // failed access check callback will be called on each access.
22682 5 : LocalContext context1(nullptr, global_template);
22683 20 : CHECK(context1->Global()
22684 : ->Set(context1.local(), v8_str("other"), global0)
22685 : .FromJust());
22686 :
22687 : v8::Local<v8::FunctionTemplate> catcher_fun =
22688 5 : v8::FunctionTemplate::New(isolate, CatcherCallback);
22689 25 : CHECK(context1->Global()
22690 : ->Set(context1.local(), v8_str("catcher"),
22691 : catcher_fun->GetFunction(context1.local()).ToLocalChecked())
22692 : .FromJust());
22693 :
22694 : v8::Local<v8::FunctionTemplate> has_own_property_fun =
22695 5 : v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22696 25 : CHECK(context1->Global()
22697 : ->Set(context1.local(), v8_str("has_own_property"),
22698 : has_own_property_fun->GetFunction(context1.local())
22699 : .ToLocalChecked())
22700 : .FromJust());
22701 :
22702 : {
22703 10 : v8::TryCatch try_catch(isolate);
22704 5 : access_check_fail_thrown = false;
22705 : CompileRun("other.x;");
22706 5 : CHECK(access_check_fail_thrown);
22707 5 : CHECK(try_catch.HasCaught());
22708 : }
22709 :
22710 5 : CheckCorrectThrow("other.x");
22711 5 : CheckCorrectThrow("other[1]");
22712 5 : CheckCorrectThrow("JSON.stringify(other)");
22713 5 : CheckCorrectThrow("has_own_property(other, 'x')");
22714 5 : CheckCorrectThrow("%GetProperty(other, 'x')");
22715 5 : CheckCorrectThrow("%SetKeyedProperty(other, 'x', 'foo')");
22716 5 : CheckCorrectThrow("%SetNamedProperty(other, 'y', 'foo')");
22717 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kSloppy) == 0);
22718 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kStrict) == 1);
22719 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); // 0 == SLOPPY
22720 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 1)"); // 1 == STRICT
22721 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22722 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 1)");
22723 5 : CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
22724 5 : CheckCorrectThrow("%HasProperty(other, 'x')");
22725 5 : CheckCorrectThrow("Object.prototype.propertyIsEnumerable(other, 'x')");
22726 : // PROPERTY_ATTRIBUTES_NONE = 0
22727 : CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22728 5 : "other, 'x', null, null, 1)");
22729 :
22730 : // Reset the failed access check callback so it does not influence
22731 : // the other tests.
22732 5 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
22733 5 : }
22734 :
22735 : namespace {
22736 :
22737 : const char kOneByteSubjectString[] = {
22738 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22739 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22740 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};
22741 : const uint16_t kTwoByteSubjectString[] = {
22742 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22743 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22744 : 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};
22745 :
22746 : const int kSubjectStringLength = arraysize(kOneByteSubjectString) - 1;
22747 : STATIC_ASSERT(arraysize(kOneByteSubjectString) ==
22748 : arraysize(kTwoByteSubjectString));
22749 :
22750 26639 : OneByteVectorResource one_byte_string_resource(
22751 : i::Vector<const char>(&kOneByteSubjectString[0], kSubjectStringLength));
22752 26639 : UC16VectorResource two_byte_string_resource(
22753 : i::Vector<const i::uc16>(&kTwoByteSubjectString[0], kSubjectStringLength));
22754 :
22755 45 : class RegExpInterruptTest {
22756 : public:
22757 15 : RegExpInterruptTest()
22758 : : i_thread(this),
22759 : env_(),
22760 15 : isolate_(env_->GetIsolate()),
22761 : sem_(0),
22762 : ran_test_body_(false),
22763 45 : ran_to_completion_(false) {}
22764 :
22765 15 : void RunTest(v8::InterruptCallback test_body_fn) {
22766 30 : v8::HandleScope handle_scope(isolate_);
22767 :
22768 : i_thread.SetTestBody(test_body_fn);
22769 15 : i_thread.Start();
22770 :
22771 15 : TestBody();
22772 :
22773 15 : i_thread.Join();
22774 15 : }
22775 :
22776 5 : static void CollectAllGarbage(v8::Isolate* isolate, void* data) {
22777 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22778 : i_isolate->heap()->PreciseCollectAllGarbage(
22779 5 : i::Heap::kNoGCFlags, i::GarbageCollectionReason::kRuntime);
22780 5 : }
22781 :
22782 5 : static void MakeSubjectOneByteExternal(v8::Isolate* isolate, void* data) {
22783 : auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22784 :
22785 10 : v8::HandleScope scope(isolate);
22786 : v8::Local<v8::String> string =
22787 : v8::Local<v8::String>::New(isolate, instance->string_handle_);
22788 5 : CHECK(string->CanMakeExternal());
22789 5 : string->MakeExternal(&one_byte_string_resource);
22790 5 : }
22791 :
22792 5 : static void MakeSubjectTwoByteExternal(v8::Isolate* isolate, void* data) {
22793 : auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22794 :
22795 10 : v8::HandleScope scope(isolate);
22796 : v8::Local<v8::String> string =
22797 : v8::Local<v8::String>::New(isolate, instance->string_handle_);
22798 5 : CHECK(string->CanMakeExternal());
22799 5 : string->MakeExternal(&two_byte_string_resource);
22800 5 : }
22801 :
22802 : private:
22803 30 : static void SignalSemaphore(v8::Isolate* isolate, void* data) {
22804 30 : reinterpret_cast<RegExpInterruptTest*>(data)->sem_.Signal();
22805 30 : }
22806 :
22807 15 : void CreateTestStrings() {
22808 15 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
22809 :
22810 : // The string must be in old space to support externalization.
22811 : i::Handle<i::String> i_string =
22812 : i_isolate->factory()->NewStringFromAsciiChecked(
22813 15 : &kOneByteSubjectString[0], i::AllocationType::kOld);
22814 : v8::Local<v8::String> string = v8::Utils::ToLocal(i_string);
22815 :
22816 60 : env_->Global()->Set(env_.local(), v8_str("a"), string).FromJust();
22817 :
22818 15 : string_handle_.Reset(env_->GetIsolate(), string);
22819 15 : }
22820 :
22821 15 : void TestBody() {
22822 15 : CHECK(!ran_test_body_.load());
22823 15 : CHECK(!ran_to_completion_.load());
22824 :
22825 15 : CreateTestStrings();
22826 :
22827 30 : v8::TryCatch try_catch(env_->GetIsolate());
22828 :
22829 15 : isolate_->RequestInterrupt(&SignalSemaphore, this);
22830 : CompileRun("/((a*)*)*b/.exec(a)");
22831 :
22832 15 : CHECK(try_catch.HasTerminated());
22833 15 : CHECK(ran_test_body_.load());
22834 15 : CHECK(ran_to_completion_.load());
22835 15 : }
22836 :
22837 15 : class InterruptThread : public v8::base::Thread {
22838 : public:
22839 : explicit InterruptThread(RegExpInterruptTest* test)
22840 15 : : Thread(Options("RegExpInterruptTest")), test_(test) {}
22841 :
22842 15 : void Run() override {
22843 15 : CHECK_NOT_NULL(test_body_fn_);
22844 :
22845 : // Wait for JS execution to start.
22846 15 : test_->sem_.Wait();
22847 :
22848 : // Sleep for a bit to allow irregexp execution to start up, then run the
22849 : // test body.
22850 15 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
22851 15 : test_->isolate_->RequestInterrupt(&RunTestBody, test_);
22852 15 : test_->isolate_->RequestInterrupt(&SignalSemaphore, test_);
22853 :
22854 : // Wait for the scheduled interrupt to signal.
22855 15 : test_->sem_.Wait();
22856 :
22857 : // Sleep again to resume irregexp execution, then terminate.
22858 15 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
22859 15 : test_->ran_to_completion_.store(true);
22860 15 : test_->isolate_->TerminateExecution();
22861 15 : }
22862 :
22863 15 : static void RunTestBody(v8::Isolate* isolate, void* data) {
22864 : auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22865 15 : instance->i_thread.test_body_fn_(isolate, data);
22866 : instance->ran_test_body_.store(true);
22867 15 : }
22868 :
22869 : void SetTestBody(v8::InterruptCallback callback) {
22870 15 : test_body_fn_ = callback;
22871 : }
22872 :
22873 : private:
22874 : v8::InterruptCallback test_body_fn_;
22875 : RegExpInterruptTest* test_;
22876 : };
22877 :
22878 : InterruptThread i_thread;
22879 :
22880 : LocalContext env_;
22881 : v8::Isolate* isolate_;
22882 : v8::base::Semaphore sem_; // Coordinates between main and interrupt threads.
22883 :
22884 : v8::Persistent<v8::String> string_handle_;
22885 :
22886 : std::atomic<bool> ran_test_body_;
22887 : std::atomic<bool> ran_to_completion_;
22888 : };
22889 :
22890 : } // namespace
22891 :
22892 26644 : TEST(RegExpInterruptAndCollectAllGarbage) {
22893 5 : i::FLAG_always_compact = true; // Move all movable objects on GC.
22894 10 : RegExpInterruptTest test;
22895 5 : test.RunTest(RegExpInterruptTest::CollectAllGarbage);
22896 5 : }
22897 :
22898 26644 : TEST(RegExpInterruptAndMakeSubjectOneByteExternal) {
22899 10 : RegExpInterruptTest test;
22900 5 : test.RunTest(RegExpInterruptTest::MakeSubjectOneByteExternal);
22901 5 : }
22902 :
22903 26644 : TEST(RegExpInterruptAndMakeSubjectTwoByteExternal) {
22904 10 : RegExpInterruptTest test;
22905 5 : test.RunTest(RegExpInterruptTest::MakeSubjectTwoByteExternal);
22906 5 : }
22907 :
22908 : class RequestInterruptTestBase {
22909 : public:
22910 35 : RequestInterruptTestBase()
22911 : : env_(),
22912 35 : isolate_(env_->GetIsolate()),
22913 : sem_(0),
22914 : warmup_(20000),
22915 70 : should_continue_(true) {
22916 35 : }
22917 :
22918 35 : virtual ~RequestInterruptTestBase() = default;
22919 :
22920 : virtual void StartInterruptThread() = 0;
22921 :
22922 : virtual void TestBody() = 0;
22923 :
22924 35 : void RunTest() {
22925 35 : StartInterruptThread();
22926 :
22927 70 : v8::HandleScope handle_scope(isolate_);
22928 :
22929 35 : TestBody();
22930 :
22931 : // Verify we arrived here because interruptor was called
22932 : // not due to a bug causing us to exit the loop too early.
22933 35 : CHECK(!should_continue());
22934 35 : }
22935 :
22936 : void WakeUpInterruptor() {
22937 35 : sem_.Signal();
22938 : }
22939 :
22940 : bool should_continue() const { return should_continue_; }
22941 :
22942 : bool ShouldContinue() {
22943 810398 : if (warmup_ > 0) {
22944 600000 : if (--warmup_ == 0) {
22945 : WakeUpInterruptor();
22946 : }
22947 : }
22948 :
22949 810398 : return should_continue_;
22950 : }
22951 :
22952 702611 : static void ShouldContinueCallback(
22953 : const v8::FunctionCallbackInfo<Value>& info) {
22954 : RequestInterruptTestBase* test =
22955 : reinterpret_cast<RequestInterruptTestBase*>(
22956 702611 : info.Data().As<v8::External>()->Value());
22957 : info.GetReturnValue().Set(test->ShouldContinue());
22958 702611 : }
22959 :
22960 : LocalContext env_;
22961 : v8::Isolate* isolate_;
22962 : v8::base::Semaphore sem_;
22963 : int warmup_;
22964 : bool should_continue_;
22965 : };
22966 :
22967 :
22968 60 : class RequestInterruptTestBaseWithSimpleInterrupt
22969 : : public RequestInterruptTestBase {
22970 : public:
22971 60 : RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22972 :
22973 30 : void StartInterruptThread() override { i_thread.Start(); }
22974 :
22975 : private:
22976 30 : class InterruptThread : public v8::base::Thread {
22977 : public:
22978 : explicit InterruptThread(RequestInterruptTestBase* test)
22979 30 : : Thread(Options("RequestInterruptTest")), test_(test) {}
22980 :
22981 30 : void Run() override {
22982 30 : test_->sem_.Wait();
22983 30 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22984 30 : }
22985 :
22986 30 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
22987 : reinterpret_cast<RequestInterruptTestBase*>(data)->
22988 30 : should_continue_ = false;
22989 30 : }
22990 :
22991 : private:
22992 : RequestInterruptTestBase* test_;
22993 : };
22994 :
22995 : InterruptThread i_thread;
22996 : };
22997 :
22998 :
22999 10 : class RequestInterruptTestWithFunctionCall
23000 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23001 : public:
23002 5 : void TestBody() override {
23003 5 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23004 10 : v8::External::New(isolate_, this))
23005 : .ToLocalChecked();
23006 20 : CHECK(env_->Global()
23007 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23008 : .FromJust());
23009 :
23010 : CompileRun("while (ShouldContinue()) { }");
23011 5 : }
23012 : };
23013 :
23014 :
23015 10 : class RequestInterruptTestWithMethodCall
23016 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23017 : public:
23018 5 : void TestBody() override {
23019 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23020 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23021 20 : proto->Set(v8_str("shouldContinue"),
23022 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23023 5 : v8::External::New(isolate_, this)));
23024 25 : CHECK(env_->Global()
23025 : ->Set(env_.local(), v8_str("Klass"),
23026 : t->GetFunction(env_.local()).ToLocalChecked())
23027 : .FromJust());
23028 :
23029 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23030 5 : }
23031 : };
23032 :
23033 :
23034 10 : class RequestInterruptTestWithAccessor
23035 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23036 : public:
23037 5 : void TestBody() override {
23038 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23039 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23040 15 : proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23041 5 : isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23042 25 : CHECK(env_->Global()
23043 : ->Set(env_.local(), v8_str("Klass"),
23044 : t->GetFunction(env_.local()).ToLocalChecked())
23045 : .FromJust());
23046 :
23047 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23048 5 : }
23049 : };
23050 :
23051 :
23052 10 : class RequestInterruptTestWithNativeAccessor
23053 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23054 : public:
23055 5 : void TestBody() override {
23056 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23057 15 : t->InstanceTemplate()->SetNativeDataProperty(
23058 : v8_str("shouldContinue"), &ShouldContinueNativeGetter, nullptr,
23059 5 : v8::External::New(isolate_, this));
23060 25 : CHECK(env_->Global()
23061 : ->Set(env_.local(), v8_str("Klass"),
23062 : t->GetFunction(env_.local()).ToLocalChecked())
23063 : .FromJust());
23064 :
23065 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23066 5 : }
23067 :
23068 : private:
23069 107787 : static void ShouldContinueNativeGetter(
23070 : Local<String> property,
23071 : const v8::PropertyCallbackInfo<v8::Value>& info) {
23072 : RequestInterruptTestBase* test =
23073 : reinterpret_cast<RequestInterruptTestBase*>(
23074 107787 : info.Data().As<v8::External>()->Value());
23075 : info.GetReturnValue().Set(test->ShouldContinue());
23076 107787 : }
23077 : };
23078 :
23079 :
23080 10 : class RequestInterruptTestWithMethodCallAndInterceptor
23081 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23082 : public:
23083 5 : void TestBody() override {
23084 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23085 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23086 20 : proto->Set(v8_str("shouldContinue"),
23087 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23088 5 : v8::External::New(isolate_, this)));
23089 5 : v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23090 5 : instance_template->SetHandler(
23091 5 : v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23092 :
23093 25 : CHECK(env_->Global()
23094 : ->Set(env_.local(), v8_str("Klass"),
23095 : t->GetFunction(env_.local()).ToLocalChecked())
23096 : .FromJust());
23097 :
23098 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23099 5 : }
23100 :
23101 : private:
23102 121078 : static void EmptyInterceptor(
23103 121078 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23104 : };
23105 :
23106 :
23107 10 : class RequestInterruptTestWithMathAbs
23108 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23109 : public:
23110 5 : void TestBody() override {
23111 10 : env_->Global()
23112 10 : ->Set(env_.local(), v8_str("WakeUpInterruptor"),
23113 5 : Function::New(env_.local(), WakeUpInterruptorCallback,
23114 10 : v8::External::New(isolate_, this))
23115 10 : .ToLocalChecked())
23116 : .FromJust();
23117 :
23118 10 : env_->Global()
23119 10 : ->Set(env_.local(), v8_str("ShouldContinue"),
23120 5 : Function::New(env_.local(), ShouldContinueCallback,
23121 10 : v8::External::New(isolate_, this))
23122 10 : .ToLocalChecked())
23123 : .FromJust();
23124 :
23125 5 : i::FLAG_allow_natives_syntax = true;
23126 : CompileRun("function loopish(o) {"
23127 : " var pre = 10;"
23128 : " while (o.abs(1) > 0) {"
23129 : " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23130 : " if (pre > 0) {"
23131 : " if (--pre === 0) WakeUpInterruptor(o === Math);"
23132 : " }"
23133 : " }"
23134 : "}"
23135 : "var i = 50;"
23136 : "var obj = {abs: function () { return i-- }, x: null};"
23137 : "delete obj.x;"
23138 : "loopish(obj);"
23139 : "%OptimizeFunctionOnNextCall(loopish);"
23140 : "loopish(Math);");
23141 :
23142 5 : i::FLAG_allow_natives_syntax = false;
23143 5 : }
23144 :
23145 : private:
23146 10 : static void WakeUpInterruptorCallback(
23147 : const v8::FunctionCallbackInfo<Value>& info) {
23148 10 : if (!info[0]->BooleanValue(info.GetIsolate())) {
23149 : return;
23150 : }
23151 :
23152 : RequestInterruptTestBase* test =
23153 : reinterpret_cast<RequestInterruptTestBase*>(
23154 5 : info.Data().As<v8::External>()->Value());
23155 : test->WakeUpInterruptor();
23156 : }
23157 :
23158 7538 : static void ShouldContinueCallback(
23159 : const v8::FunctionCallbackInfo<Value>& info) {
23160 : RequestInterruptTestBase* test =
23161 : reinterpret_cast<RequestInterruptTestBase*>(
23162 7538 : info.Data().As<v8::External>()->Value());
23163 : info.GetReturnValue().Set(test->should_continue());
23164 7538 : }
23165 : };
23166 :
23167 :
23168 26644 : TEST(RequestInterruptTestWithFunctionCall) {
23169 15 : RequestInterruptTestWithFunctionCall().RunTest();
23170 5 : }
23171 :
23172 :
23173 26644 : TEST(RequestInterruptTestWithMethodCall) {
23174 15 : RequestInterruptTestWithMethodCall().RunTest();
23175 5 : }
23176 :
23177 :
23178 26644 : TEST(RequestInterruptTestWithAccessor) {
23179 15 : RequestInterruptTestWithAccessor().RunTest();
23180 5 : }
23181 :
23182 :
23183 26644 : TEST(RequestInterruptTestWithNativeAccessor) {
23184 15 : RequestInterruptTestWithNativeAccessor().RunTest();
23185 5 : }
23186 :
23187 :
23188 26644 : TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23189 15 : RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23190 5 : }
23191 :
23192 :
23193 26644 : TEST(RequestInterruptTestWithMathAbs) {
23194 15 : RequestInterruptTestWithMathAbs().RunTest();
23195 5 : }
23196 :
23197 :
23198 10 : class RequestMultipleInterrupts : public RequestInterruptTestBase {
23199 : public:
23200 10 : RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23201 :
23202 5 : void StartInterruptThread() override { i_thread.Start(); }
23203 :
23204 5 : void TestBody() override {
23205 5 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23206 10 : v8::External::New(isolate_, this))
23207 : .ToLocalChecked();
23208 20 : CHECK(env_->Global()
23209 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23210 : .FromJust());
23211 :
23212 : CompileRun("while (ShouldContinue()) { }");
23213 5 : }
23214 :
23215 : private:
23216 5 : class InterruptThread : public v8::base::Thread {
23217 : public:
23218 : enum { NUM_INTERRUPTS = 10 };
23219 : explicit InterruptThread(RequestMultipleInterrupts* test)
23220 5 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23221 :
23222 5 : void Run() override {
23223 5 : test_->sem_.Wait();
23224 105 : for (int i = 0; i < NUM_INTERRUPTS; i++) {
23225 50 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23226 : }
23227 5 : }
23228 :
23229 50 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23230 : RequestMultipleInterrupts* test =
23231 : reinterpret_cast<RequestMultipleInterrupts*>(data);
23232 50 : test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23233 50 : }
23234 :
23235 : private:
23236 : RequestMultipleInterrupts* test_;
23237 : };
23238 :
23239 : InterruptThread i_thread;
23240 : int counter_;
23241 : };
23242 :
23243 :
23244 26644 : TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23245 :
23246 :
23247 : static bool interrupt_was_called = false;
23248 :
23249 :
23250 5 : void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
23251 5 : interrupt_was_called = true;
23252 5 : }
23253 :
23254 :
23255 26644 : TEST(RequestInterruptSmallScripts) {
23256 5 : LocalContext env;
23257 5 : v8::Isolate* isolate = CcTest::isolate();
23258 10 : v8::HandleScope scope(isolate);
23259 :
23260 5 : interrupt_was_called = false;
23261 5 : isolate->RequestInterrupt(&SmallScriptsInterruptCallback, nullptr);
23262 : CompileRun("(function(x){return x;})(1);");
23263 5 : CHECK(interrupt_was_called);
23264 5 : }
23265 :
23266 :
23267 : static Local<Value> function_new_expected_env;
23268 12 : static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23269 36 : CHECK(
23270 : function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
23271 : info.Data())
23272 : .FromJust());
23273 : info.GetReturnValue().Set(17);
23274 12 : }
23275 :
23276 :
23277 26645 : THREADED_TEST(FunctionNew) {
23278 6 : LocalContext env;
23279 6 : v8::Isolate* isolate = env->GetIsolate();
23280 12 : v8::HandleScope scope(isolate);
23281 6 : Local<Object> data = v8::Object::New(isolate);
23282 6 : function_new_expected_env = data;
23283 : Local<Function> func =
23284 12 : Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
23285 24 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
23286 6 : Local<Value> result = CompileRun("func();");
23287 18 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
23288 : // Serial number should be invalid => should not be cached.
23289 : auto serial_number =
23290 : i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
23291 : ->shared()
23292 : ->get_api_func_data()
23293 : ->serial_number())
23294 : ->value();
23295 6 : CHECK_EQ(i::FunctionTemplateInfo::kInvalidSerialNumber, serial_number);
23296 :
23297 : // Verify that each Function::New creates a new function instance
23298 6 : Local<Object> data2 = v8::Object::New(isolate);
23299 6 : function_new_expected_env = data2;
23300 : Local<Function> func2 =
23301 12 : Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
23302 6 : CHECK(!func2->IsNull());
23303 12 : CHECK(!func->Equals(env.local(), func2).FromJust());
23304 24 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
23305 6 : Local<Value> result2 = CompileRun("func2();");
23306 18 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
23307 6 : }
23308 :
23309 : namespace {
23310 :
23311 : void Verify(v8::Isolate* isolate, Local<v8::Object> obj) {
23312 : #if VERIFY_HEAP
23313 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23314 : i::Handle<i::JSReceiver> i_obj = v8::Utils::OpenHandle(*obj);
23315 : i_obj->ObjectVerify(i_isolate);
23316 : #endif
23317 : }
23318 :
23319 : } // namespace
23320 :
23321 26645 : THREADED_TEST(ObjectNew) {
23322 6 : LocalContext env;
23323 6 : v8::Isolate* isolate = env->GetIsolate();
23324 12 : v8::HandleScope scope(isolate);
23325 : {
23326 : // Verify that Object::New(null) produces an object with a null
23327 : // [[Prototype]].
23328 : Local<v8::Object> obj =
23329 6 : v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0);
23330 12 : CHECK(obj->GetPrototype()->IsNull());
23331 : Verify(isolate, obj);
23332 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23333 6 : CHECK_EQ(0, keys->Length());
23334 : }
23335 : {
23336 : // Verify that Object::New(proto) produces an object with
23337 : // proto as it's [[Prototype]].
23338 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23339 : Local<v8::Object> obj =
23340 6 : v8::Object::New(isolate, proto, nullptr, nullptr, 0);
23341 : Verify(isolate, obj);
23342 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23343 : }
23344 : {
23345 : // Verify that the properties are installed correctly.
23346 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("b"), v8_str("c")};
23347 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23348 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23349 6 : values, arraysize(values));
23350 : Verify(isolate, obj);
23351 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23352 6 : CHECK_EQ(arraysize(names), keys->Length());
23353 42 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23354 36 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23355 36 : CHECK(values[i]->SameValue(
23356 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23357 : }
23358 : }
23359 : {
23360 : // Same as above, but with non-null prototype.
23361 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23362 18 : Local<v8::Name> names[3] = {v8_str("x"), v8_str("y"), v8_str("z")};
23363 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23364 : Local<v8::Object> obj =
23365 6 : v8::Object::New(isolate, proto, names, values, arraysize(values));
23366 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23367 : Verify(isolate, obj);
23368 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23369 6 : CHECK_EQ(arraysize(names), keys->Length());
23370 42 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23371 36 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23372 36 : CHECK(values[i]->SameValue(
23373 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23374 : }
23375 : }
23376 : {
23377 : // This has to work with duplicate names too.
23378 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("a"), v8_str("a")};
23379 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23380 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23381 6 : values, arraysize(values));
23382 : Verify(isolate, obj);
23383 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23384 6 : CHECK_EQ(1, keys->Length());
23385 18 : CHECK(v8_str("a")->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23386 24 : CHECK(v8_num(3)->SameValue(
23387 : obj->Get(env.local(), v8_str("a")).ToLocalChecked()));
23388 : }
23389 : {
23390 : // This has to work with array indices too.
23391 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("1")};
23392 6 : Local<v8::Value> values[2] = {v8_num(0), v8_num(1)};
23393 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23394 6 : values, arraysize(values));
23395 : Verify(isolate, obj);
23396 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23397 6 : CHECK_EQ(arraysize(names), keys->Length());
23398 30 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23399 36 : CHECK(v8::Number::New(isolate, i)
23400 : ->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23401 24 : CHECK(values[i]->SameValue(obj->Get(env.local(), i).ToLocalChecked()));
23402 : }
23403 : }
23404 : {
23405 : // This has to work with mixed array indices / property names too.
23406 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("x")};
23407 6 : Local<v8::Value> values[2] = {v8_num(42), v8_num(24)};
23408 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23409 6 : values, arraysize(values));
23410 : Verify(isolate, obj);
23411 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23412 6 : CHECK_EQ(arraysize(names), keys->Length());
23413 : // 0 -> 42
23414 18 : CHECK(v8_num(0)->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23415 12 : CHECK(
23416 : values[0]->SameValue(obj->Get(env.local(), names[0]).ToLocalChecked()));
23417 : // "x" -> 24
23418 18 : CHECK(v8_str("x")->SameValue(keys->Get(env.local(), 1).ToLocalChecked()));
23419 12 : CHECK(
23420 : values[1]->SameValue(obj->Get(env.local(), names[1]).ToLocalChecked()));
23421 : }
23422 : {
23423 : // Verify that this also works for a couple thousand properties.
23424 : size_t const kLength = 10 * 1024;
23425 122886 : Local<v8::Name> names[kLength];
23426 122886 : Local<v8::Value> values[kLength];
23427 122886 : for (size_t i = 0; i < arraysize(names); ++i) {
23428 122880 : std::ostringstream ost;
23429 : ost << "a" << i;
23430 122880 : names[i] = v8_str(ost.str().c_str());
23431 61440 : values[i] = v8_num(static_cast<double>(i));
23432 : }
23433 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23434 6 : values, arraysize(names));
23435 : Verify(isolate, obj);
23436 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23437 6 : CHECK_EQ(arraysize(names), keys->Length());
23438 122886 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23439 122880 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23440 122880 : CHECK(values[i]->SameValue(
23441 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23442 : }
23443 : }
23444 6 : }
23445 :
23446 26644 : TEST(EscapableHandleScope) {
23447 10 : HandleScope outer_scope(CcTest::isolate());
23448 5 : LocalContext context;
23449 : const int runs = 10;
23450 105 : Local<String> values[runs];
23451 105 : for (int i = 0; i < runs; i++) {
23452 50 : v8::EscapableHandleScope inner_scope(CcTest::isolate());
23453 : Local<String> value;
23454 50 : if (i != 0) value = v8_str("escape value");
23455 50 : if (i < runs / 2) {
23456 25 : values[i] = inner_scope.Escape(value);
23457 : } else {
23458 : values[i] = inner_scope.EscapeMaybe(v8::MaybeLocal<String>(value))
23459 25 : .ToLocalChecked();
23460 : }
23461 : }
23462 105 : for (int i = 0; i < runs; i++) {
23463 : Local<String> expected;
23464 50 : if (i != 0) {
23465 135 : CHECK(v8_str("escape value")
23466 : ->Equals(context.local(), values[i])
23467 : .FromJust());
23468 : } else {
23469 5 : CHECK(values[i].IsEmpty());
23470 : }
23471 : }
23472 5 : }
23473 :
23474 :
23475 20 : static void SetterWhichExpectsThisAndHolderToDiffer(
23476 : Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23477 20 : CHECK(info.Holder() != info.This());
23478 20 : }
23479 :
23480 :
23481 26644 : TEST(Regress239669) {
23482 5 : LocalContext context;
23483 5 : v8::Isolate* isolate = context->GetIsolate();
23484 10 : v8::HandleScope scope(isolate);
23485 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23486 10 : templ->SetAccessor(v8_str("x"), nullptr,
23487 5 : SetterWhichExpectsThisAndHolderToDiffer);
23488 25 : CHECK(context->Global()
23489 : ->Set(context.local(), v8_str("P"),
23490 : templ->NewInstance(context.local()).ToLocalChecked())
23491 : .FromJust());
23492 : CompileRun(
23493 : "function C1() {"
23494 : " this.x = 23;"
23495 : "};"
23496 : "C1.prototype = P;"
23497 : "for (var i = 0; i < 4; i++ ) {"
23498 : " new C1();"
23499 : "}");
23500 5 : }
23501 :
23502 :
23503 : class ApiCallOptimizationChecker {
23504 : private:
23505 : static Local<Object> data;
23506 : static Local<Object> receiver;
23507 : static Local<Object> holder;
23508 : static Local<Object> callee;
23509 : static int count;
23510 :
23511 270 : static void OptimizationCallback(
23512 : const v8::FunctionCallbackInfo<v8::Value>& info) {
23513 270 : CHECK(data == info.Data());
23514 270 : CHECK(receiver == info.This());
23515 270 : if (info.Length() == 1) {
23516 270 : CHECK(v8_num(1)
23517 : ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
23518 : .FromJust());
23519 : }
23520 270 : CHECK(holder == info.Holder());
23521 270 : count++;
23522 270 : info.GetReturnValue().Set(v8_str("returned"));
23523 270 : }
23524 :
23525 : public:
23526 : enum SignatureType {
23527 : kNoSignature,
23528 : kSignatureOnReceiver,
23529 : kSignatureOnPrototype
23530 : };
23531 :
23532 5 : void RunAll() {
23533 : SignatureType signature_types[] =
23534 5 : {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23535 35 : for (unsigned i = 0; i < arraysize(signature_types); i++) {
23536 15 : SignatureType signature_type = signature_types[i];
23537 75 : for (int j = 0; j < 2; j++) {
23538 30 : bool global = j == 0;
23539 : int key = signature_type +
23540 30 : arraysize(signature_types) * (global ? 1 : 0);
23541 30 : Run(signature_type, global, key);
23542 : }
23543 : }
23544 5 : }
23545 :
23546 30 : void Run(SignatureType signature_type, bool global, int key) {
23547 30 : v8::Isolate* isolate = CcTest::isolate();
23548 60 : v8::HandleScope scope(isolate);
23549 : // Build a template for signature checks.
23550 : Local<v8::ObjectTemplate> signature_template;
23551 : Local<v8::Signature> signature;
23552 : {
23553 : Local<v8::FunctionTemplate> parent_template =
23554 30 : FunctionTemplate::New(isolate);
23555 : Local<v8::FunctionTemplate> function_template
23556 30 : = FunctionTemplate::New(isolate);
23557 30 : function_template->Inherit(parent_template);
23558 30 : switch (signature_type) {
23559 : case kNoSignature:
23560 : break;
23561 : case kSignatureOnReceiver:
23562 10 : signature = v8::Signature::New(isolate, function_template);
23563 10 : break;
23564 : case kSignatureOnPrototype:
23565 10 : signature = v8::Signature::New(isolate, parent_template);
23566 10 : break;
23567 : }
23568 30 : signature_template = function_template->InstanceTemplate();
23569 : }
23570 : // Global object must pass checks.
23571 : Local<v8::Context> context =
23572 30 : v8::Context::New(isolate, nullptr, signature_template);
23573 : v8::Context::Scope context_scope(context);
23574 : // Install regular object that can pass signature checks.
23575 : Local<Object> function_receiver =
23576 30 : signature_template->NewInstance(context).ToLocalChecked();
23577 120 : CHECK(context->Global()
23578 : ->Set(context, v8_str("function_receiver"), function_receiver)
23579 : .FromJust());
23580 : // Get the holder objects.
23581 : Local<Object> inner_global =
23582 60 : Local<Object>::Cast(context->Global()->GetPrototype());
23583 30 : data = Object::New(isolate);
23584 : Local<FunctionTemplate> function_template = FunctionTemplate::New(
23585 30 : isolate, OptimizationCallback, data, signature);
23586 : Local<Function> function =
23587 30 : function_template->GetFunction(context).ToLocalChecked();
23588 : Local<Object> global_holder = inner_global;
23589 : Local<Object> function_holder = function_receiver;
23590 30 : if (signature_type == kSignatureOnPrototype) {
23591 10 : function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23592 10 : global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23593 : }
23594 90 : global_holder->Set(context, v8_str("g_f"), function).FromJust();
23595 60 : global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23596 90 : function_holder->Set(context, v8_str("f"), function).FromJust();
23597 60 : function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23598 : // Initialize expected values.
23599 30 : callee = function;
23600 30 : count = 0;
23601 30 : if (global) {
23602 15 : receiver = context->Global();
23603 15 : holder = inner_global;
23604 : } else {
23605 15 : holder = function_receiver;
23606 : // If not using a signature, add something else to the prototype chain
23607 : // to test the case that holder != receiver
23608 15 : if (signature_type == kNoSignature) {
23609 : receiver = Local<Object>::Cast(CompileRun(
23610 : "var receiver_subclass = {};\n"
23611 : "receiver_subclass.__proto__ = function_receiver;\n"
23612 5 : "receiver_subclass"));
23613 : } else {
23614 : receiver = Local<Object>::Cast(CompileRun(
23615 : "var receiver_subclass = function_receiver;\n"
23616 10 : "receiver_subclass"));
23617 : }
23618 : }
23619 : // With no signature, the holder is not set.
23620 30 : if (signature_type == kNoSignature) holder = receiver;
23621 : // build wrap_function
23622 : i::ScopedVector<char> wrap_function(200);
23623 30 : if (global) {
23624 : i::SNPrintF(
23625 : wrap_function,
23626 : "function wrap_f_%d() { var f = g_f; return f(); }\n"
23627 : "function wrap_get_%d() { return this.g_acc; }\n"
23628 : "function wrap_set_%d() { return this.g_acc = 1; }\n",
23629 15 : key, key, key);
23630 : } else {
23631 : i::SNPrintF(
23632 : wrap_function,
23633 : "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23634 : "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23635 : "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23636 15 : key, key, key);
23637 : }
23638 : // build source string
23639 : i::ScopedVector<char> source(1000);
23640 : i::SNPrintF(
23641 : source,
23642 : "%s\n" // wrap functions
23643 : "function wrap_f() { return wrap_f_%d(); }\n"
23644 : "function wrap_get() { return wrap_get_%d(); }\n"
23645 : "function wrap_set() { return wrap_set_%d(); }\n"
23646 : "check = function(returned) {\n"
23647 : " if (returned !== 'returned') { throw returned; }\n"
23648 : "}\n"
23649 : "\n"
23650 : "check(wrap_f());\n"
23651 : "check(wrap_f());\n"
23652 : "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23653 : "check(wrap_f());\n"
23654 : "\n"
23655 : "check(wrap_get());\n"
23656 : "check(wrap_get());\n"
23657 : "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23658 : "check(wrap_get());\n"
23659 : "\n"
23660 : "check = function(returned) {\n"
23661 : " if (returned !== 1) { throw returned; }\n"
23662 : "}\n"
23663 : "check(wrap_set());\n"
23664 : "check(wrap_set());\n"
23665 : "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23666 : "check(wrap_set());\n",
23667 30 : wrap_function.start(), key, key, key, key, key, key);
23668 60 : v8::TryCatch try_catch(isolate);
23669 : CompileRun(source.start());
23670 30 : CHECK(!try_catch.HasCaught());
23671 30 : CHECK_EQ(9, count);
23672 30 : }
23673 : };
23674 :
23675 :
23676 : Local<Object> ApiCallOptimizationChecker::data;
23677 : Local<Object> ApiCallOptimizationChecker::receiver;
23678 : Local<Object> ApiCallOptimizationChecker::holder;
23679 : Local<Object> ApiCallOptimizationChecker::callee;
23680 : int ApiCallOptimizationChecker::count = 0;
23681 :
23682 :
23683 26644 : TEST(FunctionCallOptimization) {
23684 5 : i::FLAG_allow_natives_syntax = true;
23685 : ApiCallOptimizationChecker checker;
23686 5 : checker.RunAll();
23687 5 : }
23688 :
23689 :
23690 26644 : TEST(FunctionCallOptimizationMultipleArgs) {
23691 5 : i::FLAG_allow_natives_syntax = true;
23692 5 : LocalContext context;
23693 5 : v8::Isolate* isolate = context->GetIsolate();
23694 10 : v8::HandleScope scope(isolate);
23695 5 : Local<Object> global = context->Global();
23696 : Local<v8::Function> function =
23697 10 : Function::New(context.local(), Returns42).ToLocalChecked();
23698 15 : global->Set(context.local(), v8_str("x"), function).FromJust();
23699 : CompileRun(
23700 : "function x_wrap() {\n"
23701 : " for (var i = 0; i < 5; i++) {\n"
23702 : " x(1,2,3);\n"
23703 : " }\n"
23704 : "}\n"
23705 : "x_wrap();\n"
23706 : "%OptimizeFunctionOnNextCall(x_wrap);"
23707 : "x_wrap();\n");
23708 5 : }
23709 :
23710 :
23711 50 : static void ReturnsSymbolCallback(
23712 : const v8::FunctionCallbackInfo<v8::Value>& info) {
23713 100 : info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
23714 50 : }
23715 :
23716 :
23717 26644 : TEST(ApiCallbackCanReturnSymbols) {
23718 5 : i::FLAG_allow_natives_syntax = true;
23719 5 : LocalContext context;
23720 5 : v8::Isolate* isolate = context->GetIsolate();
23721 10 : v8::HandleScope scope(isolate);
23722 5 : Local<Object> global = context->Global();
23723 : Local<v8::Function> function =
23724 10 : Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
23725 15 : global->Set(context.local(), v8_str("x"), function).FromJust();
23726 : CompileRun(
23727 : "function x_wrap() {\n"
23728 : " for (var i = 0; i < 5; i++) {\n"
23729 : " x();\n"
23730 : " }\n"
23731 : "}\n"
23732 : "x_wrap();\n"
23733 : "%OptimizeFunctionOnNextCall(x_wrap);"
23734 : "x_wrap();\n");
23735 5 : }
23736 :
23737 :
23738 26644 : TEST(EmptyApiCallback) {
23739 5 : LocalContext context;
23740 5 : auto isolate = context->GetIsolate();
23741 10 : v8::HandleScope scope(isolate);
23742 5 : auto global = context->Global();
23743 10 : auto function = FunctionTemplate::New(isolate)
23744 5 : ->GetFunction(context.local())
23745 : .ToLocalChecked();
23746 15 : global->Set(context.local(), v8_str("x"), function).FromJust();
23747 :
23748 : auto result = CompileRun("x()");
23749 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23750 :
23751 : result = CompileRun("x(1,2,3)");
23752 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23753 :
23754 : result = CompileRun("x.call(undefined)");
23755 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23756 :
23757 : result = CompileRun("x.call(null)");
23758 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23759 :
23760 : result = CompileRun("7 + x.call(3) + 11");
23761 5 : CHECK(result->IsInt32());
23762 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23763 :
23764 : result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
23765 5 : CHECK(result->IsInt32());
23766 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23767 :
23768 : result = CompileRun("var y = []; x.call(y)");
23769 5 : CHECK(result->IsArray());
23770 :
23771 : result = CompileRun("x.call(y, 1, 2, 3, 4)");
23772 5 : CHECK(result->IsArray());
23773 5 : }
23774 :
23775 :
23776 26644 : TEST(SimpleSignatureCheck) {
23777 5 : LocalContext context;
23778 5 : auto isolate = context->GetIsolate();
23779 10 : v8::HandleScope scope(isolate);
23780 5 : auto global = context->Global();
23781 5 : auto sig_obj = FunctionTemplate::New(isolate);
23782 5 : auto sig = v8::Signature::New(isolate, sig_obj);
23783 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23784 10 : global->Set(context.local(), v8_str("sig_obj"),
23785 15 : sig_obj->GetFunction(context.local()).ToLocalChecked())
23786 : .FromJust();
23787 10 : global->Set(context.local(), v8_str("x"),
23788 15 : x->GetFunction(context.local()).ToLocalChecked())
23789 : .FromJust();
23790 : CompileRun("var s = new sig_obj();");
23791 : {
23792 10 : TryCatch try_catch(isolate);
23793 : CompileRun("x()");
23794 5 : CHECK(try_catch.HasCaught());
23795 : }
23796 : {
23797 10 : TryCatch try_catch(isolate);
23798 : CompileRun("x.call(1)");
23799 5 : CHECK(try_catch.HasCaught());
23800 : }
23801 : {
23802 10 : TryCatch try_catch(isolate);
23803 : auto result = CompileRun("s.x = x; s.x()");
23804 5 : CHECK(!try_catch.HasCaught());
23805 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23806 : }
23807 : {
23808 10 : TryCatch try_catch(isolate);
23809 : auto result = CompileRun("x.call(s)");
23810 5 : CHECK(!try_catch.HasCaught());
23811 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23812 : }
23813 5 : }
23814 :
23815 :
23816 26644 : TEST(ChainSignatureCheck) {
23817 5 : LocalContext context;
23818 5 : auto isolate = context->GetIsolate();
23819 10 : v8::HandleScope scope(isolate);
23820 5 : auto global = context->Global();
23821 5 : auto sig_obj = FunctionTemplate::New(isolate);
23822 5 : auto sig = v8::Signature::New(isolate, sig_obj);
23823 45 : for (int i = 0; i < 4; ++i) {
23824 20 : auto temp = FunctionTemplate::New(isolate);
23825 20 : temp->Inherit(sig_obj);
23826 : sig_obj = temp;
23827 : }
23828 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23829 10 : global->Set(context.local(), v8_str("sig_obj"),
23830 15 : sig_obj->GetFunction(context.local()).ToLocalChecked())
23831 : .FromJust();
23832 10 : global->Set(context.local(), v8_str("x"),
23833 15 : x->GetFunction(context.local()).ToLocalChecked())
23834 : .FromJust();
23835 : CompileRun("var s = new sig_obj();");
23836 : {
23837 10 : TryCatch try_catch(isolate);
23838 : CompileRun("x()");
23839 5 : CHECK(try_catch.HasCaught());
23840 : }
23841 : {
23842 10 : TryCatch try_catch(isolate);
23843 : CompileRun("x.call(1)");
23844 5 : CHECK(try_catch.HasCaught());
23845 : }
23846 : {
23847 10 : TryCatch try_catch(isolate);
23848 : auto result = CompileRun("s.x = x; s.x()");
23849 5 : CHECK(!try_catch.HasCaught());
23850 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23851 : }
23852 : {
23853 10 : TryCatch try_catch(isolate);
23854 : auto result = CompileRun("x.call(s)");
23855 5 : CHECK(!try_catch.HasCaught());
23856 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23857 : }
23858 5 : }
23859 :
23860 :
23861 : static const char* last_event_message;
23862 : static int last_event_status;
23863 10 : void StoringEventLoggerCallback(const char* message, int status) {
23864 10 : last_event_message = message;
23865 10 : last_event_status = status;
23866 10 : }
23867 :
23868 :
23869 26644 : TEST(EventLogging) {
23870 5 : v8::Isolate* isolate = CcTest::isolate();
23871 5 : isolate->SetEventLogger(StoringEventLoggerCallback);
23872 : v8::internal::HistogramTimer histogramTimer(
23873 : "V8.Test", 0, 10000, v8::internal::HistogramTimerResolution::MILLISECOND,
23874 : 50, reinterpret_cast<v8::internal::Isolate*>(isolate)->counters());
23875 : histogramTimer.Start();
23876 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23877 5 : CHECK_EQ(0, last_event_status);
23878 : histogramTimer.Stop();
23879 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23880 5 : CHECK_EQ(1, last_event_status);
23881 5 : }
23882 :
23883 26644 : TEST(PropertyDescriptor) {
23884 5 : LocalContext context;
23885 5 : v8::Isolate* isolate = context->GetIsolate();
23886 10 : v8::HandleScope scope(isolate);
23887 :
23888 : { // empty descriptor
23889 10 : v8::PropertyDescriptor desc;
23890 5 : CHECK(!desc.has_value());
23891 5 : CHECK(!desc.has_set());
23892 5 : CHECK(!desc.has_get());
23893 5 : CHECK(!desc.has_enumerable());
23894 5 : CHECK(!desc.has_configurable());
23895 5 : CHECK(!desc.has_writable());
23896 : }
23897 : {
23898 : // data descriptor
23899 10 : v8::PropertyDescriptor desc(v8_num(42));
23900 5 : desc.set_enumerable(false);
23901 10 : CHECK(desc.value() == v8_num(42));
23902 5 : CHECK(desc.has_value());
23903 5 : CHECK(!desc.has_set());
23904 5 : CHECK(!desc.has_get());
23905 5 : CHECK(desc.has_enumerable());
23906 5 : CHECK(!desc.enumerable());
23907 5 : CHECK(!desc.has_configurable());
23908 5 : CHECK(!desc.has_writable());
23909 : }
23910 : {
23911 : // data descriptor
23912 10 : v8::PropertyDescriptor desc(v8_num(42));
23913 5 : desc.set_configurable(true);
23914 10 : CHECK(desc.value() == v8_num(42));
23915 5 : CHECK(desc.has_value());
23916 5 : CHECK(!desc.has_set());
23917 5 : CHECK(!desc.has_get());
23918 5 : CHECK(desc.has_configurable());
23919 5 : CHECK(desc.configurable());
23920 5 : CHECK(!desc.has_enumerable());
23921 5 : CHECK(!desc.has_writable());
23922 : }
23923 : {
23924 : // data descriptor
23925 10 : v8::PropertyDescriptor desc(v8_num(42));
23926 5 : desc.set_configurable(false);
23927 10 : CHECK(desc.value() == v8_num(42));
23928 5 : CHECK(desc.has_value());
23929 5 : CHECK(!desc.has_set());
23930 5 : CHECK(!desc.has_get());
23931 5 : CHECK(desc.has_configurable());
23932 5 : CHECK(!desc.configurable());
23933 5 : CHECK(!desc.has_enumerable());
23934 5 : CHECK(!desc.has_writable());
23935 : }
23936 : {
23937 : // data descriptor
23938 10 : v8::PropertyDescriptor desc(v8_num(42), false);
23939 10 : CHECK(desc.value() == v8_num(42));
23940 5 : CHECK(desc.has_value());
23941 5 : CHECK(!desc.has_set());
23942 5 : CHECK(!desc.has_get());
23943 5 : CHECK(!desc.has_enumerable());
23944 5 : CHECK(!desc.has_configurable());
23945 5 : CHECK(desc.has_writable());
23946 5 : CHECK(!desc.writable());
23947 : }
23948 : {
23949 : // data descriptor
23950 10 : v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true);
23951 5 : CHECK(!desc.has_value());
23952 5 : CHECK(!desc.has_set());
23953 5 : CHECK(!desc.has_get());
23954 5 : CHECK(!desc.has_enumerable());
23955 5 : CHECK(!desc.has_configurable());
23956 5 : CHECK(desc.has_writable());
23957 5 : CHECK(desc.writable());
23958 : }
23959 : {
23960 : // accessor descriptor
23961 : CompileRun("var set = function() {return 43;};");
23962 :
23963 : v8::Local<v8::Function> set =
23964 10 : v8::Local<v8::Function>::Cast(context->Global()
23965 15 : ->Get(context.local(), v8_str("set"))
23966 : .ToLocalChecked());
23967 10 : v8::PropertyDescriptor desc(v8::Undefined(isolate), set);
23968 5 : desc.set_configurable(false);
23969 5 : CHECK(!desc.has_value());
23970 5 : CHECK(desc.has_get());
23971 10 : CHECK(desc.get() == v8::Undefined(isolate));
23972 5 : CHECK(desc.has_set());
23973 10 : CHECK(desc.set() == set);
23974 5 : CHECK(!desc.has_enumerable());
23975 5 : CHECK(desc.has_configurable());
23976 5 : CHECK(!desc.configurable());
23977 5 : CHECK(!desc.has_writable());
23978 : }
23979 : {
23980 : // accessor descriptor with Proxy
23981 : CompileRun(
23982 : "var set = new Proxy(function() {}, {});"
23983 : "var get = undefined;");
23984 :
23985 : v8::Local<v8::Value> get =
23986 10 : v8::Local<v8::Value>::Cast(context->Global()
23987 15 : ->Get(context.local(), v8_str("get"))
23988 5 : .ToLocalChecked());
23989 : v8::Local<v8::Function> set =
23990 10 : v8::Local<v8::Function>::Cast(context->Global()
23991 15 : ->Get(context.local(), v8_str("set"))
23992 : .ToLocalChecked());
23993 10 : v8::PropertyDescriptor desc(get, set);
23994 5 : desc.set_configurable(false);
23995 5 : CHECK(!desc.has_value());
23996 10 : CHECK(desc.get() == v8::Undefined(isolate));
23997 5 : CHECK(desc.has_get());
23998 10 : CHECK(desc.set() == set);
23999 5 : CHECK(desc.has_set());
24000 5 : CHECK(!desc.has_enumerable());
24001 5 : CHECK(desc.has_configurable());
24002 5 : CHECK(!desc.configurable());
24003 5 : CHECK(!desc.has_writable());
24004 : }
24005 : {
24006 : // accessor descriptor with empty function handle
24007 : v8::Local<v8::Function> get = v8::Local<v8::Function>();
24008 10 : v8::PropertyDescriptor desc(get, get);
24009 5 : CHECK(!desc.has_value());
24010 5 : CHECK(!desc.has_get());
24011 5 : CHECK(!desc.has_set());
24012 5 : CHECK(!desc.has_enumerable());
24013 5 : CHECK(!desc.has_configurable());
24014 5 : CHECK(!desc.has_writable());
24015 : }
24016 5 : }
24017 :
24018 26644 : TEST(Promises) {
24019 5 : LocalContext context;
24020 5 : v8::Isolate* isolate = context->GetIsolate();
24021 10 : v8::HandleScope scope(isolate);
24022 :
24023 : // Creation.
24024 : Local<v8::Promise::Resolver> pr =
24025 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24026 : Local<v8::Promise::Resolver> rr =
24027 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24028 5 : Local<v8::Promise> p = pr->GetPromise();
24029 5 : Local<v8::Promise> r = rr->GetPromise();
24030 :
24031 : // IsPromise predicate.
24032 5 : CHECK(p->IsPromise());
24033 5 : CHECK(r->IsPromise());
24034 5 : Local<Value> o = v8::Object::New(isolate);
24035 5 : CHECK(!o->IsPromise());
24036 :
24037 : // Resolution and rejection.
24038 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24039 5 : CHECK(p->IsPromise());
24040 15 : rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
24041 5 : CHECK(r->IsPromise());
24042 5 : }
24043 :
24044 : // Promise.Then(on_fulfilled)
24045 26644 : TEST(PromiseThen) {
24046 5 : LocalContext context;
24047 5 : v8::Isolate* isolate = context->GetIsolate();
24048 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24049 10 : v8::HandleScope scope(isolate);
24050 5 : Local<Object> global = context->Global();
24051 :
24052 : // Creation.
24053 : Local<v8::Promise::Resolver> pr =
24054 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24055 : Local<v8::Promise::Resolver> qr =
24056 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24057 5 : Local<v8::Promise> p = pr->GetPromise();
24058 5 : Local<v8::Promise> q = qr->GetPromise();
24059 :
24060 5 : CHECK(p->IsPromise());
24061 5 : CHECK(q->IsPromise());
24062 :
24063 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24064 10 : qr->Resolve(context.local(), p).FromJust();
24065 :
24066 : // Chaining non-pending promises.
24067 : CompileRun(
24068 : "var x1 = 0;\n"
24069 : "var x2 = 0;\n"
24070 : "function f1(x) { x1 = x; return x+1 };\n"
24071 : "function f2(x) { x2 = x; return x+1 };\n");
24072 : Local<Function> f1 = Local<Function>::Cast(
24073 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24074 : Local<Function> f2 = Local<Function>::Cast(
24075 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24076 :
24077 : // Then
24078 : CompileRun("x1 = x2 = 0;");
24079 5 : q->Then(context.local(), f1).ToLocalChecked();
24080 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24081 : .ToLocalChecked()
24082 : ->Int32Value(context.local())
24083 : .FromJust());
24084 5 : isolate->RunMicrotasks();
24085 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24086 : .ToLocalChecked()
24087 : ->Int32Value(context.local())
24088 : .FromJust());
24089 :
24090 : // Then
24091 : CompileRun("x1 = x2 = 0;");
24092 5 : pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24093 5 : qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24094 :
24095 10 : qr->Resolve(context.local(), pr).FromJust();
24096 10 : qr->GetPromise()
24097 5 : ->Then(context.local(), f1)
24098 : .ToLocalChecked()
24099 5 : ->Then(context.local(), f2)
24100 : .ToLocalChecked();
24101 :
24102 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24103 : .ToLocalChecked()
24104 : ->Int32Value(context.local())
24105 : .FromJust());
24106 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24107 : .ToLocalChecked()
24108 : ->Int32Value(context.local())
24109 : .FromJust());
24110 5 : isolate->RunMicrotasks();
24111 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24112 : .ToLocalChecked()
24113 : ->Int32Value(context.local())
24114 : .FromJust());
24115 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24116 : .ToLocalChecked()
24117 : ->Int32Value(context.local())
24118 : .FromJust());
24119 :
24120 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
24121 :
24122 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24123 : .ToLocalChecked()
24124 : ->Int32Value(context.local())
24125 : .FromJust());
24126 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24127 : .ToLocalChecked()
24128 : ->Int32Value(context.local())
24129 : .FromJust());
24130 5 : isolate->RunMicrotasks();
24131 20 : CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
24132 : .ToLocalChecked()
24133 : ->Int32Value(context.local())
24134 : .FromJust());
24135 20 : CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
24136 : .ToLocalChecked()
24137 : ->Int32Value(context.local())
24138 : .FromJust());
24139 5 : }
24140 :
24141 : // Promise.Then(on_fulfilled, on_rejected)
24142 26644 : TEST(PromiseThen2) {
24143 5 : LocalContext context;
24144 5 : v8::Isolate* isolate = context->GetIsolate();
24145 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24146 10 : v8::HandleScope scope(isolate);
24147 5 : Local<Object> global = context->Global();
24148 :
24149 : // Creation.
24150 : Local<v8::Promise::Resolver> pr =
24151 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24152 5 : Local<v8::Promise> p = pr->GetPromise();
24153 :
24154 5 : CHECK(p->IsPromise());
24155 :
24156 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24157 :
24158 : // Chaining non-pending promises.
24159 : CompileRun(
24160 : "var x1 = 0;\n"
24161 : "var x2 = 0;\n"
24162 : "function f1(x) { x1 = x; return x+1 };\n"
24163 : "function f2(x) { x2 = x; return x+1 };\n"
24164 : "function f3(x) { throw x + 100 };\n");
24165 : Local<Function> f1 = Local<Function>::Cast(
24166 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24167 : Local<Function> f2 = Local<Function>::Cast(
24168 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24169 : Local<Function> f3 = Local<Function>::Cast(
24170 15 : global->Get(context.local(), v8_str("f3")).ToLocalChecked());
24171 :
24172 : // Then
24173 : CompileRun("x1 = x2 = 0;");
24174 5 : Local<v8::Promise> a = p->Then(context.local(), f1, f2).ToLocalChecked();
24175 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24176 : .ToLocalChecked()
24177 : ->Int32Value(context.local())
24178 : .FromJust());
24179 5 : isolate->RunMicrotasks();
24180 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24181 : .ToLocalChecked()
24182 : ->Int32Value(context.local())
24183 : .FromJust());
24184 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24185 : .ToLocalChecked()
24186 : ->Int32Value(context.local())
24187 : .FromJust());
24188 :
24189 5 : Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
24190 5 : isolate->RunMicrotasks();
24191 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24192 : .ToLocalChecked()
24193 : ->Int32Value(context.local())
24194 : .FromJust());
24195 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24196 : .ToLocalChecked()
24197 : ->Int32Value(context.local())
24198 : .FromJust());
24199 :
24200 5 : Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
24201 5 : isolate->RunMicrotasks();
24202 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24203 : .ToLocalChecked()
24204 : ->Int32Value(context.local())
24205 : .FromJust());
24206 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24207 : .ToLocalChecked()
24208 : ->Int32Value(context.local())
24209 : .FromJust());
24210 :
24211 5 : v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
24212 5 : isolate->RunMicrotasks();
24213 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24214 : .ToLocalChecked()
24215 : ->Int32Value(context.local())
24216 : .FromJust());
24217 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24218 : .ToLocalChecked()
24219 : ->Int32Value(context.local())
24220 : .FromJust());
24221 :
24222 5 : v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
24223 5 : isolate->RunMicrotasks();
24224 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24225 : .ToLocalChecked()
24226 : ->Int32Value(context.local())
24227 : .FromJust());
24228 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24229 : .ToLocalChecked()
24230 : ->Int32Value(context.local())
24231 : .FromJust());
24232 :
24233 5 : v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
24234 5 : isolate->RunMicrotasks();
24235 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24236 : .ToLocalChecked()
24237 : ->Int32Value(context.local())
24238 : .FromJust());
24239 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24240 : .ToLocalChecked()
24241 : ->Int32Value(context.local())
24242 : .FromJust());
24243 :
24244 5 : f->Then(context.local(), f1, f2).ToLocalChecked();
24245 5 : isolate->RunMicrotasks();
24246 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24247 : .ToLocalChecked()
24248 : ->Int32Value(context.local())
24249 : .FromJust());
24250 20 : CHECK_EQ(304, global->Get(context.local(), v8_str("x2"))
24251 : .ToLocalChecked()
24252 : ->Int32Value(context.local())
24253 : .FromJust());
24254 5 : }
24255 :
24256 26644 : TEST(PromiseStateAndValue) {
24257 5 : LocalContext context;
24258 5 : v8::Isolate* isolate = context->GetIsolate();
24259 10 : v8::HandleScope scope(isolate);
24260 : v8::Local<v8::Value> result = CompileRun(
24261 : "var resolver;"
24262 : "new Promise((res, rej) => { resolver = res; })");
24263 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24264 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24265 :
24266 : CompileRun("resolver('fulfilled')");
24267 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24268 10 : CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24269 :
24270 : result = CompileRun("Promise.reject('rejected')");
24271 : promise = v8::Local<v8::Promise>::Cast(result);
24272 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24273 10 : CHECK(v8_str("rejected")->SameValue(promise->Result()));
24274 5 : }
24275 :
24276 26644 : TEST(ResolvedPromiseReFulfill) {
24277 5 : LocalContext context;
24278 5 : v8::Isolate* isolate = context->GetIsolate();
24279 10 : v8::HandleScope scope(isolate);
24280 : v8::Local<v8::String> value1 =
24281 5 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24282 : .ToLocalChecked();
24283 : v8::Local<v8::String> value2 =
24284 5 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24285 : .ToLocalChecked();
24286 :
24287 : v8::Local<v8::Promise::Resolver> resolver =
24288 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24289 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24290 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24291 :
24292 10 : resolver->Resolve(context.local(), value1).ToChecked();
24293 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24294 10 : CHECK_EQ(promise->Result(), value1);
24295 :
24296 : // This should be a no-op.
24297 10 : resolver->Resolve(context.local(), value2).ToChecked();
24298 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24299 10 : CHECK_EQ(promise->Result(), value1);
24300 :
24301 : // This should be a no-op.
24302 10 : resolver->Reject(context.local(), value2).ToChecked();
24303 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24304 10 : CHECK_EQ(promise->Result(), value1);
24305 5 : }
24306 :
24307 26644 : TEST(RejectedPromiseReFulfill) {
24308 5 : LocalContext context;
24309 5 : v8::Isolate* isolate = context->GetIsolate();
24310 10 : v8::HandleScope scope(isolate);
24311 : v8::Local<v8::String> value1 =
24312 5 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24313 : .ToLocalChecked();
24314 : v8::Local<v8::String> value2 =
24315 5 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24316 : .ToLocalChecked();
24317 :
24318 : v8::Local<v8::Promise::Resolver> resolver =
24319 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24320 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24321 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24322 :
24323 10 : resolver->Reject(context.local(), value1).ToChecked();
24324 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24325 10 : CHECK_EQ(promise->Result(), value1);
24326 :
24327 : // This should be a no-op.
24328 10 : resolver->Reject(context.local(), value2).ToChecked();
24329 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24330 10 : CHECK_EQ(promise->Result(), value1);
24331 :
24332 : // This should be a no-op.
24333 10 : resolver->Resolve(context.local(), value2).ToChecked();
24334 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24335 10 : CHECK_EQ(promise->Result(), value1);
24336 5 : }
24337 :
24338 26639 : TEST(DisallowJavascriptExecutionScope) {
24339 0 : LocalContext context;
24340 0 : v8::Isolate* isolate = context->GetIsolate();
24341 0 : v8::HandleScope scope(isolate);
24342 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24343 0 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24344 : CompileRun("2+2");
24345 0 : }
24346 :
24347 26644 : TEST(AllowJavascriptExecutionScope) {
24348 5 : LocalContext context;
24349 5 : v8::Isolate* isolate = context->GetIsolate();
24350 10 : v8::HandleScope scope(isolate);
24351 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24352 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24353 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24354 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24355 10 : { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
24356 : CompileRun("1+1");
24357 : }
24358 5 : }
24359 :
24360 26644 : TEST(ThrowOnJavascriptExecution) {
24361 5 : LocalContext context;
24362 5 : v8::Isolate* isolate = context->GetIsolate();
24363 10 : v8::HandleScope scope(isolate);
24364 10 : v8::TryCatch try_catch(isolate);
24365 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24366 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24367 : CompileRun("1+1");
24368 5 : CHECK(try_catch.HasCaught());
24369 5 : }
24370 :
24371 : namespace {
24372 :
24373 : class MockPlatform : public TestPlatform {
24374 : public:
24375 10 : MockPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {
24376 : // Now that it's completely constructed, make this the current platform.
24377 5 : i::V8::SetPlatformForTesting(this);
24378 5 : }
24379 10 : ~MockPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
24380 :
24381 : bool dump_without_crashing_called() const {
24382 : return dump_without_crashing_called_;
24383 : }
24384 :
24385 5 : void DumpWithoutCrashing() override { dump_without_crashing_called_ = true; }
24386 :
24387 : private:
24388 : v8::Platform* old_platform_;
24389 : bool dump_without_crashing_called_ = false;
24390 : };
24391 :
24392 : } // namespace
24393 :
24394 26644 : TEST(DumpOnJavascriptExecution) {
24395 10 : MockPlatform platform;
24396 :
24397 5 : LocalContext context;
24398 5 : v8::Isolate* isolate = context->GetIsolate();
24399 10 : v8::HandleScope scope(isolate);
24400 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24401 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::DUMP_ON_FAILURE);
24402 5 : CHECK(!platform.dump_without_crashing_called());
24403 : CompileRun("1+1");
24404 5 : CHECK(platform.dump_without_crashing_called());
24405 5 : }
24406 :
24407 26644 : TEST(Regress354123) {
24408 5 : LocalContext current;
24409 5 : v8::Isolate* isolate = current->GetIsolate();
24410 10 : v8::HandleScope scope(isolate);
24411 :
24412 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
24413 5 : templ->SetAccessCheckCallback(AccessCounter);
24414 25 : CHECK(current->Global()
24415 : ->Set(current.local(), v8_str("friend"),
24416 : templ->NewInstance(current.local()).ToLocalChecked())
24417 : .FromJust());
24418 :
24419 : // Test access using __proto__ from the prototype chain.
24420 5 : access_count = 0;
24421 : CompileRun("friend.__proto__ = {};");
24422 5 : CHECK_EQ(2, access_count);
24423 : CompileRun("friend.__proto__;");
24424 5 : CHECK_EQ(4, access_count);
24425 :
24426 : // Test access using __proto__ as a hijacked function (A).
24427 5 : access_count = 0;
24428 : CompileRun("var p = Object.prototype;"
24429 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
24430 : "f.call(friend, {});");
24431 5 : CHECK_EQ(1, access_count);
24432 : CompileRun("var p = Object.prototype;"
24433 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
24434 : "f.call(friend);");
24435 5 : CHECK_EQ(2, access_count);
24436 :
24437 : // Test access using __proto__ as a hijacked function (B).
24438 5 : access_count = 0;
24439 : CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
24440 : "f.call(friend, {});");
24441 5 : CHECK_EQ(1, access_count);
24442 : CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
24443 : "f.call(friend);");
24444 5 : CHECK_EQ(2, access_count);
24445 :
24446 : // Test access using Object.setPrototypeOf reflective method.
24447 5 : access_count = 0;
24448 : CompileRun("Object.setPrototypeOf(friend, {});");
24449 5 : CHECK_EQ(1, access_count);
24450 : CompileRun("Object.getPrototypeOf(friend);");
24451 5 : CHECK_EQ(2, access_count);
24452 5 : }
24453 :
24454 :
24455 26644 : TEST(CaptureStackTraceForStackOverflow) {
24456 5 : v8::internal::FLAG_stack_size = 150;
24457 5 : LocalContext current;
24458 5 : v8::Isolate* isolate = current->GetIsolate();
24459 10 : v8::HandleScope scope(isolate);
24460 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
24461 5 : v8::StackTrace::kDetailed);
24462 10 : v8::TryCatch try_catch(isolate);
24463 : CompileRun("(function f(x) { f(x+1); })(0)");
24464 5 : CHECK(try_catch.HasCaught());
24465 5 : }
24466 :
24467 : namespace {
24468 5 : bool ValueEqualsString(v8::Isolate* isolate, Local<Value> lhs,
24469 : const char* rhs) {
24470 5 : CHECK(!lhs.IsEmpty());
24471 5 : CHECK(lhs->IsString());
24472 10 : String::Utf8Value utf8_lhs(isolate, lhs);
24473 10 : return strcmp(rhs, *utf8_lhs) == 0;
24474 : }
24475 : } // namespace
24476 :
24477 26644 : TEST(ScriptNameAndLineNumber) {
24478 5 : LocalContext env;
24479 5 : v8::Isolate* isolate = env->GetIsolate();
24480 10 : v8::HandleScope scope(isolate);
24481 : const char* url = "http://www.foo.com/foo.js";
24482 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24483 5 : v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
24484 :
24485 : Local<Script> script =
24486 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24487 10 : CHECK(ValueEqualsString(isolate, script->GetUnboundScript()->GetScriptName(),
24488 : url));
24489 :
24490 10 : int line_number = script->GetUnboundScript()->GetLineNumber(0);
24491 5 : CHECK_EQ(13, line_number);
24492 5 : }
24493 :
24494 26644 : TEST(ScriptPositionInfo) {
24495 5 : LocalContext env;
24496 5 : v8::Isolate* isolate = env->GetIsolate();
24497 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
24498 10 : v8::HandleScope scope(isolate);
24499 : const char* url = "http://www.foo.com/foo.js";
24500 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24501 : v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
24502 : "var bar;\n"
24503 : "var fisk = foo + bar;\n"),
24504 5 : origin);
24505 : Local<Script> script =
24506 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24507 :
24508 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
24509 10 : v8::Utils::OpenHandle(*script->GetUnboundScript()));
24510 10 : CHECK(obj->script()->IsScript());
24511 :
24512 10 : i::Handle<i::Script> script1(i::Script::cast(obj->script()), i_isolate);
24513 :
24514 : v8::internal::Script::PositionInfo info;
24515 :
24516 25 : for (int i = 0; i < 2; ++i) {
24517 : // With offset.
24518 :
24519 : // Behave as if 0 was passed if position is negative.
24520 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
24521 10 : CHECK_EQ(13, info.line);
24522 10 : CHECK_EQ(0, info.column);
24523 10 : CHECK_EQ(0, info.line_start);
24524 10 : CHECK_EQ(8, info.line_end);
24525 :
24526 10 : CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
24527 10 : CHECK_EQ(13, info.line);
24528 10 : CHECK_EQ(0, info.column);
24529 10 : CHECK_EQ(0, info.line_start);
24530 10 : CHECK_EQ(8, info.line_end);
24531 :
24532 10 : CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
24533 10 : CHECK_EQ(13, info.line);
24534 10 : CHECK_EQ(8, info.column);
24535 10 : CHECK_EQ(0, info.line_start);
24536 10 : CHECK_EQ(8, info.line_end);
24537 :
24538 10 : CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
24539 10 : CHECK_EQ(14, info.line);
24540 10 : CHECK_EQ(0, info.column);
24541 10 : CHECK_EQ(9, info.line_start);
24542 10 : CHECK_EQ(17, info.line_end);
24543 :
24544 : // Fail when position is larger than script size.
24545 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
24546 :
24547 : // Without offset.
24548 :
24549 : // Behave as if 0 was passed if position is negative.
24550 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
24551 10 : CHECK_EQ(0, info.line);
24552 10 : CHECK_EQ(0, info.column);
24553 10 : CHECK_EQ(0, info.line_start);
24554 10 : CHECK_EQ(8, info.line_end);
24555 :
24556 10 : CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
24557 10 : CHECK_EQ(0, info.line);
24558 10 : CHECK_EQ(0, info.column);
24559 10 : CHECK_EQ(0, info.line_start);
24560 10 : CHECK_EQ(8, info.line_end);
24561 :
24562 10 : CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
24563 10 : CHECK_EQ(0, info.line);
24564 10 : CHECK_EQ(8, info.column);
24565 10 : CHECK_EQ(0, info.line_start);
24566 10 : CHECK_EQ(8, info.line_end);
24567 :
24568 10 : CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
24569 10 : CHECK_EQ(1, info.line);
24570 10 : CHECK_EQ(0, info.column);
24571 10 : CHECK_EQ(9, info.line_start);
24572 10 : CHECK_EQ(17, info.line_end);
24573 :
24574 : // Fail when position is larger than script size.
24575 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
24576 :
24577 10 : i::Script::InitLineEnds(script1);
24578 : }
24579 5 : }
24580 :
24581 155 : void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
24582 : const char* expected_source_url,
24583 : const char* expected_source_mapping_url) {
24584 155 : if (expected_source_url != nullptr) {
24585 : v8::String::Utf8Value url(isolate,
24586 105 : script->GetUnboundScript()->GetSourceURL());
24587 35 : CHECK_EQ(0, strcmp(expected_source_url, *url));
24588 : } else {
24589 360 : CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24590 : }
24591 155 : if (expected_source_mapping_url != nullptr) {
24592 : v8::String::Utf8Value url(
24593 90 : isolate, script->GetUnboundScript()->GetSourceMappingURL());
24594 30 : CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
24595 : } else {
24596 375 : CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24597 : }
24598 155 : }
24599 :
24600 70 : void SourceURLHelper(v8::Isolate* isolate, const char* source,
24601 : const char* expected_source_url,
24602 : const char* expected_source_mapping_url) {
24603 70 : Local<Script> script = v8_compile(source);
24604 : CheckMagicComments(isolate, script, expected_source_url,
24605 70 : expected_source_mapping_url);
24606 70 : }
24607 :
24608 :
24609 26644 : TEST(ScriptSourceURLAndSourceMappingURL) {
24610 5 : LocalContext env;
24611 5 : v8::Isolate* isolate = env->GetIsolate();
24612 10 : v8::HandleScope scope(isolate);
24613 : SourceURLHelper(isolate,
24614 : "function foo() {}\n"
24615 : "//# sourceURL=bar1.js\n",
24616 5 : "bar1.js", nullptr);
24617 : SourceURLHelper(isolate,
24618 : "function foo() {}\n"
24619 : "//# sourceMappingURL=bar2.js\n",
24620 5 : nullptr, "bar2.js");
24621 :
24622 : // Both sourceURL and sourceMappingURL.
24623 : SourceURLHelper(isolate,
24624 : "function foo() {}\n"
24625 : "//# sourceURL=bar3.js\n"
24626 : "//# sourceMappingURL=bar4.js\n",
24627 5 : "bar3.js", "bar4.js");
24628 :
24629 : // Two source URLs; the first one is ignored.
24630 : SourceURLHelper(isolate,
24631 : "function foo() {}\n"
24632 : "//# sourceURL=ignoreme.js\n"
24633 : "//# sourceURL=bar5.js\n",
24634 5 : "bar5.js", nullptr);
24635 : SourceURLHelper(isolate,
24636 : "function foo() {}\n"
24637 : "//# sourceMappingURL=ignoreme.js\n"
24638 : "//# sourceMappingURL=bar6.js\n",
24639 5 : nullptr, "bar6.js");
24640 :
24641 : // SourceURL or sourceMappingURL in the middle of the script.
24642 : SourceURLHelper(isolate,
24643 : "function foo() {}\n"
24644 : "//# sourceURL=bar7.js\n"
24645 : "function baz() {}\n",
24646 5 : "bar7.js", nullptr);
24647 : SourceURLHelper(isolate,
24648 : "function foo() {}\n"
24649 : "//# sourceMappingURL=bar8.js\n"
24650 : "function baz() {}\n",
24651 5 : nullptr, "bar8.js");
24652 :
24653 : // Too much whitespace.
24654 : SourceURLHelper(isolate,
24655 : "function foo() {}\n"
24656 : "//# sourceURL=bar9.js\n"
24657 : "//# sourceMappingURL=bar10.js\n",
24658 5 : nullptr, nullptr);
24659 : SourceURLHelper(isolate,
24660 : "function foo() {}\n"
24661 : "//# sourceURL =bar11.js\n"
24662 : "//# sourceMappingURL =bar12.js\n",
24663 5 : nullptr, nullptr);
24664 :
24665 : // Disallowed characters in value.
24666 : SourceURLHelper(isolate,
24667 : "function foo() {}\n"
24668 : "//# sourceURL=bar13 .js \n"
24669 : "//# sourceMappingURL=bar14 .js \n",
24670 5 : nullptr, nullptr);
24671 : SourceURLHelper(isolate,
24672 : "function foo() {}\n"
24673 : "//# sourceURL=bar15\t.js \n"
24674 : "//# sourceMappingURL=bar16\t.js \n",
24675 5 : nullptr, nullptr);
24676 : SourceURLHelper(isolate,
24677 : "function foo() {}\n"
24678 : "//# sourceURL=bar17'.js \n"
24679 : "//# sourceMappingURL=bar18'.js \n",
24680 5 : nullptr, nullptr);
24681 : SourceURLHelper(isolate,
24682 : "function foo() {}\n"
24683 : "//# sourceURL=bar19\".js \n"
24684 : "//# sourceMappingURL=bar20\".js \n",
24685 5 : nullptr, nullptr);
24686 :
24687 : // Not too much whitespace.
24688 : SourceURLHelper(isolate,
24689 : "function foo() {}\n"
24690 : "//# sourceURL= bar21.js \n"
24691 : "//# sourceMappingURL= bar22.js \n",
24692 5 : "bar21.js", "bar22.js");
24693 5 : }
24694 :
24695 :
24696 26644 : TEST(GetOwnPropertyDescriptor) {
24697 5 : LocalContext env;
24698 5 : v8::Isolate* isolate = env->GetIsolate();
24699 10 : v8::HandleScope scope(isolate);
24700 : CompileRun(
24701 : "var x = { value : 13};"
24702 : "Object.defineProperty(x, 'p0', {value : 12});"
24703 : "Object.defineProperty(x, Symbol.toStringTag, {value: 'foo'});"
24704 : "Object.defineProperty(x, 'p1', {"
24705 : " set : function(value) { this.value = value; },"
24706 : " get : function() { return this.value; },"
24707 : "});");
24708 : Local<Object> x = Local<Object>::Cast(
24709 20 : env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
24710 : Local<Value> desc =
24711 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
24712 : .ToLocalChecked();
24713 5 : CHECK(desc->IsUndefined());
24714 : desc =
24715 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
24716 25 : CHECK(v8_num(12)
24717 : ->Equals(env.local(), Local<Object>::Cast(desc)
24718 : ->Get(env.local(), v8_str("value"))
24719 : .ToLocalChecked())
24720 : .FromJust());
24721 : desc =
24722 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
24723 : Local<Function> set =
24724 : Local<Function>::Cast(Local<Object>::Cast(desc)
24725 15 : ->Get(env.local(), v8_str("set"))
24726 : .ToLocalChecked());
24727 : Local<Function> get =
24728 : Local<Function>::Cast(Local<Object>::Cast(desc)
24729 15 : ->Get(env.local(), v8_str("get"))
24730 : .ToLocalChecked());
24731 20 : CHECK(v8_num(13)
24732 : ->Equals(env.local(),
24733 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24734 : .FromJust());
24735 5 : Local<Value> args[] = {v8_num(14)};
24736 10 : set->Call(env.local(), x, 1, args).ToLocalChecked();
24737 20 : CHECK(v8_num(14)
24738 : ->Equals(env.local(),
24739 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24740 : .FromJust());
24741 : desc =
24742 15 : x->GetOwnPropertyDescriptor(env.local(), Symbol::GetToStringTag(isolate))
24743 : .ToLocalChecked();
24744 25 : CHECK(v8_str("foo")
24745 : ->Equals(env.local(), Local<Object>::Cast(desc)
24746 : ->Get(env.local(), v8_str("value"))
24747 : .ToLocalChecked())
24748 : .FromJust());
24749 5 : }
24750 :
24751 :
24752 26644 : TEST(Regress411877) {
24753 5 : v8::Isolate* isolate = CcTest::isolate();
24754 10 : v8::HandleScope handle_scope(isolate);
24755 : v8::Local<v8::ObjectTemplate> object_template =
24756 5 : v8::ObjectTemplate::New(isolate);
24757 5 : object_template->SetAccessCheckCallback(AccessCounter);
24758 :
24759 5 : v8::Local<Context> context = Context::New(isolate);
24760 : v8::Context::Scope context_scope(context);
24761 :
24762 25 : CHECK(context->Global()
24763 : ->Set(context, v8_str("o"),
24764 : object_template->NewInstance(context).ToLocalChecked())
24765 : .FromJust());
24766 : CompileRun("Object.getOwnPropertyNames(o)");
24767 5 : }
24768 :
24769 :
24770 26644 : TEST(GetHiddenPropertyTableAfterAccessCheck) {
24771 5 : v8::Isolate* isolate = CcTest::isolate();
24772 10 : v8::HandleScope handle_scope(isolate);
24773 : v8::Local<v8::ObjectTemplate> object_template =
24774 5 : v8::ObjectTemplate::New(isolate);
24775 5 : object_template->SetAccessCheckCallback(AccessCounter);
24776 :
24777 5 : v8::Local<Context> context = Context::New(isolate);
24778 : v8::Context::Scope context_scope(context);
24779 :
24780 : v8::Local<v8::Object> obj =
24781 5 : object_template->NewInstance(context).ToLocalChecked();
24782 20 : obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
24783 15 : obj->Delete(context, v8_str("key")).FromJust();
24784 :
24785 10 : obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
24786 15 : v8_str("hidden value 2"))
24787 : .FromJust();
24788 5 : }
24789 :
24790 :
24791 26644 : TEST(Regress411793) {
24792 5 : v8::Isolate* isolate = CcTest::isolate();
24793 10 : v8::HandleScope handle_scope(isolate);
24794 : v8::Local<v8::ObjectTemplate> object_template =
24795 5 : v8::ObjectTemplate::New(isolate);
24796 5 : object_template->SetAccessCheckCallback(AccessCounter);
24797 :
24798 5 : v8::Local<Context> context = Context::New(isolate);
24799 : v8::Context::Scope context_scope(context);
24800 :
24801 25 : CHECK(context->Global()
24802 : ->Set(context, v8_str("o"),
24803 : object_template->NewInstance(context).ToLocalChecked())
24804 : .FromJust());
24805 : CompileRun(
24806 : "Object.defineProperty(o, 'key', "
24807 : " { get: function() {}, set: function() {} });");
24808 5 : }
24809 :
24810 210 : class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24811 : public:
24812 105 : explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24813 :
24814 405 : size_t GetMoreData(const uint8_t** src) override {
24815 : // Unlike in real use cases, this function will never block.
24816 405 : if (chunks_[index_] == nullptr) {
24817 : return 0;
24818 : }
24819 : // Copy the data, since the caller takes ownership of it.
24820 310 : size_t len = strlen(chunks_[index_]);
24821 : // We don't need to zero-terminate since we return the length.
24822 310 : uint8_t* copy = new uint8_t[len];
24823 310 : memcpy(copy, chunks_[index_], len);
24824 310 : *src = copy;
24825 310 : ++index_;
24826 310 : return len;
24827 : }
24828 :
24829 : // Helper for constructing a string from chunks (the compilation needs it
24830 : // too).
24831 105 : static char* FullSourceString(const char** chunks) {
24832 : size_t total_len = 0;
24833 765 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24834 330 : total_len += strlen(chunks[i]);
24835 : }
24836 105 : char* full_string = new char[total_len + 1];
24837 : size_t offset = 0;
24838 765 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24839 330 : size_t len = strlen(chunks[i]);
24840 330 : memcpy(full_string + offset, chunks[i], len);
24841 330 : offset += len;
24842 : }
24843 105 : full_string[total_len] = 0;
24844 105 : return full_string;
24845 : }
24846 :
24847 : private:
24848 : const char** chunks_;
24849 : unsigned index_;
24850 : };
24851 :
24852 :
24853 : // Helper function for running streaming tests.
24854 95 : void RunStreamingTest(const char** chunks,
24855 : v8::ScriptCompiler::StreamedSource::Encoding encoding =
24856 : v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24857 : bool expected_success = true,
24858 : const char* expected_source_url = nullptr,
24859 : const char* expected_source_mapping_url = nullptr) {
24860 95 : LocalContext env;
24861 95 : v8::Isolate* isolate = env->GetIsolate();
24862 190 : v8::HandleScope scope(isolate);
24863 190 : v8::TryCatch try_catch(isolate);
24864 :
24865 : v8::ScriptCompiler::StreamedSource source(
24866 285 : v8::base::make_unique<TestSourceStream>(chunks), encoding);
24867 : v8::ScriptCompiler::ScriptStreamingTask* task =
24868 95 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24869 :
24870 : // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24871 : // task here in the main thread.
24872 95 : task->Run();
24873 95 : delete task;
24874 :
24875 : // Possible errors are only produced while compiling.
24876 95 : CHECK(!try_catch.HasCaught());
24877 :
24878 95 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
24879 95 : char* full_source = TestSourceStream::FullSourceString(chunks);
24880 : v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
24881 190 : env.local(), &source, v8_str(full_source), origin);
24882 95 : if (expected_success) {
24883 85 : CHECK(!script.IsEmpty());
24884 : v8::Local<Value> result(
24885 85 : script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
24886 : // All scripts are supposed to return the fixed value 13 when ran.
24887 170 : CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
24888 : CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
24889 85 : expected_source_mapping_url);
24890 : } else {
24891 10 : CHECK(script.IsEmpty());
24892 10 : CHECK(try_catch.HasCaught());
24893 : }
24894 95 : delete[] full_source;
24895 95 : }
24896 :
24897 26644 : TEST(StreamingSimpleScript) {
24898 : // This script is unrealistically small, since no one chunk is enough to fill
24899 : // the backing buffer of Scanner, let alone overflow it.
24900 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24901 5 : nullptr};
24902 5 : RunStreamingTest(chunks);
24903 5 : }
24904 :
24905 26644 : TEST(StreamingScriptConstantArray) {
24906 : // When run with Ignition, tests that the streaming parser canonicalizes
24907 : // handles so that they are only added to the constant pool array once.
24908 : const char* chunks[] = {
24909 : "var a = {};", "var b = {};", "var c = 'testing';",
24910 5 : "var d = 'testing';", "13;", nullptr};
24911 5 : RunStreamingTest(chunks);
24912 5 : }
24913 :
24914 26644 : TEST(StreamingScriptEvalShadowing) {
24915 : // When run with Ignition, tests that the streaming parser canonicalizes
24916 : // handles so the Variable::is_possibly_eval() is correct.
24917 : const char* chunk1 =
24918 : "(function() {\n"
24919 : " var y = 2;\n"
24920 : " return (function() {\n"
24921 : " eval('var y = 13;');\n"
24922 : " function g() {\n"
24923 : " return y\n"
24924 : " }\n"
24925 : " return g();\n"
24926 : " })()\n"
24927 : "})()\n";
24928 5 : const char* chunks[] = {chunk1, nullptr};
24929 5 : RunStreamingTest(chunks);
24930 5 : }
24931 :
24932 26644 : TEST(StreamingBiggerScript) {
24933 : const char* chunk1 =
24934 : "function foo() {\n"
24935 : " // Make this chunk sufficiently long so that it will overflow the\n"
24936 : " // backing buffer of the Scanner.\n"
24937 : " var i = 0;\n"
24938 : " var result = 0;\n"
24939 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24940 : " result = 0;\n"
24941 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24942 : " result = 0;\n"
24943 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24944 : " result = 0;\n"
24945 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24946 : " return result;\n"
24947 : "}\n";
24948 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
24949 5 : RunStreamingTest(chunks);
24950 5 : }
24951 :
24952 :
24953 26644 : TEST(StreamingScriptWithParseError) {
24954 : // Test that parse errors from streamed scripts are propagated correctly.
24955 : {
24956 : char chunk1[] =
24957 : " // This will result in a parse error.\n"
24958 5 : " var if else then foo";
24959 5 : char chunk2[] = " 13\n";
24960 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24961 :
24962 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24963 5 : false);
24964 : }
24965 : // Test that the next script succeeds normally.
24966 : {
24967 : char chunk1[] =
24968 : " // This will be parsed successfully.\n"
24969 5 : " function foo() { return ";
24970 5 : char chunk2[] = " 13; }\n";
24971 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24972 :
24973 5 : RunStreamingTest(chunks);
24974 : }
24975 5 : }
24976 :
24977 :
24978 26644 : TEST(StreamingUtf8Script) {
24979 : // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
24980 : // don't like it.
24981 : const char* chunk1 =
24982 : "function foo() {\n"
24983 : " // This function will contain an UTF-8 character which is not in\n"
24984 : " // ASCII.\n"
24985 : " var foob\xec\x92\x81r = 13;\n"
24986 : " return foob\xec\x92\x81r;\n"
24987 : "}\n";
24988 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
24989 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24990 5 : }
24991 :
24992 :
24993 26644 : TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24994 : // A sanity check to prove that the approach of splitting UTF-8
24995 : // characters is correct. Here is an UTF-8 character which will take three
24996 : // bytes.
24997 : const char* reference = "\xec\x92\x81";
24998 : CHECK_EQ(3, strlen(reference));
24999 :
25000 : char chunk1[] =
25001 : "function foo() {\n"
25002 : " // This function will contain an UTF-8 character which is not in\n"
25003 : " // ASCII.\n"
25004 5 : " var foob";
25005 : char chunk2[] =
25006 : "XXXr = 13;\n"
25007 : " return foob\xec\x92\x81r;\n"
25008 5 : "}\n";
25009 35 : for (int i = 0; i < 3; ++i) {
25010 15 : chunk2[i] = reference[i];
25011 : }
25012 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25013 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25014 5 : }
25015 :
25016 :
25017 26644 : TEST(StreamingUtf8ScriptWithSplitCharacters) {
25018 : // Stream data where a multi-byte UTF-8 character is split between two data
25019 : // chunks.
25020 : const char* reference = "\xec\x92\x81";
25021 : char chunk1[] =
25022 : "function foo() {\n"
25023 : " // This function will contain an UTF-8 character which is not in\n"
25024 : " // ASCII.\n"
25025 5 : " var foobX";
25026 : char chunk2[] =
25027 : "XXr = 13;\n"
25028 : " return foob\xec\x92\x81r;\n"
25029 5 : "}\n";
25030 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25031 5 : chunk2[0] = reference[1];
25032 5 : chunk2[1] = reference[2];
25033 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25034 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25035 5 : }
25036 :
25037 :
25038 26644 : TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
25039 : // Tests edge cases which should still be decoded correctly.
25040 :
25041 : // Case 1: a chunk contains only bytes for a split character (and no other
25042 : // data). This kind of a chunk would be exceptionally small, but we should
25043 : // still decode it correctly.
25044 : const char* reference = "\xec\x92\x81";
25045 : // The small chunk is at the beginning of the split character
25046 : {
25047 : char chunk1[] =
25048 : "function foo() {\n"
25049 : " // This function will contain an UTF-8 character which is not in\n"
25050 : " // ASCII.\n"
25051 5 : " var foob";
25052 5 : char chunk2[] = "XX";
25053 : char chunk3[] =
25054 : "Xr = 13;\n"
25055 : " return foob\xec\x92\x81r;\n"
25056 5 : "}\n";
25057 5 : chunk2[0] = reference[0];
25058 5 : chunk2[1] = reference[1];
25059 5 : chunk3[0] = reference[2];
25060 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25061 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25062 : }
25063 : // The small chunk is at the end of a character
25064 : {
25065 : char chunk1[] =
25066 : "function foo() {\n"
25067 : " // This function will contain an UTF-8 character which is not in\n"
25068 : " // ASCII.\n"
25069 5 : " var foobX";
25070 5 : char chunk2[] = "XX";
25071 : char chunk3[] =
25072 : "r = 13;\n"
25073 : " return foob\xec\x92\x81r;\n"
25074 5 : "}\n";
25075 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25076 5 : chunk2[0] = reference[1];
25077 5 : chunk2[1] = reference[2];
25078 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25079 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25080 : }
25081 : // Case 2: the script ends with a multi-byte character. Make sure that it's
25082 : // decoded correctly and not just ignored.
25083 : {
25084 : char chunk1[] =
25085 : "var foob\xec\x92\x81 = 13;\n"
25086 5 : "foob\xec\x92\x81";
25087 5 : const char* chunks[] = {chunk1, nullptr};
25088 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25089 : }
25090 5 : }
25091 :
25092 :
25093 26644 : TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
25094 : // Test cases where a UTF-8 character is split over several chunks. Those
25095 : // cases are not supported (the embedder should give the data in big enough
25096 : // chunks), but we shouldn't crash and parse this just fine.
25097 : const char* reference = "\xec\x92\x81";
25098 : char chunk1[] =
25099 : "function foo() {\n"
25100 : " // This function will contain an UTF-8 character which is not in\n"
25101 : " // ASCII.\n"
25102 5 : " var foobX";
25103 5 : char chunk2[] = "X";
25104 : char chunk3[] =
25105 : "Xr = 13;\n"
25106 : " return foob\xec\x92\x81r;\n"
25107 5 : "}\n";
25108 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25109 5 : chunk2[0] = reference[1];
25110 5 : chunk3[0] = reference[2];
25111 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25112 :
25113 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25114 5 : }
25115 :
25116 :
25117 :
25118 26644 : TEST(StreamingWithDebuggingEnabledLate) {
25119 : // The streaming parser can only parse lazily, i.e. inner functions are not
25120 : // fully parsed. However, we may compile inner functions eagerly when
25121 : // debugging. Make sure that we can deal with this when turning on debugging
25122 : // after streaming parser has already finished parsing.
25123 : const char* chunks[] = {"with({x:1}) {",
25124 : " var foo = function foo(y) {",
25125 : " return x + y;",
25126 : " };",
25127 : " foo(2);",
25128 : "}",
25129 5 : nullptr};
25130 :
25131 5 : LocalContext env;
25132 5 : v8::Isolate* isolate = env->GetIsolate();
25133 10 : v8::HandleScope scope(isolate);
25134 10 : v8::TryCatch try_catch(isolate);
25135 :
25136 : v8::ScriptCompiler::StreamedSource source(
25137 : v8::base::make_unique<TestSourceStream>(chunks),
25138 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25139 : v8::ScriptCompiler::ScriptStreamingTask* task =
25140 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25141 :
25142 5 : task->Run();
25143 5 : delete task;
25144 :
25145 5 : CHECK(!try_catch.HasCaught());
25146 :
25147 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25148 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25149 :
25150 : EnableDebugger(isolate);
25151 :
25152 : v8::Local<Script> script =
25153 5 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25154 5 : origin)
25155 : .ToLocalChecked();
25156 :
25157 : Maybe<uint32_t> result =
25158 10 : script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
25159 5 : CHECK_EQ(3U, result.FromMaybe(0));
25160 :
25161 5 : delete[] full_source;
25162 :
25163 : DisableDebugger(isolate);
25164 5 : }
25165 :
25166 :
25167 26644 : TEST(StreamingScriptWithInvalidUtf8) {
25168 : // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
25169 : // chunk don't produce a crash.
25170 : const char* reference = "\xec\x92\x81\x80\x80";
25171 : char chunk1[] =
25172 : "function foo() {\n"
25173 : " // This function will contain an UTF-8 character which is not in\n"
25174 : " // ASCII.\n"
25175 5 : " var foobXXXXX"; // Too many bytes which look like incomplete chars!
25176 : char chunk2[] =
25177 : "r = 13;\n"
25178 : " return foob\xec\x92\x81\x80\x80r;\n"
25179 5 : "}\n";
25180 30 : for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
25181 :
25182 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25183 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
25184 5 : }
25185 :
25186 :
25187 26644 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
25188 : // Regression test: Stream data where there are several multi-byte UTF-8
25189 : // characters in a sequence and one of them is split between two data chunks.
25190 : const char* reference = "\xec\x92\x81";
25191 : char chunk1[] =
25192 : "function foo() {\n"
25193 : " // This function will contain an UTF-8 character which is not in\n"
25194 : " // ASCII.\n"
25195 5 : " var foob\xec\x92\x81X";
25196 : char chunk2[] =
25197 : "XXr = 13;\n"
25198 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25199 5 : "}\n";
25200 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25201 5 : chunk2[0] = reference[1];
25202 5 : chunk2[1] = reference[2];
25203 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25204 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25205 5 : }
25206 :
25207 :
25208 26644 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
25209 : // Another regression test, similar to the previous one. The difference is
25210 : // that the split character is not the last one in the sequence.
25211 : const char* reference = "\xec\x92\x81";
25212 : char chunk1[] =
25213 : "function foo() {\n"
25214 : " // This function will contain an UTF-8 character which is not in\n"
25215 : " // ASCII.\n"
25216 5 : " var foobX";
25217 : char chunk2[] =
25218 : "XX\xec\x92\x81r = 13;\n"
25219 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25220 5 : "}\n";
25221 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25222 5 : chunk2[0] = reference[1];
25223 5 : chunk2[1] = reference[2];
25224 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25225 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25226 5 : }
25227 :
25228 :
25229 26644 : TEST(StreamingWithHarmonyScopes) {
25230 : // Don't use RunStreamingTest here so that both scripts get to use the same
25231 : // LocalContext and HandleScope.
25232 5 : LocalContext env;
25233 5 : v8::Isolate* isolate = env->GetIsolate();
25234 10 : v8::HandleScope scope(isolate);
25235 :
25236 : // First, run a script with a let variable.
25237 : CompileRun("\"use strict\"; let x = 1;");
25238 :
25239 : // Then stream a script which (erroneously) tries to introduce the same
25240 : // variable again.
25241 5 : const char* chunks[] = {"\"use strict\"; let x = 2;", nullptr};
25242 :
25243 10 : v8::TryCatch try_catch(isolate);
25244 : v8::ScriptCompiler::StreamedSource source(
25245 : v8::base::make_unique<TestSourceStream>(chunks),
25246 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25247 : v8::ScriptCompiler::ScriptStreamingTask* task =
25248 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25249 5 : task->Run();
25250 5 : delete task;
25251 :
25252 : // Parsing should succeed (the script will be parsed and compiled in a context
25253 : // independent way, so the error is not detected).
25254 5 : CHECK(!try_catch.HasCaught());
25255 :
25256 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25257 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25258 : v8::Local<Script> script =
25259 5 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25260 5 : origin)
25261 : .ToLocalChecked();
25262 5 : CHECK(!script.IsEmpty());
25263 5 : CHECK(!try_catch.HasCaught());
25264 :
25265 : // Running the script exposes the error.
25266 10 : CHECK(script->Run(env.local()).IsEmpty());
25267 5 : CHECK(try_catch.HasCaught());
25268 5 : delete[] full_source;
25269 5 : }
25270 :
25271 :
25272 26644 : TEST(CodeCache) {
25273 : v8::Isolate::CreateParams create_params;
25274 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25275 :
25276 : const char* source = "Math.sqrt(4)";
25277 : const char* origin = "code cache test";
25278 : v8::ScriptCompiler::CachedData* cache;
25279 :
25280 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
25281 : {
25282 : v8::Isolate::Scope iscope(isolate1);
25283 10 : v8::HandleScope scope(isolate1);
25284 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
25285 : v8::Context::Scope cscope(context);
25286 5 : v8::Local<v8::String> source_string = v8_str(source);
25287 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25288 : v8::ScriptCompiler::Source source(source_string, script_origin);
25289 : v8::ScriptCompiler::CompileOptions option =
25290 : v8::ScriptCompiler::kNoCompileOptions;
25291 : v8::Local<v8::Script> script =
25292 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25293 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25294 : }
25295 5 : isolate1->Dispose();
25296 :
25297 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
25298 : {
25299 : v8::Isolate::Scope iscope(isolate2);
25300 10 : v8::HandleScope scope(isolate2);
25301 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
25302 : v8::Context::Scope cscope(context);
25303 5 : v8::Local<v8::String> source_string = v8_str(source);
25304 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25305 : v8::ScriptCompiler::Source source(source_string, script_origin, cache);
25306 : v8::ScriptCompiler::CompileOptions option =
25307 : v8::ScriptCompiler::kConsumeCodeCache;
25308 : v8::Local<v8::Script> script;
25309 : {
25310 : i::DisallowCompilation no_compile(
25311 : reinterpret_cast<i::Isolate*>(isolate2));
25312 5 : script = v8::ScriptCompiler::Compile(context, &source, option)
25313 : .ToLocalChecked();
25314 : }
25315 20 : CHECK_EQ(2, script->Run(context)
25316 : .ToLocalChecked()
25317 : ->ToInt32(context)
25318 : .ToLocalChecked()
25319 : ->Int32Value(context)
25320 : .FromJust());
25321 : }
25322 5 : isolate2->Dispose();
25323 5 : }
25324 :
25325 0 : v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
25326 : Local<String> specifier,
25327 : Local<Module> referrer) {
25328 0 : CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
25329 : }
25330 :
25331 : namespace {
25332 :
25333 10 : Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
25334 : Local<Context> context,
25335 : const char* resource_name,
25336 : const char* source) {
25337 10 : Local<String> source_string = v8_str(source);
25338 : v8::ScriptOrigin script_origin(
25339 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25340 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25341 10 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25342 : v8::ScriptCompiler::Source script_compiler_source(source_string,
25343 : script_origin);
25344 : Local<Module> module =
25345 10 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source)
25346 : .ToLocalChecked();
25347 20 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25348 : .ToChecked();
25349 :
25350 20 : return module;
25351 : }
25352 :
25353 5 : Local<Module> CompileAndInstantiateModuleFromCache(
25354 : v8::Isolate* isolate, Local<Context> context, const char* resource_name,
25355 : const char* source, v8::ScriptCompiler::CachedData* cache) {
25356 5 : Local<String> source_string = v8_str(source);
25357 : v8::ScriptOrigin script_origin(
25358 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25359 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25360 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25361 : v8::ScriptCompiler::Source script_compiler_source(source_string,
25362 : script_origin, cache);
25363 :
25364 : Local<Module> module =
25365 5 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source,
25366 : v8::ScriptCompiler::kConsumeCodeCache)
25367 : .ToLocalChecked();
25368 10 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25369 : .ToChecked();
25370 :
25371 10 : return module;
25372 : }
25373 :
25374 : } // namespace
25375 :
25376 26644 : TEST(ModuleCodeCache) {
25377 : v8::Isolate::CreateParams create_params;
25378 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25379 :
25380 : const char* origin = "code cache test";
25381 : const char* source =
25382 : "export default 5; export const a = 10; function f() { return 42; } "
25383 : "(function() { return f(); })();";
25384 :
25385 : v8::ScriptCompiler::CachedData* cache;
25386 : {
25387 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25388 : {
25389 : v8::Isolate::Scope iscope(isolate);
25390 10 : v8::HandleScope scope(isolate);
25391 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25392 : v8::Context::Scope cscope(context);
25393 :
25394 : Local<Module> module =
25395 5 : CompileAndInstantiateModule(isolate, context, origin, source);
25396 :
25397 : // Fetch the shared function info before evaluation.
25398 : Local<v8::UnboundModuleScript> unbound_module_script =
25399 5 : module->GetUnboundModuleScript();
25400 :
25401 : // Evaluate for possible lazy compilation.
25402 : Local<Value> completion_value =
25403 5 : module->Evaluate(context).ToLocalChecked();
25404 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25405 :
25406 : // Now create the cache. Note that it is freed, obscurely, when
25407 : // ScriptCompiler::Source goes out of scope below.
25408 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25409 : }
25410 5 : isolate->Dispose();
25411 : }
25412 :
25413 : // Test that the cache is consumed and execution still works.
25414 : {
25415 : // Disable --always_opt, otherwise we try to optimize during module
25416 : // instantiation, violating the DisallowCompilation scope.
25417 5 : i::FLAG_always_opt = false;
25418 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25419 : {
25420 : v8::Isolate::Scope iscope(isolate);
25421 10 : v8::HandleScope scope(isolate);
25422 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25423 : v8::Context::Scope cscope(context);
25424 :
25425 : Local<Module> module;
25426 : {
25427 : i::DisallowCompilation no_compile(
25428 : reinterpret_cast<i::Isolate*>(isolate));
25429 : module = CompileAndInstantiateModuleFromCache(isolate, context, origin,
25430 5 : source, cache);
25431 : }
25432 :
25433 : Local<Value> completion_value =
25434 5 : module->Evaluate(context).ToLocalChecked();
25435 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25436 : }
25437 5 : isolate->Dispose();
25438 : }
25439 5 : }
25440 :
25441 : // Tests that the code cache does not confuse the same source code compiled as a
25442 : // script and as a module.
25443 26644 : TEST(CodeCacheModuleScriptMismatch) {
25444 : v8::Isolate::CreateParams create_params;
25445 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25446 :
25447 : const char* origin = "code cache test";
25448 : const char* source = "42";
25449 :
25450 : v8::ScriptCompiler::CachedData* cache;
25451 : {
25452 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25453 : {
25454 : v8::Isolate::Scope iscope(isolate);
25455 10 : v8::HandleScope scope(isolate);
25456 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25457 : v8::Context::Scope cscope(context);
25458 :
25459 : Local<Module> module =
25460 5 : CompileAndInstantiateModule(isolate, context, origin, source);
25461 :
25462 : // Fetch the shared function info before evaluation.
25463 : Local<v8::UnboundModuleScript> unbound_module_script =
25464 5 : module->GetUnboundModuleScript();
25465 :
25466 : // Evaluate for possible lazy compilation.
25467 : Local<Value> completion_value =
25468 5 : module->Evaluate(context).ToLocalChecked();
25469 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25470 :
25471 : // Now create the cache. Note that it is freed, obscurely, when
25472 : // ScriptCompiler::Source goes out of scope below.
25473 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25474 : }
25475 5 : isolate->Dispose();
25476 : }
25477 :
25478 : // Test that the cache is not consumed when source is compiled as a script.
25479 : {
25480 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25481 : {
25482 : v8::Isolate::Scope iscope(isolate);
25483 10 : v8::HandleScope scope(isolate);
25484 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25485 : v8::Context::Scope cscope(context);
25486 :
25487 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25488 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25489 5 : script_origin, cache);
25490 :
25491 : v8::Local<v8::Script> script =
25492 5 : v8::ScriptCompiler::Compile(context, &script_compiler_source,
25493 : v8::ScriptCompiler::kConsumeCodeCache)
25494 : .ToLocalChecked();
25495 :
25496 5 : CHECK(cache->rejected);
25497 :
25498 20 : CHECK_EQ(42, script->Run(context)
25499 : .ToLocalChecked()
25500 : ->ToInt32(context)
25501 : .ToLocalChecked()
25502 : ->Int32Value(context)
25503 : .FromJust());
25504 : }
25505 5 : isolate->Dispose();
25506 : }
25507 5 : }
25508 :
25509 : // Same as above but other way around.
25510 26644 : TEST(CodeCacheScriptModuleMismatch) {
25511 : v8::Isolate::CreateParams create_params;
25512 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25513 :
25514 : const char* origin = "code cache test";
25515 : const char* source = "42";
25516 :
25517 : v8::ScriptCompiler::CachedData* cache;
25518 : {
25519 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25520 : {
25521 : v8::Isolate::Scope iscope(isolate);
25522 10 : v8::HandleScope scope(isolate);
25523 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25524 : v8::Context::Scope cscope(context);
25525 5 : v8::Local<v8::String> source_string = v8_str(source);
25526 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25527 : v8::ScriptCompiler::Source source(source_string, script_origin);
25528 : v8::ScriptCompiler::CompileOptions option =
25529 : v8::ScriptCompiler::kNoCompileOptions;
25530 : v8::Local<v8::Script> script =
25531 5 : v8::ScriptCompiler::Compile(context, &source, option)
25532 : .ToLocalChecked();
25533 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25534 : }
25535 5 : isolate->Dispose();
25536 : }
25537 :
25538 : // Test that the cache is not consumed when source is compiled as a module.
25539 : {
25540 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
25541 : {
25542 : v8::Isolate::Scope iscope(isolate);
25543 10 : v8::HandleScope scope(isolate);
25544 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
25545 : v8::Context::Scope cscope(context);
25546 :
25547 : v8::ScriptOrigin script_origin(
25548 : v8_str(origin), Local<v8::Integer>(), Local<v8::Integer>(),
25549 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25550 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25551 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25552 5 : script_origin, cache);
25553 :
25554 5 : Local<Module> module = v8::ScriptCompiler::CompileModule(
25555 : isolate, &script_compiler_source,
25556 : v8::ScriptCompiler::kConsumeCodeCache)
25557 : .ToLocalChecked();
25558 10 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25559 : .ToChecked();
25560 :
25561 5 : CHECK(cache->rejected);
25562 :
25563 : Local<Value> completion_value =
25564 5 : module->Evaluate(context).ToLocalChecked();
25565 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25566 : }
25567 5 : isolate->Dispose();
25568 : }
25569 5 : }
25570 :
25571 : // Tests that compilation can handle a garbled cache.
25572 26644 : TEST(InvalidCodeCacheDataInCompileModule) {
25573 5 : v8::V8::Initialize();
25574 5 : v8::Isolate* isolate = CcTest::isolate();
25575 10 : v8::HandleScope scope(isolate);
25576 5 : LocalContext local_context;
25577 :
25578 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
25579 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25580 5 : Local<String> origin = v8_str("origin");
25581 : int length = 16;
25582 : v8::ScriptCompiler::CachedData* cached_data =
25583 5 : new v8::ScriptCompiler::CachedData(data, length);
25584 5 : CHECK(!cached_data->rejected);
25585 :
25586 : v8::ScriptOrigin script_origin(
25587 : origin, Local<v8::Integer>(), Local<v8::Integer>(), Local<v8::Boolean>(),
25588 : Local<v8::Integer>(), Local<v8::Value>(), Local<v8::Boolean>(),
25589 : Local<v8::Boolean>(), True(isolate));
25590 5 : v8::ScriptCompiler::Source source(v8_str("42"), script_origin, cached_data);
25591 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25592 :
25593 : Local<Module> module =
25594 5 : v8::ScriptCompiler::CompileModule(isolate, &source,
25595 : v8::ScriptCompiler::kConsumeCodeCache)
25596 : .ToLocalChecked();
25597 10 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25598 : .ToChecked();
25599 :
25600 5 : CHECK(cached_data->rejected);
25601 15 : CHECK_EQ(42, module->Evaluate(context)
25602 : .ToLocalChecked()
25603 : ->Int32Value(context)
25604 : .FromJust());
25605 5 : }
25606 :
25607 5 : void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
25608 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
25609 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25610 : int length = 16;
25611 : v8::ScriptCompiler::CachedData* cached_data =
25612 5 : new v8::ScriptCompiler::CachedData(data, length);
25613 5 : CHECK(!cached_data->rejected);
25614 5 : v8::ScriptOrigin origin(v8_str("origin"));
25615 5 : v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
25616 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25617 : v8::Local<v8::Script> script =
25618 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25619 5 : CHECK(cached_data->rejected);
25620 15 : CHECK_EQ(
25621 : 42,
25622 : script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
25623 5 : }
25624 :
25625 :
25626 26644 : TEST(InvalidCodeCacheData) {
25627 5 : v8::V8::Initialize();
25628 10 : v8::HandleScope scope(CcTest::isolate());
25629 5 : LocalContext context;
25630 5 : TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
25631 5 : }
25632 :
25633 :
25634 26644 : TEST(StringConcatOverflow) {
25635 5 : v8::V8::Initialize();
25636 5 : v8::Isolate* isolate = CcTest::isolate();
25637 10 : v8::HandleScope scope(isolate);
25638 : RandomLengthOneByteResource* r =
25639 5 : new RandomLengthOneByteResource(i::String::kMaxLength);
25640 : v8::Local<v8::String> str =
25641 5 : v8::String::NewExternalOneByte(isolate, r).ToLocalChecked();
25642 5 : CHECK(!str.IsEmpty());
25643 10 : v8::TryCatch try_catch(isolate);
25644 5 : v8::Local<v8::String> result = v8::String::Concat(isolate, str, str);
25645 5 : v8::String::Concat(CcTest::isolate(), str, str);
25646 5 : CHECK(result.IsEmpty());
25647 5 : CHECK(!try_catch.HasCaught());
25648 5 : }
25649 :
25650 26643 : TEST(TurboAsmDisablesDetach) {
25651 : #ifndef V8_LITE_MODE
25652 4 : i::FLAG_opt = true;
25653 4 : i::FLAG_allow_natives_syntax = true;
25654 4 : v8::V8::Initialize();
25655 8 : v8::HandleScope scope(CcTest::isolate());
25656 4 : LocalContext context;
25657 : const char* load =
25658 : "function Module(stdlib, foreign, heap) {"
25659 : " 'use asm';"
25660 : " var MEM32 = new stdlib.Int32Array(heap);"
25661 : " function load() { return MEM32[0] | 0; }"
25662 : " return { load: load };"
25663 : "}"
25664 : "var buffer = new ArrayBuffer(4096);"
25665 : "var module = Module(this, {}, buffer);"
25666 : "%OptimizeFunctionOnNextCall(module.load);"
25667 : "module.load();"
25668 : "buffer";
25669 :
25670 : v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
25671 4 : CHECK(!result->IsDetachable());
25672 :
25673 : const char* store =
25674 : "function Module(stdlib, foreign, heap) {"
25675 : " 'use asm';"
25676 : " var MEM32 = new stdlib.Int32Array(heap);"
25677 : " function store() { MEM32[0] = 0; }"
25678 : " return { store: store };"
25679 : "}"
25680 : "var buffer = new ArrayBuffer(4096);"
25681 : "var module = Module(this, {}, buffer);"
25682 : "%OptimizeFunctionOnNextCall(module.store);"
25683 : "module.store();"
25684 : "buffer";
25685 :
25686 : result = CompileRun(store).As<v8::ArrayBuffer>();
25687 4 : CHECK(!result->IsDetachable());
25688 : #endif // V8_LITE_MODE
25689 4 : }
25690 :
25691 26644 : TEST(ClassPrototypeCreationContext) {
25692 5 : v8::Isolate* isolate = CcTest::isolate();
25693 10 : v8::HandleScope handle_scope(isolate);
25694 5 : LocalContext env;
25695 :
25696 : Local<Object> result = Local<Object>::Cast(
25697 : CompileRun("'use strict'; class Example { }; Example.prototype"));
25698 10 : CHECK(env.local() == result->CreationContext());
25699 5 : }
25700 :
25701 :
25702 26644 : TEST(SimpleStreamingScriptWithSourceURL) {
25703 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
25704 5 : "//# sourceURL=bar2.js\n", nullptr};
25705 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25706 5 : "bar2.js");
25707 5 : }
25708 :
25709 :
25710 26644 : TEST(StreamingScriptWithSplitSourceURL) {
25711 : const char* chunks[] = {"function foo() { ret", "urn 13; } f",
25712 5 : "oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
25713 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25714 5 : "bar2.js");
25715 5 : }
25716 :
25717 :
25718 26644 : TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
25719 : const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
25720 5 : " sourceMappingURL=bar2.js\n", "foo();", nullptr};
25721 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25722 5 : nullptr, "bar2.js");
25723 5 : }
25724 :
25725 :
25726 26644 : TEST(NewStringRangeError) {
25727 : // This test uses a lot of memory and fails with flaky OOM when run
25728 : // with --stress-incremental-marking on TSAN.
25729 5 : i::FLAG_stress_incremental_marking = false;
25730 5 : v8::Isolate* isolate = CcTest::isolate();
25731 10 : v8::HandleScope handle_scope(isolate);
25732 : const int length = i::String::kMaxLength + 1;
25733 : const int buffer_size = length * sizeof(uint16_t);
25734 5 : void* buffer = malloc(buffer_size);
25735 5 : if (buffer == nullptr) return;
25736 : memset(buffer, 'A', buffer_size);
25737 : {
25738 10 : v8::TryCatch try_catch(isolate);
25739 : char* data = reinterpret_cast<char*>(buffer);
25740 10 : CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
25741 : length)
25742 : .IsEmpty());
25743 5 : CHECK(!try_catch.HasCaught());
25744 : }
25745 : {
25746 10 : v8::TryCatch try_catch(isolate);
25747 : uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
25748 10 : CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
25749 : length)
25750 : .IsEmpty());
25751 5 : CHECK(!try_catch.HasCaught());
25752 : }
25753 : {
25754 10 : v8::TryCatch try_catch(isolate);
25755 : uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
25756 10 : CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
25757 : length)
25758 : .IsEmpty());
25759 5 : CHECK(!try_catch.HasCaught());
25760 : }
25761 5 : free(buffer);
25762 : }
25763 :
25764 :
25765 26639 : TEST(SealHandleScope) {
25766 0 : v8::Isolate* isolate = CcTest::isolate();
25767 0 : v8::HandleScope handle_scope(isolate);
25768 0 : LocalContext env;
25769 :
25770 0 : v8::SealHandleScope seal(isolate);
25771 :
25772 : // Should fail
25773 0 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25774 :
25775 : USE(obj);
25776 0 : }
25777 :
25778 :
25779 26644 : TEST(SealHandleScopeNested) {
25780 5 : v8::Isolate* isolate = CcTest::isolate();
25781 10 : v8::HandleScope handle_scope(isolate);
25782 5 : LocalContext env;
25783 :
25784 10 : v8::SealHandleScope seal(isolate);
25785 :
25786 : {
25787 10 : v8::HandleScope handle_scope(isolate);
25788 :
25789 : // Should work
25790 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25791 :
25792 : USE(obj);
25793 : }
25794 5 : }
25795 :
25796 :
25797 5 : static void ExtrasBindingTestRuntimeFunction(
25798 : const v8::FunctionCallbackInfo<v8::Value>& args) {
25799 15 : CHECK_EQ(
25800 : 3,
25801 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
25802 5 : args.GetReturnValue().Set(v8_num(7));
25803 5 : }
25804 :
25805 26644 : TEST(ExtrasFunctionSource) {
25806 5 : v8::Isolate* isolate = CcTest::isolate();
25807 10 : v8::HandleScope handle_scope(isolate);
25808 5 : LocalContext env;
25809 :
25810 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25811 :
25812 : // Functions defined in extras do not expose source code.
25813 15 : auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
25814 : .ToLocalChecked()
25815 : .As<v8::Function>();
25816 : auto undefined = v8::Undefined(isolate);
25817 10 : auto result = func->Call(env.local(), undefined, 0, {})
25818 : .ToLocalChecked()
25819 : .As<v8::String>();
25820 10 : CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
25821 :
25822 : // Functions defined in extras do not show up in the stack trace.
25823 15 : auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
25824 : .ToLocalChecked()
25825 : .As<v8::Function>();
25826 20 : CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
25827 : ExpectString(
25828 : "function f(x) { return wrapper(x) }"
25829 : "function g() { return new Error().stack; }"
25830 : "f(g)",
25831 : "Error\n"
25832 : " at g (<anonymous>:1:58)\n"
25833 : " at f (<anonymous>:1:24)\n"
25834 5 : " at <anonymous>:1:78");
25835 5 : }
25836 :
25837 26644 : TEST(ExtrasBindingObject) {
25838 5 : v8::Isolate* isolate = CcTest::isolate();
25839 10 : v8::HandleScope handle_scope(isolate);
25840 5 : LocalContext env;
25841 :
25842 : // standalone.gypi ensures we include the test-extra.js file, which should
25843 : // export the tested functions.
25844 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25845 :
25846 15 : auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
25847 : .ToLocalChecked()
25848 : .As<v8::Function>();
25849 : auto undefined = v8::Undefined(isolate);
25850 10 : auto result = func->Call(env.local(), undefined, 0, {})
25851 : .ToLocalChecked()
25852 : .As<v8::Number>();
25853 10 : CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
25854 :
25855 : v8::Local<v8::FunctionTemplate> runtimeFunction =
25856 5 : v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
25857 10 : binding->Set(env.local(), v8_str("runtime"),
25858 15 : runtimeFunction->GetFunction(env.local()).ToLocalChecked())
25859 : .FromJust();
25860 15 : func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
25861 : .ToLocalChecked()
25862 : .As<v8::Function>();
25863 10 : result = func->Call(env.local(), undefined, 0, {})
25864 : .ToLocalChecked()
25865 : .As<v8::Number>();
25866 10 : CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
25867 5 : }
25868 :
25869 :
25870 26644 : TEST(ExtrasCreatePromise) {
25871 5 : i::FLAG_allow_natives_syntax = true;
25872 5 : LocalContext context;
25873 5 : v8::Isolate* isolate = context->GetIsolate();
25874 10 : v8::HandleScope handle_scope(isolate);
25875 :
25876 5 : LocalContext env;
25877 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25878 :
25879 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromise"))
25880 : .ToLocalChecked()
25881 : .As<v8::Function>();
25882 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25883 :
25884 : auto promise = CompileRun(
25885 : "func();\n"
25886 : "func();\n"
25887 : "%OptimizeFunctionOnNextCall(func);\n"
25888 : "func()\n")
25889 : .As<v8::Promise>();
25890 5 : CHECK_EQ(v8::Promise::kPending, promise->State());
25891 5 : }
25892 :
25893 26644 : TEST(ExtrasCreatePromiseWithParent) {
25894 5 : i::FLAG_allow_natives_syntax = true;
25895 5 : LocalContext context;
25896 5 : v8::Isolate* isolate = context->GetIsolate();
25897 10 : v8::HandleScope handle_scope(isolate);
25898 :
25899 5 : LocalContext env;
25900 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25901 :
25902 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromiseWithParent"))
25903 : .ToLocalChecked()
25904 : .As<v8::Function>();
25905 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25906 :
25907 : auto promise = CompileRun(
25908 : "var parent = new Promise((a, b) => {});\n"
25909 : "func(parent);\n"
25910 : "func(parent);\n"
25911 : "%OptimizeFunctionOnNextCall(func);\n"
25912 : "func(parent)\n")
25913 : .As<v8::Promise>();
25914 5 : CHECK_EQ(v8::Promise::kPending, promise->State());
25915 5 : }
25916 :
25917 26644 : TEST(ExtrasRejectPromise) {
25918 5 : i::FLAG_allow_natives_syntax = true;
25919 5 : LocalContext context;
25920 5 : v8::Isolate* isolate = context->GetIsolate();
25921 10 : v8::HandleScope handle_scope(isolate);
25922 :
25923 5 : LocalContext env;
25924 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25925 :
25926 15 : auto func = binding->Get(env.local(), v8_str("testRejectPromise"))
25927 : .ToLocalChecked()
25928 : .As<v8::Function>();
25929 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25930 :
25931 : auto rejected_promise = CompileRun(
25932 : "function newPromise() {\n"
25933 : " return new Promise((a, b) => {});\n"
25934 : "}\n"
25935 : "func(newPromise(), 1);\n"
25936 : "func(newPromise(), 1);\n"
25937 : "%OptimizeFunctionOnNextCall(func);\n"
25938 : "var promise = newPromise();\n"
25939 : "func(promise, 1);\n"
25940 : "promise;\n")
25941 : .As<v8::Promise>();
25942 5 : CHECK_EQ(v8::Promise::kRejected, rejected_promise->State());
25943 15 : CHECK_EQ(1, rejected_promise->Result()->Int32Value(env.local()).FromJust());
25944 5 : }
25945 :
25946 26644 : TEST(ExtrasResolvePromise) {
25947 5 : i::FLAG_allow_natives_syntax = true;
25948 5 : LocalContext context;
25949 5 : v8::Isolate* isolate = context->GetIsolate();
25950 10 : v8::HandleScope handle_scope(isolate);
25951 :
25952 5 : LocalContext env;
25953 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25954 :
25955 15 : auto func = binding->Get(env.local(), v8_str("testResolvePromise"))
25956 : .ToLocalChecked()
25957 : .As<v8::Function>();
25958 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25959 :
25960 : auto pending_promise = CompileRun(
25961 : "function newPromise() {\n"
25962 : " return new Promise((a, b) => {});\n"
25963 : "}\n"
25964 : "func(newPromise(), newPromise());\n"
25965 : "func(newPromise(), newPromise());\n"
25966 : "%OptimizeFunctionOnNextCall(func);\n"
25967 : "var promise = newPromise();\n"
25968 : "func(promise, newPromise());\n"
25969 : "promise;\n")
25970 : .As<v8::Promise>();
25971 5 : CHECK_EQ(v8::Promise::kPending, pending_promise->State());
25972 :
25973 : auto fulfilled_promise = CompileRun(
25974 : "function newPromise() {\n"
25975 : " return new Promise((a, b) => {});\n"
25976 : "}\n"
25977 : "func(newPromise(), 1);\n"
25978 : "func(newPromise(), 1);\n"
25979 : "%OptimizeFunctionOnNextCall(func);\n"
25980 : "var promise = newPromise();\n"
25981 : "func(promise, 1);\n"
25982 : "promise;\n")
25983 : .As<v8::Promise>();
25984 5 : CHECK_EQ(v8::Promise::kFulfilled, fulfilled_promise->State());
25985 15 : CHECK_EQ(1, fulfilled_promise->Result()->Int32Value(env.local()).FromJust());
25986 5 : }
25987 :
25988 26644 : TEST(ExtrasUtilsObject) {
25989 5 : LocalContext context;
25990 5 : v8::Isolate* isolate = context->GetIsolate();
25991 10 : v8::HandleScope handle_scope(isolate);
25992 :
25993 5 : LocalContext env;
25994 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25995 :
25996 15 : auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
25997 : .ToLocalChecked()
25998 : .As<v8::Function>();
25999 : auto undefined = v8::Undefined(isolate);
26000 10 : auto result = func->Call(env.local(), undefined, 0, {})
26001 : .ToLocalChecked()
26002 : .As<v8::Object>();
26003 :
26004 15 : auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
26005 : .ToLocalChecked()
26006 : .As<v8::Symbol>();
26007 : i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
26008 5 : CHECK(ips->IsPrivate());
26009 :
26010 : CompileRun("var result = 0; function store(x) { result = x; }");
26011 5 : auto store = CompileRun("store").As<v8::Function>();
26012 :
26013 15 : auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
26014 : .ToLocalChecked()
26015 : .As<v8::Promise>();
26016 5 : fulfilled_promise->Then(env.local(), store).ToLocalChecked();
26017 5 : isolate->RunMicrotasks();
26018 10 : CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
26019 :
26020 : auto fulfilled_promise_2 =
26021 15 : result->Get(env.local(), v8_str("fulfilledPromise2"))
26022 : .ToLocalChecked()
26023 : .As<v8::Promise>();
26024 5 : fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
26025 5 : isolate->RunMicrotasks();
26026 10 : CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
26027 :
26028 15 : auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
26029 : .ToLocalChecked()
26030 : .As<v8::Promise>();
26031 5 : rejected_promise->Catch(env.local(), store).ToLocalChecked();
26032 5 : isolate->RunMicrotasks();
26033 10 : CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
26034 :
26035 : auto rejected_but_handled_promise =
26036 15 : result->Get(env.local(), v8_str("rejectedButHandledPromise"))
26037 : .ToLocalChecked()
26038 : .As<v8::Promise>();
26039 5 : CHECK(rejected_but_handled_promise->HasHandler());
26040 :
26041 15 : auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
26042 : .ToLocalChecked()
26043 : .As<v8::String>();
26044 10 : String::Utf8Value promise_states_string(isolate, promise_states);
26045 5 : CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
26046 :
26047 15 : auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
26048 : .ToLocalChecked()
26049 : .As<v8::Boolean>();
26050 5 : CHECK_EQ(true, promise_is_promise->Value());
26051 :
26052 : auto thenable_is_promise =
26053 15 : result->Get(env.local(), v8_str("thenableIsPromise"))
26054 : .ToLocalChecked()
26055 : .As<v8::Boolean>();
26056 5 : CHECK_EQ(false, thenable_is_promise->Value());
26057 :
26058 15 : auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
26059 : .ToLocalChecked()
26060 : .As<v8::Boolean>();
26061 5 : CHECK_EQ(true, uncurry_this->Value());
26062 5 : }
26063 :
26064 :
26065 26644 : TEST(Map) {
26066 5 : v8::Isolate* isolate = CcTest::isolate();
26067 10 : v8::HandleScope handle_scope(isolate);
26068 5 : LocalContext env;
26069 :
26070 5 : v8::Local<v8::Map> map = v8::Map::New(isolate);
26071 5 : CHECK(map->IsObject());
26072 5 : CHECK(map->IsMap());
26073 10 : CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
26074 5 : CHECK_EQ(0U, map->Size());
26075 :
26076 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
26077 5 : CHECK(val->IsMap());
26078 : map = v8::Local<v8::Map>::Cast(val);
26079 5 : CHECK_EQ(2U, map->Size());
26080 :
26081 5 : v8::Local<v8::Array> contents = map->AsArray();
26082 5 : CHECK_EQ(4U, contents->Length());
26083 10 : CHECK_EQ(
26084 : 1,
26085 : contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26086 10 : CHECK_EQ(
26087 : 2,
26088 : contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26089 10 : CHECK_EQ(
26090 : 3,
26091 : contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
26092 10 : CHECK_EQ(
26093 : 4,
26094 : contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
26095 :
26096 5 : CHECK_EQ(2U, map->Size());
26097 :
26098 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26099 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26100 :
26101 15 : CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26102 10 : CHECK(!map->Has(env.local(), map).FromJust());
26103 :
26104 20 : CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
26105 : .ToLocalChecked()
26106 : ->Int32Value(env.local())
26107 : .FromJust());
26108 20 : CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
26109 : .ToLocalChecked()
26110 : ->Int32Value(env.local())
26111 : .FromJust());
26112 :
26113 15 : CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
26114 : .ToLocalChecked()
26115 : ->IsUndefined());
26116 :
26117 10 : CHECK(!map->Set(env.local(), map, map).IsEmpty());
26118 5 : CHECK_EQ(3U, map->Size());
26119 10 : CHECK(map->Has(env.local(), map).FromJust());
26120 :
26121 10 : CHECK(map->Delete(env.local(), map).FromJust());
26122 5 : CHECK_EQ(2U, map->Size());
26123 10 : CHECK(!map->Has(env.local(), map).FromJust());
26124 10 : CHECK(!map->Delete(env.local(), map).FromJust());
26125 :
26126 5 : map->Clear();
26127 5 : CHECK_EQ(0U, map->Size());
26128 5 : }
26129 :
26130 :
26131 26644 : TEST(Set) {
26132 5 : v8::Isolate* isolate = CcTest::isolate();
26133 10 : v8::HandleScope handle_scope(isolate);
26134 5 : LocalContext env;
26135 :
26136 5 : v8::Local<v8::Set> set = v8::Set::New(isolate);
26137 5 : CHECK(set->IsObject());
26138 5 : CHECK(set->IsSet());
26139 10 : CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
26140 5 : CHECK_EQ(0U, set->Size());
26141 :
26142 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
26143 5 : CHECK(val->IsSet());
26144 : set = v8::Local<v8::Set>::Cast(val);
26145 5 : CHECK_EQ(2U, set->Size());
26146 :
26147 5 : v8::Local<v8::Array> keys = set->AsArray();
26148 5 : CHECK_EQ(2U, keys->Length());
26149 10 : CHECK_EQ(1,
26150 : keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26151 10 : CHECK_EQ(2,
26152 : keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26153 :
26154 5 : CHECK_EQ(2U, set->Size());
26155 :
26156 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26157 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26158 :
26159 15 : CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26160 10 : CHECK(!set->Has(env.local(), set).FromJust());
26161 :
26162 10 : CHECK(!set->Add(env.local(), set).IsEmpty());
26163 5 : CHECK_EQ(3U, set->Size());
26164 10 : CHECK(set->Has(env.local(), set).FromJust());
26165 :
26166 10 : CHECK(set->Delete(env.local(), set).FromJust());
26167 5 : CHECK_EQ(2U, set->Size());
26168 10 : CHECK(!set->Has(env.local(), set).FromJust());
26169 10 : CHECK(!set->Delete(env.local(), set).FromJust());
26170 :
26171 5 : set->Clear();
26172 5 : CHECK_EQ(0U, set->Size());
26173 5 : }
26174 :
26175 26644 : TEST(SetDeleteThenAsArray) {
26176 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26177 5 : v8::Isolate* isolate = CcTest::isolate();
26178 10 : v8::HandleScope handle_scope(isolate);
26179 5 : LocalContext env;
26180 :
26181 : // make a Set
26182 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
26183 : v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
26184 5 : CHECK_EQ(3U, set->Size());
26185 :
26186 : // delete the "middle" element (using AsArray to
26187 : // determine which element is the "middle" element)
26188 5 : v8::Local<v8::Array> array1 = set->AsArray();
26189 5 : CHECK_EQ(3U, array1->Length());
26190 15 : CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
26191 : .FromJust());
26192 :
26193 : // make sure there are no undefined values when we convert to an array again.
26194 5 : v8::Local<v8::Array> array2 = set->AsArray();
26195 5 : uint32_t length = array2->Length();
26196 5 : CHECK_EQ(2U, length);
26197 25 : for (uint32_t i = 0; i < length; i++) {
26198 20 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26199 : }
26200 5 : }
26201 :
26202 26644 : TEST(MapDeleteThenAsArray) {
26203 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26204 5 : v8::Isolate* isolate = CcTest::isolate();
26205 10 : v8::HandleScope handle_scope(isolate);
26206 5 : LocalContext env;
26207 :
26208 : // make a Map
26209 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
26210 : v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
26211 5 : CHECK_EQ(3U, map->Size());
26212 :
26213 : // delete the "middle" element (using AsArray to
26214 : // determine which element is the "middle" element)
26215 5 : v8::Local<v8::Array> array1 = map->AsArray();
26216 5 : CHECK_EQ(6U, array1->Length());
26217 : // Map::AsArray returns a flat array, so the second key is at index 2.
26218 10 : v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
26219 10 : CHECK(map->Delete(env.local(), key).FromJust());
26220 :
26221 : // make sure there are no undefined values when we convert to an array again.
26222 5 : v8::Local<v8::Array> array2 = map->AsArray();
26223 5 : uint32_t length = array2->Length();
26224 5 : CHECK_EQ(4U, length);
26225 45 : for (uint32_t i = 0; i < length; i++) {
26226 40 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26227 : }
26228 5 : }
26229 :
26230 26644 : TEST(CompatibleReceiverCheckOnCachedICHandler) {
26231 5 : v8::Isolate* isolate = CcTest::isolate();
26232 10 : v8::HandleScope scope(isolate);
26233 5 : v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
26234 5 : v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
26235 : auto returns_42 =
26236 5 : v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
26237 15 : parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
26238 5 : v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
26239 5 : child->Inherit(parent);
26240 5 : LocalContext env;
26241 25 : CHECK(env->Global()
26242 : ->Set(env.local(), v8_str("Child"),
26243 : child->GetFunction(env.local()).ToLocalChecked())
26244 : .FromJust());
26245 :
26246 : // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
26247 : CompileRun(
26248 : "var real = new Child();\n"
26249 : "for (var i = 0; i < 3; ++i) {\n"
26250 : " real.age;\n"
26251 : "}\n");
26252 :
26253 : // Check that the cached stub is never used.
26254 : ExpectInt32(
26255 : "var fake = Object.create(Child.prototype);\n"
26256 : "var result = 0;\n"
26257 : "function test(d) {\n"
26258 : " if (d == 3) return;\n"
26259 : " try {\n"
26260 : " fake.age;\n"
26261 : " result = 1;\n"
26262 : " } catch (e) {\n"
26263 : " }\n"
26264 : " test(d+1);\n"
26265 : "}\n"
26266 : "test(0);\n"
26267 : "result;\n",
26268 5 : 0);
26269 5 : }
26270 :
26271 26645 : THREADED_TEST(ReceiverConversionForAccessors) {
26272 6 : LocalContext env;
26273 6 : v8::Isolate* isolate = CcTest::isolate();
26274 12 : v8::HandleScope scope(isolate);
26275 : Local<v8::FunctionTemplate> acc =
26276 6 : v8::FunctionTemplate::New(isolate, Returns42);
26277 30 : CHECK(env->Global()
26278 : ->Set(env.local(), v8_str("acc"),
26279 : acc->GetFunction(env.local()).ToLocalChecked())
26280 : .FromJust());
26281 :
26282 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
26283 12 : templ->SetAccessorProperty(v8_str("acc"), acc, acc);
26284 6 : Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
26285 :
26286 24 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
26287 6 : CHECK(CompileRun("(p.acc == 42)")->BooleanValue(isolate));
26288 6 : CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(isolate));
26289 :
26290 6 : CHECK(!CompileRun("Number.prototype.__proto__ = p;"
26291 : "var a = 1;")
26292 : .IsEmpty());
26293 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26294 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26295 :
26296 6 : CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
26297 : "var a = true;")
26298 : .IsEmpty());
26299 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26300 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26301 :
26302 6 : CHECK(!CompileRun("String.prototype.__proto__ = p;"
26303 : "var a = 'foo';")
26304 : .IsEmpty());
26305 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26306 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26307 :
26308 6 : CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(isolate));
26309 6 : CHECK(CompileRun("acc.call(true)==42")->BooleanValue(isolate));
26310 6 : CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(isolate));
26311 6 : CHECK(CompileRun("acc.call(null) == 42")->BooleanValue(isolate));
26312 6 : CHECK(CompileRun("acc.call(undefined) == 42")->BooleanValue(isolate));
26313 6 : }
26314 :
26315 5 : class FutexInterruptionThread : public v8::base::Thread {
26316 : public:
26317 : explicit FutexInterruptionThread(v8::Isolate* isolate)
26318 5 : : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
26319 :
26320 5 : void Run() override {
26321 : // Wait a bit before terminating.
26322 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
26323 5 : isolate_->TerminateExecution();
26324 5 : }
26325 :
26326 : private:
26327 : v8::Isolate* isolate_;
26328 : };
26329 :
26330 :
26331 26644 : TEST(FutexInterruption) {
26332 5 : i::FLAG_harmony_sharedarraybuffer = true;
26333 5 : v8::Isolate* isolate = CcTest::isolate();
26334 10 : v8::HandleScope scope(isolate);
26335 5 : LocalContext env;
26336 :
26337 : FutexInterruptionThread timeout_thread(isolate);
26338 :
26339 10 : v8::TryCatch try_catch(CcTest::isolate());
26340 5 : timeout_thread.Start();
26341 :
26342 : CompileRun(
26343 : "var ab = new SharedArrayBuffer(4);"
26344 : "var i32a = new Int32Array(ab);"
26345 : "Atomics.wait(i32a, 0, 0);");
26346 5 : CHECK(try_catch.HasTerminated());
26347 5 : timeout_thread.Join();
26348 5 : }
26349 :
26350 26645 : THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
26351 6 : i::FLAG_harmony_sharedarraybuffer = true;
26352 6 : LocalContext env;
26353 6 : v8::Isolate* isolate = env->GetIsolate();
26354 12 : v8::HandleScope handle_scope(isolate);
26355 :
26356 : const size_t ab_size = 1024;
26357 : Local<v8::SharedArrayBuffer> ab =
26358 6 : v8::SharedArrayBuffer::New(isolate, ab_size);
26359 12 : ScopedSharedArrayBufferContents contents(ab->Externalize());
26360 :
26361 : // Array buffers should have normal allocation mode.
26362 6 : CHECK_EQ(contents.AllocationMode(),
26363 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
26364 : // The allocation must contain the buffer (normally they will be equal, but
26365 : // this is not required by the contract).
26366 6 : CHECK_NOT_NULL(contents.AllocationBase());
26367 : const uintptr_t alloc =
26368 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
26369 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
26370 6 : CHECK_LE(alloc, data);
26371 6 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
26372 6 : }
26373 :
26374 : static int nb_uncaught_exception_callback_calls = 0;
26375 :
26376 :
26377 5 : bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
26378 5 : ++nb_uncaught_exception_callback_calls;
26379 5 : return false;
26380 : }
26381 :
26382 :
26383 26644 : TEST(AbortOnUncaughtExceptionNoAbort) {
26384 5 : v8::Isolate* isolate = CcTest::isolate();
26385 10 : v8::HandleScope handle_scope(isolate);
26386 : v8::Local<v8::ObjectTemplate> global_template =
26387 5 : v8::ObjectTemplate::New(isolate);
26388 5 : LocalContext env(nullptr, global_template);
26389 :
26390 5 : i::FLAG_abort_on_uncaught_exception = true;
26391 5 : isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
26392 :
26393 : CompileRun("function boom() { throw new Error(\"boom\") }");
26394 :
26395 5 : v8::Local<v8::Object> global_object = env->Global();
26396 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
26397 15 : global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
26398 :
26399 10 : CHECK(foo->Call(env.local(), global_object, 0, nullptr).IsEmpty());
26400 :
26401 5 : CHECK_EQ(1, nb_uncaught_exception_callback_calls);
26402 5 : }
26403 :
26404 :
26405 26644 : TEST(AccessCheckedIsConcatSpreadable) {
26406 5 : v8::Isolate* isolate = CcTest::isolate();
26407 10 : HandleScope scope(isolate);
26408 5 : LocalContext env;
26409 :
26410 : // Object with access check
26411 5 : Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
26412 5 : spreadable_template->SetAccessCheckCallback(AccessBlocker);
26413 10 : spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
26414 5 : v8::Boolean::New(isolate, true));
26415 : Local<Object> object =
26416 5 : spreadable_template->NewInstance(env.local()).ToLocalChecked();
26417 :
26418 5 : allowed_access = true;
26419 20 : CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
26420 15 : object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
26421 15 : object->Set(env.local(), 0U, v8_str("a")).FromJust();
26422 15 : object->Set(env.local(), 1U, v8_str("b")).FromJust();
26423 :
26424 : // Access check is allowed, and the object is spread
26425 : CompileRun("var result = [].concat(object)");
26426 : ExpectTrue("Array.isArray(result)");
26427 5 : ExpectString("result[0]", "a");
26428 5 : ExpectString("result[1]", "b");
26429 : ExpectTrue("result.length === 2");
26430 : ExpectTrue("object[Symbol.isConcatSpreadable]");
26431 :
26432 : // If access check fails, the value of @@isConcatSpreadable is ignored
26433 5 : allowed_access = false;
26434 : CompileRun("var result = [].concat(object)");
26435 : ExpectTrue("Array.isArray(result)");
26436 : ExpectTrue("result[0] === object");
26437 : ExpectTrue("result.length === 1");
26438 : ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
26439 5 : }
26440 :
26441 :
26442 26644 : TEST(AccessCheckedToStringTag) {
26443 5 : v8::Isolate* isolate = CcTest::isolate();
26444 10 : HandleScope scope(isolate);
26445 5 : LocalContext env;
26446 :
26447 : // Object with access check
26448 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26449 5 : object_template->SetAccessCheckCallback(AccessBlocker);
26450 : Local<Object> object =
26451 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26452 :
26453 5 : allowed_access = true;
26454 20 : env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
26455 20 : object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
26456 : .FromJust();
26457 :
26458 : // Access check is allowed, and the toStringTag is read
26459 : CompileRun("var result = Object.prototype.toString.call(object)");
26460 5 : ExpectString("result", "[object hello]");
26461 5 : ExpectString("object[Symbol.toStringTag]", "hello");
26462 :
26463 : // ToString through the API should succeed too.
26464 : String::Utf8Value result_allowed(
26465 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26466 5 : CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
26467 :
26468 : // If access check fails, the value of @@toStringTag is ignored
26469 5 : allowed_access = false;
26470 : CompileRun("var result = Object.prototype.toString.call(object)");
26471 5 : ExpectString("result", "[object Object]");
26472 : ExpectTrue("object[Symbol.toStringTag] === undefined");
26473 :
26474 : // ToString through the API should also fail.
26475 : String::Utf8Value result_denied(
26476 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26477 5 : CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
26478 5 : }
26479 :
26480 26644 : TEST(TemplateIteratorPrototypeIntrinsics) {
26481 5 : v8::Isolate* isolate = CcTest::isolate();
26482 10 : v8::HandleScope scope(isolate);
26483 5 : LocalContext env;
26484 :
26485 : // Object templates.
26486 : {
26487 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26488 10 : object_template->SetIntrinsicDataProperty(v8_str("iter_proto"),
26489 5 : v8::kIteratorPrototype);
26490 : Local<Object> object =
26491 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26492 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26493 : ExpectTrue("obj.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26494 : }
26495 : // Setting %IteratorProto% on the function object's prototype template.
26496 : {
26497 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26498 15 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26499 5 : v8_str("iter_proto"), v8::kIteratorPrototype);
26500 : Local<Function> func1 =
26501 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26502 20 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26503 : Local<Function> func2 =
26504 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26505 20 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26506 : ExpectTrue(
26507 : "func1.prototype.iter_proto === "
26508 : "[][Symbol.iterator]().__proto__.__proto__");
26509 : ExpectTrue(
26510 : "func2.prototype.iter_proto === "
26511 : "[][Symbol.iterator]().__proto__.__proto__");
26512 : ExpectTrue("func1.prototype.iter_proto === func2.prototype.iter_proto");
26513 :
26514 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26515 20 : CHECK(env->Global()
26516 : ->Set(env.local(), v8_str("instance1"), instance1)
26517 : .FromJust());
26518 : ExpectFalse("instance1.hasOwnProperty('iter_proto')");
26519 : ExpectTrue("'iter_proto' in instance1.__proto__");
26520 : ExpectTrue(
26521 : "instance1.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26522 : }
26523 : // Put %IteratorProto% in a function object's inheritance chain.
26524 : {
26525 : Local<FunctionTemplate> parent_template =
26526 5 : v8::FunctionTemplate::New(isolate);
26527 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26528 10 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26529 5 : v8::kIteratorPrototype);
26530 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26531 5 : func_template->Inherit(parent_template);
26532 :
26533 : Local<Function> func =
26534 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26535 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26536 : ExpectTrue(
26537 : "func.prototype.__proto__ === "
26538 : "[][Symbol.iterator]().__proto__.__proto__");
26539 :
26540 : Local<Object> func_instance =
26541 : func->NewInstance(env.local()).ToLocalChecked();
26542 20 : CHECK(env->Global()
26543 : ->Set(env.local(), v8_str("instance"), func_instance)
26544 : .FromJust());
26545 : ExpectTrue(
26546 : "instance.__proto__.__proto__ === "
26547 : "[][Symbol.iterator]().__proto__.__proto__");
26548 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26549 : }
26550 5 : }
26551 :
26552 26644 : TEST(TemplateErrorPrototypeIntrinsics) {
26553 5 : v8::Isolate* isolate = CcTest::isolate();
26554 10 : v8::HandleScope scope(isolate);
26555 5 : LocalContext env;
26556 :
26557 : // Object templates.
26558 : {
26559 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26560 10 : object_template->SetIntrinsicDataProperty(v8_str("error_proto"),
26561 5 : v8::kErrorPrototype);
26562 : Local<Object> object =
26563 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26564 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26565 : ExpectTrue("obj.error_proto === Error.prototype");
26566 5 : Local<Value> error = v8::Exception::Error(v8_str("error message"));
26567 20 : CHECK(env->Global()->Set(env.local(), v8_str("err"), error).FromJust());
26568 : ExpectTrue("obj.error_proto === Object.getPrototypeOf(err)");
26569 : }
26570 : // Setting %ErrorPrototype% on the function object's prototype template.
26571 : {
26572 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26573 15 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26574 5 : v8_str("error_proto"), v8::kErrorPrototype);
26575 : Local<Function> func1 =
26576 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26577 20 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26578 : Local<Function> func2 =
26579 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26580 20 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26581 : ExpectTrue("func1.prototype.error_proto === Error.prototype");
26582 : ExpectTrue("func2.prototype.error_proto === Error.prototype");
26583 : ExpectTrue("func1.prototype.error_proto === func2.prototype.error_proto");
26584 :
26585 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26586 20 : CHECK(env->Global()
26587 : ->Set(env.local(), v8_str("instance1"), instance1)
26588 : .FromJust());
26589 : ExpectFalse("instance1.hasOwnProperty('error_proto')");
26590 : ExpectTrue("'error_proto' in instance1.__proto__");
26591 : ExpectTrue("instance1.error_proto === Error.prototype");
26592 : }
26593 : // Put %ErrorPrototype% in a function object's inheritance chain.
26594 : {
26595 : Local<FunctionTemplate> parent_template =
26596 5 : v8::FunctionTemplate::New(isolate);
26597 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26598 10 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26599 5 : v8::kErrorPrototype);
26600 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26601 5 : func_template->Inherit(parent_template);
26602 :
26603 : Local<Function> func =
26604 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26605 20 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26606 : ExpectTrue("func.prototype.__proto__ === Error.prototype");
26607 :
26608 : Local<Object> func_instance =
26609 : func->NewInstance(env.local()).ToLocalChecked();
26610 20 : CHECK(env->Global()
26611 : ->Set(env.local(), v8_str("instance"), func_instance)
26612 : .FromJust());
26613 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26614 : // Now let's check if %ErrorPrototype% properties are in the instance.
26615 : ExpectTrue("'constructor' in instance");
26616 : ExpectTrue("'message' in instance");
26617 : ExpectTrue("'name' in instance");
26618 : ExpectTrue("'toString' in instance");
26619 : }
26620 5 : }
26621 :
26622 26644 : TEST(ObjectTemplateArrayProtoIntrinsics) {
26623 5 : v8::Isolate* isolate = CcTest::isolate();
26624 10 : v8::HandleScope scope(isolate);
26625 5 : LocalContext env;
26626 :
26627 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26628 10 : object_template->SetIntrinsicDataProperty(v8_str("prop_entries"),
26629 5 : v8::kArrayProto_entries);
26630 10 : object_template->SetIntrinsicDataProperty(v8_str("prop_forEach"),
26631 5 : v8::kArrayProto_forEach);
26632 10 : object_template->SetIntrinsicDataProperty(v8_str("prop_keys"),
26633 5 : v8::kArrayProto_keys);
26634 10 : object_template->SetIntrinsicDataProperty(v8_str("prop_values"),
26635 5 : v8::kArrayProto_values);
26636 : Local<Object> object =
26637 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26638 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26639 :
26640 : const struct {
26641 : const char* const object_property_name;
26642 : const char* const array_property_name;
26643 : } intrinsics_comparisons[] = {
26644 : {"prop_entries", "Array.prototype.entries"},
26645 : {"prop_forEach", "Array.prototype.forEach"},
26646 : {"prop_keys", "Array.prototype.keys"},
26647 : {"prop_values", "Array.prototype[Symbol.iterator]"},
26648 5 : };
26649 :
26650 45 : for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) {
26651 : i::ScopedVector<char> test_string(64);
26652 :
26653 : i::SNPrintF(test_string, "typeof obj1.%s",
26654 20 : intrinsics_comparisons[i].object_property_name);
26655 20 : ExpectString(test_string.start(), "function");
26656 :
26657 : i::SNPrintF(test_string, "obj1.%s === %s",
26658 : intrinsics_comparisons[i].object_property_name,
26659 20 : intrinsics_comparisons[i].array_property_name);
26660 : ExpectTrue(test_string.start());
26661 :
26662 : i::SNPrintF(test_string, "obj1.%s = 42",
26663 20 : intrinsics_comparisons[i].object_property_name);
26664 : CompileRun(test_string.start());
26665 :
26666 : i::SNPrintF(test_string, "obj1.%s === %s",
26667 : intrinsics_comparisons[i].object_property_name,
26668 20 : intrinsics_comparisons[i].array_property_name);
26669 : ExpectFalse(test_string.start());
26670 :
26671 : i::SNPrintF(test_string, "typeof obj1.%s",
26672 20 : intrinsics_comparisons[i].object_property_name);
26673 20 : ExpectString(test_string.start(), "number");
26674 : }
26675 5 : }
26676 :
26677 26644 : TEST(ObjectTemplatePerContextIntrinsics) {
26678 5 : v8::Isolate* isolate = CcTest::isolate();
26679 10 : v8::HandleScope scope(isolate);
26680 5 : LocalContext env;
26681 :
26682 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26683 10 : object_template->SetIntrinsicDataProperty(v8_str("values"),
26684 5 : v8::kArrayProto_values);
26685 : Local<Object> object =
26686 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26687 :
26688 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26689 5 : ExpectString("typeof obj1.values", "function");
26690 :
26691 : auto values = Local<Function>::Cast(
26692 15 : object->Get(env.local(), v8_str("values")).ToLocalChecked());
26693 : auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
26694 : auto ctx = v8::Utils::OpenHandle(*env.local());
26695 10 : CHECK_EQ(*fn->GetCreationContext(), *ctx);
26696 :
26697 : {
26698 5 : LocalContext env2;
26699 : Local<Object> object2 =
26700 5 : object_template->NewInstance(env2.local()).ToLocalChecked();
26701 20 : CHECK(
26702 : env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
26703 5 : ExpectString("typeof obj2.values", "function");
26704 25 : CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
26705 : *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26706 :
26707 : auto values2 = Local<Function>::Cast(
26708 15 : object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26709 : auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
26710 : auto ctx2 = v8::Utils::OpenHandle(*env2.local());
26711 10 : CHECK_EQ(*fn2->GetCreationContext(), *ctx2);
26712 : }
26713 5 : }
26714 :
26715 :
26716 26644 : TEST(Proxy) {
26717 5 : LocalContext context;
26718 5 : v8::Isolate* isolate = CcTest::isolate();
26719 10 : v8::HandleScope scope(isolate);
26720 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
26721 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
26722 :
26723 : v8::Local<v8::Proxy> proxy =
26724 5 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
26725 5 : CHECK(proxy->IsProxy());
26726 5 : CHECK(!target->IsProxy());
26727 5 : CHECK(!proxy->IsRevoked());
26728 10 : CHECK(proxy->GetTarget()->SameValue(target));
26729 10 : CHECK(proxy->GetHandler()->SameValue(handler));
26730 :
26731 5 : proxy->Revoke();
26732 5 : CHECK(proxy->IsProxy());
26733 5 : CHECK(!target->IsProxy());
26734 5 : CHECK(proxy->IsRevoked());
26735 10 : CHECK(proxy->GetTarget()->IsNull());
26736 10 : CHECK(proxy->GetHandler()->IsNull());
26737 5 : }
26738 :
26739 10 : WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
26740 : v8::Isolate* isolate, WeakCallCounter* counter) {
26741 10 : v8::Locker locker(isolate);
26742 10 : LocalContext env;
26743 20 : HandleScope scope(isolate);
26744 : WeakCallCounterAndPersistent<Value>* val =
26745 10 : new WeakCallCounterAndPersistent<Value>(counter);
26746 20 : val->handle.Reset(isolate, Object::New(isolate));
26747 : val->handle.SetWeak(val, &WeakPointerCallback,
26748 : v8::WeakCallbackType::kParameter);
26749 10 : return val;
26750 : }
26751 :
26752 5 : class MemoryPressureThread : public v8::base::Thread {
26753 : public:
26754 : explicit MemoryPressureThread(v8::Isolate* isolate,
26755 : v8::MemoryPressureLevel level)
26756 : : Thread(Options("MemoryPressureThread")),
26757 : isolate_(isolate),
26758 5 : level_(level) {}
26759 :
26760 5 : void Run() override { isolate_->MemoryPressureNotification(level_); }
26761 :
26762 : private:
26763 : v8::Isolate* isolate_;
26764 : v8::MemoryPressureLevel level_;
26765 : };
26766 :
26767 26644 : TEST(MemoryPressure) {
26768 5 : if (v8::internal::FLAG_optimize_for_size) return;
26769 5 : v8::Isolate* isolate = CcTest::isolate();
26770 : WeakCallCounter counter(1234);
26771 :
26772 : // Check that critical memory pressure notification sets GC interrupt.
26773 5 : auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26774 5 : CHECK(!v8::Locker::IsLocked(isolate));
26775 : {
26776 5 : v8::Locker locker(isolate);
26777 10 : v8::HandleScope scope(isolate);
26778 5 : LocalContext env;
26779 : MemoryPressureThread memory_pressure_thread(
26780 : isolate, v8::MemoryPressureLevel::kCritical);
26781 5 : memory_pressure_thread.Start();
26782 5 : memory_pressure_thread.Join();
26783 : // This should trigger GC.
26784 5 : CHECK_EQ(0, counter.NumberOfWeakCalls());
26785 : CompileRun("(function noop() { return 0; })()");
26786 5 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26787 : }
26788 10 : delete garbage;
26789 : // Check that critical memory pressure notification triggers GC.
26790 5 : garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26791 : {
26792 5 : v8::Locker locker(isolate);
26793 : // If isolate is locked, memory pressure notification should trigger GC.
26794 5 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26795 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
26796 5 : CHECK_EQ(2, counter.NumberOfWeakCalls());
26797 : }
26798 10 : delete garbage;
26799 : // Check that moderate memory pressure notification sets GC into memory
26800 : // optimizing mode.
26801 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
26802 5 : CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26803 : // Check that disabling memory pressure returns GC into normal mode.
26804 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
26805 5 : CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26806 : }
26807 :
26808 26644 : TEST(SetIntegrityLevel) {
26809 5 : LocalContext context;
26810 5 : v8::Isolate* isolate = CcTest::isolate();
26811 10 : v8::HandleScope scope(isolate);
26812 :
26813 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
26814 20 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
26815 :
26816 : v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
26817 5 : CHECK(!is_frozen->BooleanValue(isolate));
26818 :
26819 10 : CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
26820 : .FromJust());
26821 :
26822 : is_frozen = CompileRun("Object.isFrozen(o)");
26823 5 : CHECK(is_frozen->BooleanValue(isolate));
26824 5 : }
26825 :
26826 26644 : TEST(PrivateForApiIsNumber) {
26827 5 : LocalContext context;
26828 5 : v8::Isolate* isolate = CcTest::isolate();
26829 10 : v8::HandleScope scope(isolate);
26830 :
26831 : // Shouldn't crash.
26832 5 : v8::Private::ForApi(isolate, v8_str("42"));
26833 5 : }
26834 :
26835 26645 : THREADED_TEST(ImmutableProto) {
26836 6 : LocalContext context;
26837 6 : v8::Isolate* isolate = context->GetIsolate();
26838 12 : v8::HandleScope handle_scope(isolate);
26839 :
26840 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26841 12 : templ->InstanceTemplate()->SetImmutableProto();
26842 :
26843 6 : Local<v8::Object> object = templ->GetFunction(context.local())
26844 : .ToLocalChecked()
26845 : ->NewInstance(context.local())
26846 : .ToLocalChecked();
26847 :
26848 : // Look up the prototype
26849 : Local<v8::Value> original_proto =
26850 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26851 :
26852 : // Setting the prototype (e.g., to null) throws
26853 12 : CHECK(object->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26854 :
26855 : // The original prototype is still there
26856 : Local<Value> new_proto =
26857 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26858 6 : CHECK(new_proto->IsObject());
26859 12 : CHECK(new_proto.As<v8::Object>()
26860 : ->Equals(context.local(), original_proto)
26861 : .FromJust());
26862 6 : }
26863 :
26864 : Local<v8::Context> call_eval_context;
26865 : Local<v8::Function> call_eval_bound_function;
26866 :
26867 5 : static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
26868 : v8::Context::Scope scope(call_eval_context);
26869 : args.GetReturnValue().Set(
26870 : call_eval_bound_function
26871 15 : ->Call(call_eval_context, call_eval_context->Global(), 0, nullptr)
26872 : .ToLocalChecked());
26873 5 : }
26874 :
26875 26644 : TEST(CrossActivationEval) {
26876 5 : LocalContext env;
26877 5 : v8::Isolate* isolate = env->GetIsolate();
26878 10 : v8::HandleScope scope(isolate);
26879 : {
26880 5 : call_eval_context = v8::Context::New(isolate);
26881 : v8::Context::Scope scope(call_eval_context);
26882 : call_eval_bound_function =
26883 5 : Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
26884 : }
26885 10 : env->Global()
26886 10 : ->Set(env.local(), v8_str("CallEval"),
26887 10 : v8::FunctionTemplate::New(isolate, CallEval)
26888 5 : ->GetFunction(env.local())
26889 10 : .ToLocalChecked())
26890 : .FromJust();
26891 : Local<Value> result = CompileRun("CallEval();");
26892 5 : CHECK(result->IsInt32());
26893 10 : CHECK_EQ(1, result->Int32Value(env.local()).FromJust());
26894 5 : }
26895 :
26896 26644 : TEST(EvalInAccessCheckedContext) {
26897 5 : v8::Isolate* isolate = CcTest::isolate();
26898 10 : v8::HandleScope scope(isolate);
26899 :
26900 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26901 :
26902 5 : obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
26903 :
26904 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
26905 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, obj_template);
26906 :
26907 5 : Local<Value> foo = v8_str("foo");
26908 5 : Local<Value> bar = v8_str("bar");
26909 :
26910 : // Set to different domains.
26911 5 : context0->SetSecurityToken(foo);
26912 5 : context1->SetSecurityToken(bar);
26913 :
26914 : // Set up function in context0 that uses eval from context0.
26915 5 : context0->Enter();
26916 : v8::Local<v8::Value> fun = CompileRun(
26917 : "var x = 42;"
26918 : "(function() {"
26919 : " var e = eval;"
26920 : " return function(s) { return e(s); }"
26921 5 : "})()");
26922 5 : context0->Exit();
26923 :
26924 : // Put the function into context1 and call it. Since the access check
26925 : // callback always returns true, the call succeeds even though the tokens
26926 : // are different.
26927 5 : context1->Enter();
26928 20 : context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
26929 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
26930 10 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
26931 5 : context1->Exit();
26932 5 : }
26933 :
26934 26645 : THREADED_TEST(ImmutableProtoWithParent) {
26935 6 : LocalContext context;
26936 6 : v8::Isolate* isolate = context->GetIsolate();
26937 12 : v8::HandleScope handle_scope(isolate);
26938 :
26939 6 : Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
26940 :
26941 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26942 6 : templ->Inherit(parent);
26943 12 : templ->PrototypeTemplate()->SetImmutableProto();
26944 :
26945 : Local<v8::Function> function =
26946 6 : templ->GetFunction(context.local()).ToLocalChecked();
26947 : Local<v8::Object> instance =
26948 : function->NewInstance(context.local()).ToLocalChecked();
26949 : Local<v8::Object> prototype =
26950 18 : instance->Get(context.local(), v8_str("__proto__"))
26951 : .ToLocalChecked()
26952 6 : ->ToObject(context.local())
26953 : .ToLocalChecked();
26954 :
26955 : // Look up the prototype
26956 : Local<v8::Value> original_proto =
26957 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26958 :
26959 : // Setting the prototype (e.g., to null) throws
26960 12 : CHECK(
26961 : prototype->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26962 :
26963 : // The original prototype is still there
26964 : Local<Value> new_proto =
26965 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26966 6 : CHECK(new_proto->IsObject());
26967 12 : CHECK(new_proto.As<v8::Object>()
26968 : ->Equals(context.local(), original_proto)
26969 : .FromJust());
26970 6 : }
26971 :
26972 26644 : TEST(InternalFieldsOnGlobalProxy) {
26973 5 : v8::Isolate* isolate = CcTest::isolate();
26974 10 : v8::HandleScope scope(isolate);
26975 :
26976 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26977 5 : obj_template->SetInternalFieldCount(1);
26978 :
26979 5 : v8::Local<v8::Context> context = Context::New(isolate, nullptr, obj_template);
26980 5 : v8::Local<v8::Object> global = context->Global();
26981 5 : CHECK_EQ(1, global->InternalFieldCount());
26982 5 : }
26983 :
26984 26645 : THREADED_TEST(ImmutableProtoGlobal) {
26985 6 : v8::Isolate* isolate = CcTest::isolate();
26986 12 : v8::HandleScope handle_scope(isolate);
26987 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26988 6 : global_template->SetImmutableProto();
26989 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
26990 : Context::Scope context_scope(context);
26991 : v8::Local<Value> result = CompileRun(
26992 : "global = this;"
26993 : "(function() {"
26994 : " try {"
26995 : " global.__proto__ = {};"
26996 : " return 0;"
26997 : " } catch (e) {"
26998 : " return 1;"
26999 : " }"
27000 : "})()");
27001 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 1))
27002 : .FromJust());
27003 6 : }
27004 :
27005 26645 : THREADED_TEST(MutableProtoGlobal) {
27006 6 : v8::Isolate* isolate = CcTest::isolate();
27007 12 : v8::HandleScope handle_scope(isolate);
27008 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
27009 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
27010 : Context::Scope context_scope(context);
27011 : v8::Local<Value> result = CompileRun(
27012 : "global = this;"
27013 : "(function() {"
27014 : " try {"
27015 : " global.__proto__ = {};"
27016 : " return 0;"
27017 : " } catch (e) {"
27018 : " return 1;"
27019 : " }"
27020 : "})()");
27021 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 0))
27022 : .FromJust());
27023 6 : }
27024 :
27025 26644 : TEST(InternalFieldsOnTypedArray) {
27026 5 : LocalContext env;
27027 5 : v8::Isolate* isolate = env->GetIsolate();
27028 10 : v8::HandleScope scope(isolate);
27029 : v8::Local<v8::Context> context = env.local();
27030 : Context::Scope context_scope(context);
27031 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27032 5 : v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
27033 25 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27034 10 : CHECK_EQ(static_cast<void*>(nullptr),
27035 : array->GetAlignedPointerFromInternalField(i));
27036 : }
27037 5 : }
27038 :
27039 26644 : TEST(InternalFieldsOnDataView) {
27040 5 : LocalContext env;
27041 5 : v8::Isolate* isolate = env->GetIsolate();
27042 10 : v8::HandleScope scope(isolate);
27043 : v8::Local<v8::Context> context = env.local();
27044 : Context::Scope context_scope(context);
27045 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27046 5 : v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
27047 25 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27048 10 : CHECK_EQ(static_cast<void*>(nullptr),
27049 : array->GetAlignedPointerFromInternalField(i));
27050 : }
27051 5 : }
27052 :
27053 26644 : TEST(SetPrototypeTemplate) {
27054 5 : LocalContext env;
27055 5 : v8::Isolate* isolate = env->GetIsolate();
27056 10 : v8::HandleScope scope(isolate);
27057 :
27058 5 : Local<FunctionTemplate> HTMLElementTemplate = FunctionTemplate::New(isolate);
27059 : Local<FunctionTemplate> HTMLImageElementTemplate =
27060 5 : FunctionTemplate::New(isolate);
27061 5 : HTMLImageElementTemplate->Inherit(HTMLElementTemplate);
27062 :
27063 5 : Local<FunctionTemplate> ImageTemplate = FunctionTemplate::New(isolate);
27064 5 : ImageTemplate->SetPrototypeProviderTemplate(HTMLImageElementTemplate);
27065 :
27066 : Local<Function> HTMLImageElement =
27067 5 : HTMLImageElementTemplate->GetFunction(env.local()).ToLocalChecked();
27068 : Local<Function> Image =
27069 5 : ImageTemplate->GetFunction(env.local()).ToLocalChecked();
27070 :
27071 20 : CHECK(env->Global()
27072 : ->Set(env.local(), v8_str("HTMLImageElement"), HTMLImageElement)
27073 : .FromJust());
27074 20 : CHECK(env->Global()->Set(env.local(), v8_str("Image"), Image).FromJust());
27075 :
27076 : ExpectTrue("Image.prototype === HTMLImageElement.prototype");
27077 5 : }
27078 :
27079 120 : void ensure_receiver_is_global_proxy(
27080 : v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
27081 120 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSGlobalProxy());
27082 120 : }
27083 :
27084 26645 : THREADED_TEST(GlobalAccessorInfo) {
27085 6 : v8::Isolate* isolate = CcTest::isolate();
27086 12 : v8::HandleScope scope(isolate);
27087 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
27088 6 : global_template->SetAccessor(
27089 6 : v8::String::NewFromUtf8(isolate, "prop", v8::NewStringType::kInternalized)
27090 : .ToLocalChecked(),
27091 6 : &ensure_receiver_is_global_proxy);
27092 6 : LocalContext env(nullptr, global_template);
27093 : CompileRun("for (var i = 0; i < 10; i++) this.prop");
27094 : CompileRun("for (var i = 0; i < 10; i++) prop");
27095 6 : }
27096 :
27097 26644 : TEST(DeterministicRandomNumberGeneration) {
27098 10 : v8::HandleScope scope(CcTest::isolate());
27099 :
27100 5 : int previous_seed = v8::internal::FLAG_random_seed;
27101 5 : v8::internal::FLAG_random_seed = 1234;
27102 :
27103 : double first_value;
27104 : double second_value;
27105 : {
27106 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27107 : Context::Scope context_scope(context);
27108 : v8::Local<Value> result = CompileRun("Math.random();");
27109 10 : first_value = result->ToNumber(context).ToLocalChecked()->Value();
27110 : }
27111 : {
27112 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27113 : Context::Scope context_scope(context);
27114 : v8::Local<Value> result = CompileRun("Math.random();");
27115 10 : second_value = result->ToNumber(context).ToLocalChecked()->Value();
27116 : }
27117 5 : CHECK_EQ(first_value, second_value);
27118 :
27119 5 : v8::internal::FLAG_random_seed = previous_seed;
27120 5 : }
27121 :
27122 26644 : UNINITIALIZED_TEST(AllowAtomicsWait) {
27123 : v8::Isolate::CreateParams create_params;
27124 5 : create_params.allow_atomics_wait = false;
27125 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27126 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
27127 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27128 : {
27129 5 : CHECK_EQ(false, i_isolate->allow_atomics_wait());
27130 5 : isolate->SetAllowAtomicsWait(true);
27131 5 : CHECK_EQ(true, i_isolate->allow_atomics_wait());
27132 : }
27133 5 : isolate->Dispose();
27134 5 : }
27135 :
27136 : enum ContextId { EnteredContext, CurrentContext };
27137 :
27138 20 : void CheckContexts(v8::Isolate* isolate) {
27139 60 : CHECK_EQ(CurrentContext, isolate->GetCurrentContext()
27140 : ->GetEmbedderData(1)
27141 : .As<v8::Integer>()
27142 : ->Value());
27143 60 : CHECK_EQ(EnteredContext, isolate->GetEnteredOrMicrotaskContext()
27144 : ->GetEmbedderData(1)
27145 : .As<v8::Integer>()
27146 : ->Value());
27147 20 : }
27148 :
27149 5 : void ContextCheckGetter(Local<String> name,
27150 : const v8::PropertyCallbackInfo<v8::Value>& info) {
27151 5 : CheckContexts(info.GetIsolate());
27152 : info.GetReturnValue().Set(true);
27153 5 : }
27154 :
27155 5 : void ContextCheckSetter(Local<String> name, Local<Value>,
27156 : const v8::PropertyCallbackInfo<void>& info) {
27157 5 : CheckContexts(info.GetIsolate());
27158 5 : }
27159 :
27160 10 : void ContextCheckToString(const v8::FunctionCallbackInfo<v8::Value>& info) {
27161 10 : CheckContexts(info.GetIsolate());
27162 10 : info.GetReturnValue().Set(v8_str("foo"));
27163 10 : }
27164 :
27165 26644 : TEST(CorrectEnteredContext) {
27166 10 : v8::HandleScope scope(CcTest::isolate());
27167 :
27168 5 : LocalContext currentContext;
27169 10 : currentContext->SetEmbedderData(
27170 5 : 1, v8::Integer::New(currentContext->GetIsolate(), CurrentContext));
27171 5 : LocalContext enteredContext;
27172 10 : enteredContext->SetEmbedderData(
27173 5 : 1, v8::Integer::New(enteredContext->GetIsolate(), EnteredContext));
27174 :
27175 : v8::Context::Scope contextScope(enteredContext.local());
27176 :
27177 : v8::Local<v8::ObjectTemplate> object_template =
27178 5 : ObjectTemplate::New(currentContext->GetIsolate());
27179 10 : object_template->SetAccessor(v8_str("p"), &ContextCheckGetter,
27180 5 : &ContextCheckSetter);
27181 :
27182 : v8::Local<v8::Object> object =
27183 5 : object_template->NewInstance(currentContext.local()).ToLocalChecked();
27184 :
27185 15 : object->Get(currentContext.local(), v8_str("p")).ToLocalChecked();
27186 15 : object->Set(currentContext.local(), v8_str("p"), v8_int(0)).FromJust();
27187 :
27188 : v8::Local<v8::Function> to_string =
27189 10 : v8::Function::New(currentContext.local(), ContextCheckToString)
27190 : .ToLocalChecked();
27191 :
27192 10 : to_string->Call(currentContext.local(), object, 0, nullptr).ToLocalChecked();
27193 :
27194 : object
27195 10 : ->CreateDataProperty(currentContext.local(), v8_str("toString"),
27196 10 : to_string)
27197 : .FromJust();
27198 :
27199 5 : object->ToString(currentContext.local()).ToLocalChecked();
27200 5 : }
27201 :
27202 5 : v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
27203 : Local<Context> context, Local<v8::ScriptOrModule> referrer,
27204 : Local<String> specifier) {
27205 5 : CHECK(!referrer.IsEmpty());
27206 : String::Utf8Value referrer_utf8(
27207 15 : context->GetIsolate(), Local<String>::Cast(referrer->GetResourceName()));
27208 5 : CHECK_EQ(0, strcmp("www.google.com", *referrer_utf8));
27209 15 : CHECK(referrer->GetHostDefinedOptions()
27210 : ->Get(context->GetIsolate(), 0)
27211 : ->IsSymbol());
27212 :
27213 5 : CHECK(!specifier.IsEmpty());
27214 10 : String::Utf8Value specifier_utf8(context->GetIsolate(), specifier);
27215 5 : CHECK_EQ(0, strcmp("index.js", *specifier_utf8));
27216 :
27217 : Local<v8::Promise::Resolver> resolver =
27218 5 : v8::Promise::Resolver::New(context).ToLocalChecked();
27219 5 : auto result = v8_str("hello world");
27220 10 : resolver->Resolve(context, result).ToChecked();
27221 10 : return resolver->GetPromise();
27222 : }
27223 :
27224 26644 : TEST(DynamicImport) {
27225 5 : i::FLAG_harmony_dynamic_import = true;
27226 5 : LocalContext context;
27227 5 : v8::Isolate* isolate = context->GetIsolate();
27228 10 : v8::HandleScope scope(isolate);
27229 :
27230 : isolate->SetHostImportModuleDynamicallyCallback(
27231 5 : HostImportModuleDynamicallyCallbackResolve);
27232 :
27233 10 : i::Handle<i::String> url(v8::Utils::OpenHandle(*v8_str("www.google.com")));
27234 10 : i::Handle<i::Object> specifier(v8::Utils::OpenHandle(*v8_str("index.js")));
27235 10 : i::Handle<i::String> result(v8::Utils::OpenHandle(*v8_str("hello world")));
27236 10 : i::Handle<i::String> source(v8::Utils::OpenHandle(*v8_str("foo")));
27237 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27238 5 : i::Handle<i::FixedArray> options = i_isolate->factory()->NewFixedArray(1);
27239 5 : i::Handle<i::Symbol> symbol = i_isolate->factory()->NewSymbol();
27240 10 : options->set(0, *symbol);
27241 5 : i::Handle<i::Script> referrer = i_isolate->factory()->NewScript(source);
27242 10 : referrer->set_name(*url);
27243 5 : referrer->set_host_defined_options(*options);
27244 : i::MaybeHandle<i::JSPromise> maybe_promise =
27245 5 : i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
27246 : i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
27247 5 : isolate->RunMicrotasks();
27248 5 : CHECK(result->Equals(i::String::cast(promise->result())));
27249 5 : }
27250 :
27251 5 : void HostInitializeImportMetaObjectCallbackStatic(Local<Context> context,
27252 : Local<Module> module,
27253 : Local<Object> meta) {
27254 5 : CHECK(!module.IsEmpty());
27255 :
27256 20 : meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
27257 5 : }
27258 :
27259 26644 : TEST(ImportMeta) {
27260 5 : i::FLAG_harmony_dynamic_import = true;
27261 5 : i::FLAG_harmony_import_meta = true;
27262 5 : LocalContext context;
27263 5 : v8::Isolate* isolate = context->GetIsolate();
27264 10 : v8::HandleScope scope(isolate);
27265 :
27266 : isolate->SetHostInitializeImportMetaObjectCallback(
27267 5 : HostInitializeImportMetaObjectCallbackStatic);
27268 :
27269 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27270 5 : Local<String> url = v8_str("www.google.com");
27271 5 : Local<String> source_text = v8_str("import.meta;");
27272 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27273 : Local<v8::Boolean>(), Local<v8::Integer>(),
27274 : Local<v8::Value>(), Local<v8::Boolean>(),
27275 : Local<v8::Boolean>(), True(isolate));
27276 : v8::ScriptCompiler::Source source(source_text, origin);
27277 : Local<Module> module =
27278 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27279 : i::Handle<i::Object> meta =
27280 : i_isolate->RunHostInitializeImportMetaObjectCallback(
27281 5 : v8::Utils::OpenHandle(*module));
27282 5 : CHECK(meta->IsJSObject());
27283 : Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
27284 15 : CHECK(meta_obj->Get(context.local(), v8_str("foo"))
27285 : .ToLocalChecked()
27286 : ->IsString());
27287 15 : CHECK(meta_obj->Get(context.local(), v8_str("zapp"))
27288 : .ToLocalChecked()
27289 : ->IsUndefined());
27290 :
27291 10 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27292 : .ToChecked();
27293 5 : Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
27294 5 : CHECK(result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
27295 5 : }
27296 :
27297 26644 : TEST(GetModuleNamespace) {
27298 5 : LocalContext context;
27299 5 : v8::Isolate* isolate = context->GetIsolate();
27300 10 : v8::HandleScope scope(isolate);
27301 :
27302 5 : Local<String> url = v8_str("www.google.com");
27303 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27304 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27305 : Local<v8::Boolean>(), Local<v8::Integer>(),
27306 : Local<v8::Value>(), Local<v8::Boolean>(),
27307 : Local<v8::Boolean>(), True(isolate));
27308 : v8::ScriptCompiler::Source source(source_text, origin);
27309 : Local<Module> module =
27310 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27311 10 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27312 : .ToChecked();
27313 5 : module->Evaluate(context.local()).ToLocalChecked();
27314 :
27315 5 : Local<Value> ns_val = module->GetModuleNamespace();
27316 5 : CHECK(ns_val->IsModuleNamespaceObject());
27317 : Local<Object> ns = ns_val.As<Object>();
27318 20 : CHECK(ns->Get(context.local(), v8_str("default"))
27319 : .ToLocalChecked()
27320 : ->StrictEquals(v8::Number::New(isolate, 5)));
27321 20 : CHECK(ns->Get(context.local(), v8_str("a"))
27322 : .ToLocalChecked()
27323 : ->StrictEquals(v8::Number::New(isolate, 10)));
27324 5 : }
27325 :
27326 26644 : TEST(ModuleGetUnboundModuleScript) {
27327 5 : LocalContext context;
27328 5 : v8::Isolate* isolate = context->GetIsolate();
27329 10 : v8::HandleScope scope(isolate);
27330 :
27331 5 : Local<String> url = v8_str("www.google.com");
27332 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27333 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27334 : Local<v8::Boolean>(), Local<v8::Integer>(),
27335 : Local<v8::Value>(), Local<v8::Boolean>(),
27336 : Local<v8::Boolean>(), True(isolate));
27337 : v8::ScriptCompiler::Source source(source_text, origin);
27338 : Local<Module> module =
27339 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27340 : Local<v8::UnboundModuleScript> sfi_before_instantiation =
27341 5 : module->GetUnboundModuleScript();
27342 10 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27343 : .ToChecked();
27344 : Local<v8::UnboundModuleScript> sfi_after_instantiation =
27345 5 : module->GetUnboundModuleScript();
27346 :
27347 : // Check object identity.
27348 : {
27349 : i::Handle<i::Object> s1 = v8::Utils::OpenHandle(*sfi_before_instantiation);
27350 : i::Handle<i::Object> s2 = v8::Utils::OpenHandle(*sfi_after_instantiation);
27351 5 : CHECK_EQ(*s1, *s2);
27352 : }
27353 5 : }
27354 :
27355 26644 : TEST(GlobalTemplateWithDoubleProperty) {
27356 5 : v8::Isolate* isolate = CcTest::isolate();
27357 10 : v8::HandleScope handle_scope(isolate);
27358 :
27359 5 : v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
27360 15 : global->Set(v8_str("double"), v8_num(3.14));
27361 :
27362 5 : v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
27363 :
27364 : v8::Context::Scope context_scope(context);
27365 :
27366 : Local<Value> result = CompileRun("double");
27367 5 : CHECK(result->IsNumber());
27368 10 : CheckDoubleEquals(3.14, result->NumberValue(context).ToChecked());
27369 5 : }
27370 :
27371 26644 : TEST(PrimitiveArray) {
27372 5 : v8::Isolate* isolate = CcTest::isolate();
27373 10 : v8::HandleScope scope(isolate);
27374 5 : LocalContext env;
27375 :
27376 : int length = 5;
27377 5 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 5));
27378 5 : CHECK_EQ(length, array->Length());
27379 :
27380 55 : for (int i = 0; i < length; i++) {
27381 25 : Local<v8::Primitive> item = array->Get(isolate, i);
27382 25 : CHECK(item->IsUndefined());
27383 : }
27384 :
27385 5 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
27386 5 : array->Set(isolate, 0, symbol);
27387 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27388 :
27389 : Local<v8::String> string =
27390 5 : v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kInternalized)
27391 : .ToLocalChecked();
27392 5 : array->Set(isolate, 1, string);
27393 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27394 10 : CHECK(array->Get(isolate, 1)->IsString());
27395 :
27396 5 : Local<v8::Number> num = v8::Number::New(env->GetIsolate(), 3.1415926);
27397 5 : array->Set(isolate, 2, num);
27398 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27399 10 : CHECK(array->Get(isolate, 1)->IsString());
27400 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27401 :
27402 : v8::Local<v8::Boolean> f = v8::False(isolate);
27403 5 : array->Set(isolate, 3, f);
27404 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27405 10 : CHECK(array->Get(isolate, 1)->IsString());
27406 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27407 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
27408 :
27409 5 : v8::Local<v8::Primitive> n = v8::Null(isolate);
27410 5 : array->Set(isolate, 4, n);
27411 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
27412 10 : CHECK(array->Get(isolate, 1)->IsString());
27413 10 : CHECK(array->Get(isolate, 2)->IsNumber());
27414 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
27415 10 : CHECK(array->Get(isolate, 4)->IsNull());
27416 5 : }
27417 :
27418 26644 : TEST(PersistentValueMap) {
27419 5 : v8::Isolate* isolate = CcTest::isolate();
27420 10 : v8::HandleScope scope(isolate);
27421 5 : LocalContext env;
27422 :
27423 : v8::PersistentValueMap<
27424 : std::string, v8::Value,
27425 : v8::DefaultPersistentValueMapTraits<std::string, v8::Value>>
27426 : map(isolate);
27427 : v8::Local<v8::Value> value =
27428 5 : v8::String::NewFromUtf8(isolate, "value",
27429 : v8::NewStringType::kInternalized)
27430 : .ToLocalChecked();
27431 15 : map.Set("key", value);
27432 5 : }
27433 :
27434 : namespace {
27435 :
27436 : bool wasm_streaming_callback_got_called = false;
27437 : bool wasm_streaming_data_got_collected = false;
27438 :
27439 4 : void WasmStreamingTestFinalizer(const v8::WeakCallbackInfo<void>& data) {
27440 4 : CHECK(!wasm_streaming_data_got_collected);
27441 4 : wasm_streaming_data_got_collected = true;
27442 4 : i::GlobalHandles::Destroy(reinterpret_cast<i::Address*>(data.GetParameter()));
27443 4 : }
27444 :
27445 4 : void WasmStreamingCallbackTestCallbackIsCalled(
27446 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27447 4 : CHECK(!wasm_streaming_callback_got_called);
27448 4 : wasm_streaming_callback_got_called = true;
27449 :
27450 : i::Handle<i::Object> global_handle =
27451 : reinterpret_cast<i::Isolate*>(args.GetIsolate())
27452 : ->global_handles()
27453 4 : ->Create(*v8::Utils::OpenHandle(*args.Data()));
27454 : i::GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
27455 : WasmStreamingTestFinalizer,
27456 4 : v8::WeakCallbackType::kParameter);
27457 4 : }
27458 :
27459 4 : void WasmStreamingCallbackTestOnBytesReceived(
27460 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27461 : std::shared_ptr<v8::WasmStreaming> streaming =
27462 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27463 :
27464 : // The first bytes of the WebAssembly magic word.
27465 4 : const uint8_t bytes[]{0x00, 0x61, 0x73};
27466 4 : streaming->OnBytesReceived(bytes, arraysize(bytes));
27467 4 : }
27468 :
27469 4 : void WasmStreamingCallbackTestFinishWithSuccess(
27470 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27471 : std::shared_ptr<v8::WasmStreaming> streaming =
27472 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27473 : // The bytes of a minimal WebAssembly module.
27474 4 : const uint8_t bytes[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
27475 4 : streaming->OnBytesReceived(bytes, arraysize(bytes));
27476 4 : streaming->Finish();
27477 4 : }
27478 :
27479 4 : void WasmStreamingCallbackTestFinishWithFailure(
27480 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27481 : std::shared_ptr<v8::WasmStreaming> streaming =
27482 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27483 4 : streaming->Finish();
27484 4 : }
27485 :
27486 4 : void WasmStreamingCallbackTestAbortWithReject(
27487 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27488 : std::shared_ptr<v8::WasmStreaming> streaming =
27489 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27490 8 : streaming->Abort(v8::Object::New(args.GetIsolate()));
27491 4 : }
27492 :
27493 4 : void WasmStreamingCallbackTestAbortNoReject(
27494 : const v8::FunctionCallbackInfo<v8::Value>& args) {
27495 : std::shared_ptr<v8::WasmStreaming> streaming =
27496 4 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27497 4 : streaming->Abort({});
27498 4 : }
27499 :
27500 24 : void TestWasmStreaming(v8::WasmStreamingCallback callback,
27501 : v8::Promise::PromiseState expected_state) {
27502 24 : CcTest::isolate()->SetWasmStreamingCallback(callback);
27503 24 : LocalContext env;
27504 24 : v8::Isolate* isolate = env->GetIsolate();
27505 48 : v8::HandleScope scope(isolate);
27506 :
27507 : // Call {WebAssembly.compileStreaming} with {null} as parameter. The parameter
27508 : // is only really processed by the embedder, so for this test the value is
27509 : // irrelevant.
27510 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(
27511 : CompileRun("WebAssembly.compileStreaming(null)"));
27512 :
27513 24 : EmptyMessageQueues(isolate);
27514 24 : CHECK_EQ(expected_state, promise->State());
27515 24 : }
27516 :
27517 : } // namespace
27518 :
27519 26643 : TEST(WasmStreamingCallback) {
27520 : TestWasmStreaming(WasmStreamingCallbackTestCallbackIsCalled,
27521 4 : v8::Promise::kPending);
27522 4 : CHECK(wasm_streaming_callback_got_called);
27523 4 : CcTest::CollectAllAvailableGarbage();
27524 4 : CHECK(wasm_streaming_data_got_collected);
27525 4 : }
27526 :
27527 26643 : TEST(WasmStreamingOnBytesReceived) {
27528 : TestWasmStreaming(WasmStreamingCallbackTestOnBytesReceived,
27529 4 : v8::Promise::kPending);
27530 4 : }
27531 :
27532 26643 : TEST(WasmStreamingFinishWithSuccess) {
27533 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithSuccess,
27534 4 : v8::Promise::kFulfilled);
27535 4 : }
27536 :
27537 26643 : TEST(WasmStreamingFinishWithFailure) {
27538 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithFailure,
27539 4 : v8::Promise::kRejected);
27540 4 : }
27541 :
27542 26643 : TEST(WasmStreamingAbortWithReject) {
27543 : TestWasmStreaming(WasmStreamingCallbackTestAbortWithReject,
27544 4 : v8::Promise::kRejected);
27545 4 : }
27546 :
27547 26643 : TEST(WasmStreamingAbortWithoutReject) {
27548 : TestWasmStreaming(WasmStreamingCallbackTestAbortNoReject,
27549 4 : v8::Promise::kPending);
27550 4 : }
27551 :
27552 : enum class AtomicsWaitCallbackAction {
27553 : Interrupt,
27554 : StopAndThrowInFirstCall,
27555 : StopAndThrowInSecondCall,
27556 : StopFromThreadAndThrow,
27557 : KeepWaiting
27558 : };
27559 :
27560 : class StopAtomicsWaitThread;
27561 :
27562 26 : struct AtomicsWaitCallbackInfo {
27563 : v8::Isolate* isolate;
27564 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle;
27565 : std::unique_ptr<StopAtomicsWaitThread> stop_thread;
27566 : AtomicsWaitCallbackAction action;
27567 :
27568 : Local<v8::SharedArrayBuffer> expected_sab;
27569 : v8::Isolate::AtomicsWaitEvent expected_event;
27570 : double expected_timeout;
27571 : int64_t expected_value;
27572 : size_t expected_offset;
27573 :
27574 : size_t ncalls = 0;
27575 : };
27576 :
27577 13 : class StopAtomicsWaitThread : public v8::base::Thread {
27578 : public:
27579 : explicit StopAtomicsWaitThread(AtomicsWaitCallbackInfo* info)
27580 13 : : Thread(Options("StopAtomicsWaitThread")), info_(info) {}
27581 :
27582 13 : void Run() override {
27583 13 : CHECK_NOT_NULL(info_->wake_handle);
27584 13 : info_->wake_handle->Wake();
27585 13 : }
27586 :
27587 : private:
27588 : AtomicsWaitCallbackInfo* info_;
27589 : };
27590 :
27591 169 : void AtomicsWaitCallbackForTesting(
27592 : v8::Isolate::AtomicsWaitEvent event, Local<v8::SharedArrayBuffer> sab,
27593 : size_t offset_in_bytes, int64_t value, double timeout_in_ms,
27594 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle, void* data) {
27595 169 : AtomicsWaitCallbackInfo* info = static_cast<AtomicsWaitCallbackInfo*>(data);
27596 169 : info->ncalls++;
27597 169 : info->wake_handle = wake_handle;
27598 169 : CHECK(sab->StrictEquals(info->expected_sab));
27599 169 : CHECK_EQ(timeout_in_ms, info->expected_timeout);
27600 169 : CHECK_EQ(value, info->expected_value);
27601 169 : CHECK_EQ(offset_in_bytes, info->expected_offset);
27602 :
27603 52 : auto ThrowSomething = [&]() {
27604 104 : info->isolate->ThrowException(v8::Integer::New(info->isolate, 42));
27605 221 : };
27606 :
27607 169 : if (event == v8::Isolate::AtomicsWaitEvent::kStartWait) {
27608 91 : CHECK_NOT_NULL(wake_handle);
27609 91 : switch (info->action) {
27610 : case AtomicsWaitCallbackAction::Interrupt:
27611 13 : info->isolate->TerminateExecution();
27612 13 : break;
27613 : case AtomicsWaitCallbackAction::StopAndThrowInFirstCall:
27614 13 : ThrowSomething();
27615 : V8_FALLTHROUGH;
27616 : case AtomicsWaitCallbackAction::StopAndThrowInSecondCall:
27617 39 : wake_handle->Wake();
27618 39 : break;
27619 : case AtomicsWaitCallbackAction::StopFromThreadAndThrow:
27620 26 : info->stop_thread = v8::base::make_unique<StopAtomicsWaitThread>(info);
27621 26 : info->stop_thread->Start();
27622 13 : break;
27623 : case AtomicsWaitCallbackAction::KeepWaiting:
27624 : break;
27625 : }
27626 : } else {
27627 78 : CHECK_EQ(event, info->expected_event);
27628 78 : CHECK_NULL(wake_handle);
27629 :
27630 78 : if (info->stop_thread) {
27631 13 : info->stop_thread->Join();
27632 13 : info->stop_thread.reset();
27633 : }
27634 :
27635 78 : if (info->action == AtomicsWaitCallbackAction::StopAndThrowInSecondCall ||
27636 : info->action == AtomicsWaitCallbackAction::StopFromThreadAndThrow) {
27637 39 : ThrowSomething();
27638 : }
27639 : }
27640 169 : }
27641 :
27642 : // Must be called from within HandleScope
27643 13 : void AtomicsWaitCallbackCommon(v8::Isolate* isolate, Local<Value> sab,
27644 : size_t initial_offset,
27645 : size_t offset_multiplier) {
27646 13 : CHECK(sab->IsSharedArrayBuffer());
27647 :
27648 : AtomicsWaitCallbackInfo info;
27649 13 : info.isolate = isolate;
27650 13 : info.expected_sab = sab.As<v8::SharedArrayBuffer>();
27651 13 : isolate->SetAtomicsWaitCallback(AtomicsWaitCallbackForTesting, &info);
27652 :
27653 : {
27654 26 : v8::TryCatch try_catch(isolate);
27655 13 : info.expected_offset = initial_offset;
27656 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27657 13 : info.expected_value = 0;
27658 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
27659 13 : info.action = AtomicsWaitCallbackAction::Interrupt;
27660 13 : info.ncalls = 0;
27661 : CompileRun("wait(0, 0);");
27662 26 : CHECK_EQ(info.ncalls, 2);
27663 13 : CHECK(try_catch.HasTerminated());
27664 : }
27665 :
27666 : {
27667 26 : v8::TryCatch try_catch(isolate);
27668 13 : info.expected_offset = initial_offset + offset_multiplier;
27669 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27670 13 : info.expected_value = 1;
27671 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
27672 13 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
27673 13 : info.ncalls = 0;
27674 : CompileRun("wait(1, 1);"); // real value is 0 != 1
27675 26 : CHECK_EQ(info.ncalls, 2);
27676 13 : CHECK(!try_catch.HasCaught());
27677 : }
27678 :
27679 : {
27680 26 : v8::TryCatch try_catch(isolate);
27681 13 : info.expected_offset = initial_offset + offset_multiplier;
27682 13 : info.expected_timeout = 0.125;
27683 13 : info.expected_value = 0;
27684 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
27685 13 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
27686 13 : info.ncalls = 0;
27687 : CompileRun("wait(1, 0, 0.125);"); // timeout
27688 26 : CHECK_EQ(info.ncalls, 2);
27689 13 : CHECK(!try_catch.HasCaught());
27690 : }
27691 :
27692 : {
27693 26 : v8::TryCatch try_catch(isolate);
27694 13 : info.expected_offset = initial_offset + offset_multiplier;
27695 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27696 13 : info.expected_value = 0;
27697 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27698 13 : info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
27699 13 : info.ncalls = 0;
27700 : CompileRun("wait(1, 0);");
27701 26 : CHECK_EQ(info.ncalls, 1); // Only one extra call
27702 13 : CHECK(try_catch.HasCaught());
27703 26 : CHECK(try_catch.Exception()->IsInt32());
27704 13 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27705 : }
27706 :
27707 : {
27708 26 : v8::TryCatch try_catch(isolate);
27709 13 : info.expected_offset = initial_offset + offset_multiplier;
27710 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27711 13 : info.expected_value = 0;
27712 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27713 13 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27714 13 : info.ncalls = 0;
27715 : CompileRun("wait(1, 0);");
27716 26 : CHECK_EQ(info.ncalls, 2);
27717 13 : CHECK(try_catch.HasCaught());
27718 26 : CHECK(try_catch.Exception()->IsInt32());
27719 13 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27720 : }
27721 :
27722 : {
27723 : // Same test as before, but with a different `expected_value`.
27724 26 : v8::TryCatch try_catch(isolate);
27725 13 : info.expected_offset = initial_offset + offset_multiplier;
27726 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27727 13 : info.expected_value = 200;
27728 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27729 13 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27730 13 : info.ncalls = 0;
27731 : CompileRun(
27732 : "setArrayElemAs(1, 200);"
27733 : "wait(1, 200);");
27734 26 : CHECK_EQ(info.ncalls, 2);
27735 13 : CHECK(try_catch.HasCaught());
27736 26 : CHECK(try_catch.Exception()->IsInt32());
27737 13 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27738 : }
27739 :
27740 : {
27741 : // Wake the `Atomics.wait()` call from a thread.
27742 26 : v8::TryCatch try_catch(isolate);
27743 13 : info.expected_offset = initial_offset;
27744 13 : info.expected_timeout = std::numeric_limits<double>::infinity();
27745 13 : info.expected_value = 0;
27746 13 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27747 13 : info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
27748 13 : info.ncalls = 0;
27749 : CompileRun(
27750 : "setArrayElemAs(1, 0);"
27751 : "wait(0, 0);");
27752 26 : CHECK_EQ(info.ncalls, 2);
27753 13 : CHECK(try_catch.HasCaught());
27754 26 : CHECK(try_catch.Exception()->IsInt32());
27755 13 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27756 : }
27757 13 : }
27758 :
27759 26644 : TEST(AtomicsWaitCallback) {
27760 5 : LocalContext env;
27761 5 : v8::Isolate* isolate = env->GetIsolate();
27762 10 : v8::HandleScope scope(isolate);
27763 : const char* init = R"(
27764 : let sab = new SharedArrayBuffer(16);
27765 : let int32arr = new Int32Array(sab, 4);
27766 : let setArrayElemAs = function(id, val) {
27767 : int32arr[id] = val;
27768 : };
27769 : let wait = function(id, val, timeout) {
27770 : if(arguments.length == 2) return Atomics.wait(int32arr, id, val);
27771 : return Atomics.wait(int32arr, id, val, timeout);
27772 : };
27773 : sab;)";
27774 5 : AtomicsWaitCallbackCommon(isolate, CompileRun(init), 4, 4);
27775 5 : }
27776 :
27777 : namespace v8 {
27778 : namespace internal {
27779 : namespace wasm {
27780 26643 : TEST(WasmI32AtomicWaitCallback) {
27781 : FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
27782 8 : WasmRunner<int32_t, int32_t, int32_t, double> r(ExecutionTier::kTurbofan);
27783 4 : r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
27784 : r.builder().SetHasSharedMemory();
27785 4 : BUILD(r, WASM_ATOMICS_WAIT(kExprI32AtomicWait, WASM_GET_LOCAL(0),
27786 : WASM_GET_LOCAL(1),
27787 : WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 4));
27788 4 : LocalContext env;
27789 4 : v8::Isolate* isolate = env->GetIsolate();
27790 8 : v8::HandleScope scope(isolate);
27791 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27792 4 : Handle<JSFunction> func = r.builder().WrapCode(0);
27793 16 : CHECK(env->Global()
27794 : ->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
27795 : .FromJust());
27796 : Handle<JSArrayBuffer> memory(
27797 : r.builder().instance_object()->memory_object()->array_buffer(),
27798 : i_isolate);
27799 16 : CHECK(env->Global()
27800 : ->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
27801 : .FromJust());
27802 :
27803 : const char* init = R"(
27804 : let int32arr = new Int32Array(sab, 4);
27805 : let setArrayElemAs = function(id, val) {
27806 : int32arr[id] = val;
27807 : };
27808 : let wait = function(id, val, timeout) {
27809 : if(arguments.length === 2)
27810 : return func(id << 2, val, -1);
27811 : return func(id << 2, val, timeout*1000000);
27812 : };
27813 : sab;)";
27814 4 : AtomicsWaitCallbackCommon(isolate, CompileRun(init), 4, 4);
27815 4 : }
27816 :
27817 26643 : TEST(WasmI64AtomicWaitCallback) {
27818 : FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
27819 8 : WasmRunner<int32_t, int32_t, double, double> r(ExecutionTier::kTurbofan);
27820 4 : r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
27821 : r.builder().SetHasSharedMemory();
27822 4 : BUILD(r, WASM_ATOMICS_WAIT(kExprI64AtomicWait, WASM_GET_LOCAL(0),
27823 : WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(1)),
27824 : WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 8));
27825 4 : LocalContext env;
27826 4 : v8::Isolate* isolate = env->GetIsolate();
27827 8 : v8::HandleScope scope(isolate);
27828 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27829 4 : Handle<JSFunction> func = r.builder().WrapCode(0);
27830 16 : CHECK(env->Global()
27831 : ->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
27832 : .FromJust());
27833 : Handle<JSArrayBuffer> memory(
27834 : r.builder().instance_object()->memory_object()->array_buffer(),
27835 : i_isolate);
27836 16 : CHECK(env->Global()
27837 : ->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
27838 : .FromJust());
27839 :
27840 : const char* init = R"(
27841 : let int64arr = new BigInt64Array(sab, 8);
27842 : let setArrayElemAs = function(id, val) {
27843 : int64arr[id] = BigInt(val);
27844 : };
27845 : let wait = function(id, val, timeout) {
27846 : if(arguments.length === 2)
27847 : return func(id << 3, val, -1);
27848 : return func(id << 3, val, timeout*1000000);
27849 : };
27850 : sab;)";
27851 4 : AtomicsWaitCallbackCommon(isolate, CompileRun(init), 8, 8);
27852 4 : }
27853 :
27854 : } // namespace wasm
27855 : } // namespace internal
27856 : } // namespace v8
27857 :
27858 : // TODO(mstarzinger): Move this into a test-api-wasm.cc file when this large
27859 : // test file is being split up into chunks.
27860 26644 : TEST(WasmModuleObjectCompileFailure) {
27861 5 : LocalContext env;
27862 5 : v8::Isolate* isolate = env->GetIsolate();
27863 10 : v8::HandleScope scope(isolate);
27864 :
27865 : {
27866 10 : v8::TryCatch try_catch(isolate);
27867 5 : uint8_t buffer[] = {0xDE, 0xAD, 0xBE, 0xEF};
27868 5 : v8::MemorySpan<const uint8_t> serialized_module;
27869 : v8::MemorySpan<const uint8_t> wire_bytes = {buffer, arraysize(buffer)};
27870 : v8::MaybeLocal<v8::WasmModuleObject> maybe_module =
27871 : v8::WasmModuleObject::DeserializeOrCompile(isolate, serialized_module,
27872 5 : wire_bytes);
27873 5 : CHECK(maybe_module.IsEmpty());
27874 5 : CHECK(try_catch.HasCaught());
27875 : }
27876 5 : }
27877 :
27878 26644 : TEST(BigIntAPI) {
27879 5 : LocalContext env;
27880 5 : v8::Isolate* isolate = env->GetIsolate();
27881 10 : v8::HandleScope scope(isolate);
27882 : bool lossless;
27883 : uint64_t words1[10];
27884 : uint64_t words2[10];
27885 :
27886 : {
27887 : Local<Value> bi = CompileRun("12n");
27888 5 : CHECK(bi->IsBigInt());
27889 :
27890 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 12);
27891 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless), 12);
27892 5 : CHECK_EQ(lossless, true);
27893 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 12);
27894 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 12);
27895 5 : CHECK_EQ(lossless, true);
27896 : }
27897 :
27898 : {
27899 : Local<Value> bi = CompileRun("-12n");
27900 5 : CHECK(bi->IsBigInt());
27901 :
27902 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), static_cast<uint64_t>(-12));
27903 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27904 : static_cast<uint64_t>(-12));
27905 5 : CHECK_EQ(lossless, false);
27906 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -12);
27907 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), -12);
27908 5 : CHECK_EQ(lossless, true);
27909 : }
27910 :
27911 : {
27912 : Local<Value> bi = CompileRun("123456789012345678901234567890n");
27913 5 : CHECK(bi->IsBigInt());
27914 :
27915 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 14083847773837265618ULL);
27916 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27917 : 14083847773837265618ULL);
27918 5 : CHECK_EQ(lossless, false);
27919 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -4362896299872285998LL);
27920 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless),
27921 : -4362896299872285998LL);
27922 5 : CHECK_EQ(lossless, false);
27923 : }
27924 :
27925 : {
27926 : Local<Value> bi = CompileRun("-123456789012345678901234567890n");
27927 5 : CHECK(bi->IsBigInt());
27928 :
27929 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 4362896299872285998LL);
27930 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27931 : 4362896299872285998LL);
27932 5 : CHECK_EQ(lossless, false);
27933 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 4362896299872285998LL);
27934 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 4362896299872285998LL);
27935 5 : CHECK_EQ(lossless, false);
27936 : }
27937 :
27938 : {
27939 : Local<v8::BigInt> bi =
27940 5 : v8::BigInt::NewFromWords(env.local(), 0, 0, words1).ToLocalChecked();
27941 10 : CHECK_EQ(bi->Uint64Value(), 0);
27942 5 : CHECK_EQ(bi->WordCount(), 0);
27943 : }
27944 :
27945 : {
27946 10 : TryCatch try_catch(isolate);
27947 : v8::MaybeLocal<v8::BigInt> bi = v8::BigInt::NewFromWords(
27948 5 : env.local(), 0, std::numeric_limits<int>::max(), words1);
27949 5 : CHECK(bi.IsEmpty());
27950 5 : CHECK(try_catch.HasCaught());
27951 : }
27952 :
27953 : {
27954 10 : TryCatch try_catch(isolate);
27955 : v8::MaybeLocal<v8::BigInt> bi =
27956 5 : v8::BigInt::NewFromWords(env.local(), 0, -1, words1);
27957 5 : CHECK(bi.IsEmpty());
27958 5 : CHECK(try_catch.HasCaught());
27959 : }
27960 :
27961 : {
27962 10 : TryCatch try_catch(isolate);
27963 : v8::MaybeLocal<v8::BigInt> bi =
27964 5 : v8::BigInt::NewFromWords(env.local(), 0, 1 << 30, words1);
27965 5 : CHECK(bi.IsEmpty());
27966 5 : CHECK(try_catch.HasCaught());
27967 : }
27968 :
27969 25 : for (int sign_bit = 0; sign_bit <= 1; sign_bit++) {
27970 10 : words1[0] = 0xffffffff00000000ULL;
27971 10 : words1[1] = 0x00000000ffffffffULL;
27972 : v8::Local<v8::BigInt> bi =
27973 10 : v8::BigInt::NewFromWords(env.local(), sign_bit, 2, words1)
27974 : .ToLocalChecked();
27975 10 : CHECK_EQ(bi->Uint64Value(&lossless),
27976 : sign_bit ? static_cast<uint64_t>(-static_cast<int64_t>(words1[0]))
27977 : : words1[0]);
27978 10 : CHECK_EQ(lossless, false);
27979 10 : CHECK_EQ(bi->Int64Value(&lossless), sign_bit
27980 : ? -static_cast<int64_t>(words1[0])
27981 : : static_cast<int64_t>(words1[0]));
27982 10 : CHECK_EQ(lossless, false);
27983 10 : CHECK_EQ(bi->WordCount(), 2);
27984 : int real_sign_bit;
27985 10 : int word_count = arraysize(words2);
27986 10 : bi->ToWordsArray(&real_sign_bit, &word_count, words2);
27987 10 : CHECK_EQ(real_sign_bit, sign_bit);
27988 10 : CHECK_EQ(word_count, 2);
27989 : }
27990 5 : }
27991 :
27992 : namespace {
27993 :
27994 : bool wasm_threads_enabled_value = false;
27995 :
27996 10 : bool MockWasmThreadsEnabledCallback(Local<Context>) {
27997 10 : return wasm_threads_enabled_value;
27998 : }
27999 :
28000 : } // namespace
28001 :
28002 26644 : TEST(TestSetWasmThreadsEnabledCallback) {
28003 5 : LocalContext env;
28004 5 : v8::Isolate* isolate = env->GetIsolate();
28005 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28006 10 : v8::HandleScope scope(isolate);
28007 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
28008 5 : i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context);
28009 :
28010 : // {Isolate::AreWasmThreadsEnabled} calls the callback set by the embedder if
28011 : // such a callback exists. Otherwise it returns
28012 : // {FLAG_experimental_wasm_threads}. First we test that the flag is returned
28013 : // correctly if no callback is set. Then we test that the flag is ignored if
28014 : // the callback is set.
28015 :
28016 5 : i::FLAG_experimental_wasm_threads = false;
28017 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28018 :
28019 5 : i::FLAG_experimental_wasm_threads = true;
28020 5 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28021 :
28022 5 : isolate->SetWasmThreadsEnabledCallback(MockWasmThreadsEnabledCallback);
28023 5 : wasm_threads_enabled_value = false;
28024 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28025 :
28026 5 : wasm_threads_enabled_value = true;
28027 5 : i::FLAG_experimental_wasm_threads = false;
28028 5 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28029 5 : }
28030 :
28031 26644 : TEST(TestGetUnwindState) {
28032 5 : LocalContext env;
28033 5 : v8::Isolate* isolate = env->GetIsolate();
28034 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28035 :
28036 5 : v8::UnwindState unwind_state = isolate->GetUnwindState();
28037 5 : v8::MemoryRange builtins_range = unwind_state.embedded_code_range;
28038 :
28039 : // Check that each off-heap builtin is within the builtins code range.
28040 : if (i::FLAG_embedded_builtins) {
28041 15215 : for (int id = 0; id < i::Builtins::builtin_count; id++) {
28042 : if (!i::Builtins::IsIsolateIndependent(id)) continue;
28043 7605 : i::Code builtin = i_isolate->builtins()->builtin(id);
28044 : i::Address start = builtin->InstructionStart();
28045 7605 : i::Address end = start + builtin->InstructionSize();
28046 :
28047 : i::Address builtins_start =
28048 7605 : reinterpret_cast<i::Address>(builtins_range.start);
28049 7605 : CHECK(start >= builtins_start &&
28050 : end < builtins_start + builtins_range.length_in_bytes);
28051 : }
28052 : } else {
28053 : CHECK_EQ(nullptr, builtins_range.start);
28054 : CHECK_EQ(0, builtins_range.length_in_bytes);
28055 : }
28056 :
28057 5 : v8::JSEntryStub js_entry_stub = unwind_state.js_entry_stub;
28058 :
28059 15 : CHECK_EQ(
28060 : i_isolate->heap()->builtin(i::Builtins::kJSEntry)->InstructionStart(),
28061 : reinterpret_cast<i::Address>(js_entry_stub.code.start));
28062 5 : }
28063 :
28064 26644 : TEST(MicrotaskContextShouldBeNativeContext) {
28065 5 : LocalContext env;
28066 5 : v8::Isolate* isolate = env->GetIsolate();
28067 10 : v8::HandleScope scope(isolate);
28068 :
28069 10 : auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
28070 : v8::Isolate* isolate = info.GetIsolate();
28071 10 : v8::HandleScope scope(isolate);
28072 : i::Handle<i::Context> context =
28073 10 : v8::Utils::OpenHandle(*isolate->GetEnteredOrMicrotaskContext());
28074 :
28075 5 : CHECK(context->IsNativeContext());
28076 : info.GetReturnValue().SetUndefined();
28077 10 : };
28078 :
28079 5 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
28080 10 : desc->InstanceTemplate()->SetCallAsFunctionHandler(callback);
28081 5 : Local<v8::Object> obj = desc->GetFunction(env.local())
28082 : .ToLocalChecked()
28083 : ->NewInstance(env.local())
28084 : .ToLocalChecked();
28085 :
28086 20 : CHECK(env->Global()->Set(env.local(), v8_str("callback"), obj).FromJust());
28087 : CompileRun(
28088 : "with({}){(async ()=>{"
28089 : " await 42;"
28090 : "})().then(callback);}");
28091 :
28092 5 : isolate->RunMicrotasks();
28093 5 : }
28094 :
28095 26644 : TEST(PreviewSetKeysIteratorEntriesWithDeleted) {
28096 5 : LocalContext env;
28097 10 : v8::HandleScope handle_scope(env->GetIsolate());
28098 5 : v8::Local<v8::Context> context = env.local();
28099 :
28100 : {
28101 : // Create set, delete entry, create iterator, preview.
28102 : v8::Local<v8::Object> iterator =
28103 : CompileRun("var set = new Set([1,2,3]); set.delete(1); set.keys()")
28104 5 : ->ToObject(context)
28105 : .ToLocalChecked();
28106 : bool is_key;
28107 : v8::Local<v8::Array> entries =
28108 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28109 5 : CHECK(!is_key);
28110 5 : CHECK_EQ(2, entries->Length());
28111 15 : CHECK_EQ(2, entries->Get(context, 0)
28112 : .ToLocalChecked()
28113 : ->Int32Value(context)
28114 : .FromJust());
28115 15 : CHECK_EQ(3, entries->Get(context, 1)
28116 : .ToLocalChecked()
28117 : ->Int32Value(context)
28118 : .FromJust());
28119 : }
28120 : {
28121 : // Create set, create iterator, delete entry, preview.
28122 : v8::Local<v8::Object> iterator =
28123 : CompileRun("var set = new Set([1,2,3]); set.keys()")
28124 5 : ->ToObject(context)
28125 : .ToLocalChecked();
28126 : CompileRun("set.delete(1);");
28127 : bool is_key;
28128 : v8::Local<v8::Array> entries =
28129 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28130 5 : CHECK(!is_key);
28131 5 : CHECK_EQ(2, entries->Length());
28132 15 : CHECK_EQ(2, entries->Get(context, 0)
28133 : .ToLocalChecked()
28134 : ->Int32Value(context)
28135 : .FromJust());
28136 15 : CHECK_EQ(3, entries->Get(context, 1)
28137 : .ToLocalChecked()
28138 : ->Int32Value(context)
28139 : .FromJust());
28140 : }
28141 : {
28142 : // Create set, create iterator, delete entry, iterate, preview.
28143 : v8::Local<v8::Object> iterator =
28144 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28145 5 : ->ToObject(context)
28146 : .ToLocalChecked();
28147 : CompileRun("set.delete(1); it.next();");
28148 : bool is_key;
28149 : v8::Local<v8::Array> entries =
28150 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28151 5 : CHECK(!is_key);
28152 5 : CHECK_EQ(1, entries->Length());
28153 15 : CHECK_EQ(3, entries->Get(context, 0)
28154 : .ToLocalChecked()
28155 : ->Int32Value(context)
28156 : .FromJust());
28157 : }
28158 : {
28159 : // Create set, create iterator, delete entry, iterate until empty, preview.
28160 : v8::Local<v8::Object> iterator =
28161 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28162 5 : ->ToObject(context)
28163 : .ToLocalChecked();
28164 : CompileRun("set.delete(1); it.next(); it.next();");
28165 : bool is_key;
28166 : v8::Local<v8::Array> entries =
28167 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28168 5 : CHECK(!is_key);
28169 5 : CHECK_EQ(0, entries->Length());
28170 : }
28171 : {
28172 : // Create set, create iterator, delete entry, iterate, trigger rehash,
28173 : // preview.
28174 : v8::Local<v8::Object> iterator =
28175 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28176 5 : ->ToObject(context)
28177 : .ToLocalChecked();
28178 : CompileRun("set.delete(1); it.next();");
28179 : CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28180 : bool is_key;
28181 : v8::Local<v8::Array> entries =
28182 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28183 5 : CHECK(!is_key);
28184 5 : CHECK_EQ(17, entries->Length());
28185 175 : for (uint32_t i = 0; i < 17; i++) {
28186 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28187 : .ToLocalChecked()
28188 : ->Int32Value(context)
28189 : .FromJust());
28190 : }
28191 : }
28192 5 : }
28193 :
28194 26644 : TEST(PreviewSetValuesIteratorEntriesWithDeleted) {
28195 5 : LocalContext env;
28196 10 : v8::HandleScope handle_scope(env->GetIsolate());
28197 5 : v8::Local<v8::Context> context = env.local();
28198 :
28199 : {
28200 : // Create set, delete entry, create iterator, preview.
28201 : v8::Local<v8::Object> iterator =
28202 : CompileRun("var set = new Set([1,2,3]); set.delete(1); set.values()")
28203 5 : ->ToObject(context)
28204 : .ToLocalChecked();
28205 : bool is_key;
28206 : v8::Local<v8::Array> entries =
28207 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28208 5 : CHECK(!is_key);
28209 5 : CHECK_EQ(2, entries->Length());
28210 15 : CHECK_EQ(2, entries->Get(context, 0)
28211 : .ToLocalChecked()
28212 : ->Int32Value(context)
28213 : .FromJust());
28214 15 : CHECK_EQ(3, entries->Get(context, 1)
28215 : .ToLocalChecked()
28216 : ->Int32Value(context)
28217 : .FromJust());
28218 : }
28219 : {
28220 : // Create set, create iterator, delete entry, preview.
28221 : v8::Local<v8::Object> iterator =
28222 : CompileRun("var set = new Set([1,2,3]); set.values()")
28223 5 : ->ToObject(context)
28224 : .ToLocalChecked();
28225 : CompileRun("set.delete(1);");
28226 : bool is_key;
28227 : v8::Local<v8::Array> entries =
28228 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28229 5 : CHECK(!is_key);
28230 5 : CHECK_EQ(2, entries->Length());
28231 15 : CHECK_EQ(2, entries->Get(context, 0)
28232 : .ToLocalChecked()
28233 : ->Int32Value(context)
28234 : .FromJust());
28235 15 : CHECK_EQ(3, entries->Get(context, 1)
28236 : .ToLocalChecked()
28237 : ->Int32Value(context)
28238 : .FromJust());
28239 : }
28240 : {
28241 : // Create set, create iterator, delete entry, iterate, preview.
28242 : v8::Local<v8::Object> iterator =
28243 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28244 5 : ->ToObject(context)
28245 : .ToLocalChecked();
28246 : CompileRun("set.delete(1); it.next();");
28247 : bool is_key;
28248 : v8::Local<v8::Array> entries =
28249 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28250 5 : CHECK(!is_key);
28251 5 : CHECK_EQ(1, entries->Length());
28252 15 : CHECK_EQ(3, entries->Get(context, 0)
28253 : .ToLocalChecked()
28254 : ->Int32Value(context)
28255 : .FromJust());
28256 : }
28257 : {
28258 : // Create set, create iterator, delete entry, iterate until empty, preview.
28259 : v8::Local<v8::Object> iterator =
28260 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28261 5 : ->ToObject(context)
28262 : .ToLocalChecked();
28263 : CompileRun("set.delete(1); it.next(); it.next();");
28264 : bool is_key;
28265 : v8::Local<v8::Array> entries =
28266 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28267 5 : CHECK(!is_key);
28268 5 : CHECK_EQ(0, entries->Length());
28269 : }
28270 : {
28271 : // Create set, create iterator, delete entry, iterate, trigger rehash,
28272 : // preview.
28273 : v8::Local<v8::Object> iterator =
28274 : CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28275 5 : ->ToObject(context)
28276 : .ToLocalChecked();
28277 : CompileRun("set.delete(1); it.next();");
28278 : CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28279 : bool is_key;
28280 : v8::Local<v8::Array> entries =
28281 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28282 5 : CHECK(!is_key);
28283 5 : CHECK_EQ(17, entries->Length());
28284 175 : for (uint32_t i = 0; i < 17; i++) {
28285 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28286 : .ToLocalChecked()
28287 : ->Int32Value(context)
28288 : .FromJust());
28289 : }
28290 : }
28291 5 : }
28292 :
28293 26644 : TEST(PreviewMapEntriesIteratorEntries) {
28294 5 : LocalContext env;
28295 10 : v8::HandleScope handle_scope(env->GetIsolate());
28296 5 : v8::Local<v8::Context> context = env.local();
28297 : {
28298 : // Create set, delete entry, create entries iterator, preview.
28299 : v8::Local<v8::Object> iterator =
28300 : CompileRun("var set = new Set([1,2,3]); set.delete(2); set.entries()")
28301 5 : ->ToObject(context)
28302 : .ToLocalChecked();
28303 : bool is_key;
28304 : v8::Local<v8::Array> entries =
28305 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28306 5 : CHECK(is_key);
28307 5 : CHECK_EQ(4, entries->Length());
28308 5 : uint32_t first = entries->Get(context, 0)
28309 : .ToLocalChecked()
28310 10 : ->Int32Value(context)
28311 5 : .FromJust();
28312 5 : uint32_t second = entries->Get(context, 2)
28313 : .ToLocalChecked()
28314 10 : ->Int32Value(context)
28315 5 : .FromJust();
28316 5 : CHECK_EQ(1, first);
28317 5 : CHECK_EQ(3, second);
28318 15 : CHECK_EQ(first, entries->Get(context, 1)
28319 : .ToLocalChecked()
28320 : ->Int32Value(context)
28321 : .FromJust());
28322 15 : CHECK_EQ(second, entries->Get(context, 3)
28323 : .ToLocalChecked()
28324 : ->Int32Value(context)
28325 : .FromJust());
28326 : }
28327 5 : }
28328 :
28329 26644 : TEST(PreviewMapValuesIteratorEntriesWithDeleted) {
28330 5 : LocalContext env;
28331 10 : v8::HandleScope handle_scope(env->GetIsolate());
28332 5 : v8::Local<v8::Context> context = env.local();
28333 :
28334 : {
28335 : // Create map, delete entry, create iterator, preview.
28336 : v8::Local<v8::Object> iterator = CompileRun(
28337 : "var map = new Map();"
28338 : "var key = {}; map.set(key, 1);"
28339 : "map.set({}, 2); map.set({}, 3);"
28340 : "map.delete(key);"
28341 : "map.values()")
28342 5 : ->ToObject(context)
28343 : .ToLocalChecked();
28344 : bool is_key;
28345 : v8::Local<v8::Array> entries =
28346 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28347 5 : CHECK(!is_key);
28348 5 : CHECK_EQ(2, entries->Length());
28349 15 : CHECK_EQ(2, entries->Get(context, 0)
28350 : .ToLocalChecked()
28351 : ->Int32Value(context)
28352 : .FromJust());
28353 15 : CHECK_EQ(3, entries->Get(context, 1)
28354 : .ToLocalChecked()
28355 : ->Int32Value(context)
28356 : .FromJust());
28357 : }
28358 : {
28359 : // Create map, create iterator, delete entry, preview.
28360 : v8::Local<v8::Object> iterator = CompileRun(
28361 : "var map = new Map();"
28362 : "var key = {}; map.set(key, 1);"
28363 : "map.set({}, 2); map.set({}, 3);"
28364 : "map.values()")
28365 5 : ->ToObject(context)
28366 : .ToLocalChecked();
28367 : CompileRun("map.delete(key);");
28368 : bool is_key;
28369 : v8::Local<v8::Array> entries =
28370 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28371 5 : CHECK(!is_key);
28372 5 : CHECK_EQ(2, entries->Length());
28373 15 : CHECK_EQ(2, entries->Get(context, 0)
28374 : .ToLocalChecked()
28375 : ->Int32Value(context)
28376 : .FromJust());
28377 15 : CHECK_EQ(3, entries->Get(context, 1)
28378 : .ToLocalChecked()
28379 : ->Int32Value(context)
28380 : .FromJust());
28381 : }
28382 : {
28383 : // Create map, create iterator, delete entry, iterate, preview.
28384 : v8::Local<v8::Object> iterator = CompileRun(
28385 : "var map = new Map();"
28386 : "var key = {}; map.set(key, 1);"
28387 : "map.set({}, 2); map.set({}, 3);"
28388 : "var it = map.values(); it")
28389 5 : ->ToObject(context)
28390 : .ToLocalChecked();
28391 : CompileRun("map.delete(key); it.next();");
28392 : bool is_key;
28393 : v8::Local<v8::Array> entries =
28394 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28395 5 : CHECK(!is_key);
28396 5 : CHECK_EQ(1, entries->Length());
28397 15 : CHECK_EQ(3, entries->Get(context, 0)
28398 : .ToLocalChecked()
28399 : ->Int32Value(context)
28400 : .FromJust());
28401 : }
28402 : {
28403 : // Create map, create iterator, delete entry, iterate until empty, preview.
28404 : v8::Local<v8::Object> iterator = CompileRun(
28405 : "var map = new Map();"
28406 : "var key = {}; map.set(key, 1);"
28407 : "map.set({}, 2); map.set({}, 3);"
28408 : "var it = map.values(); it")
28409 5 : ->ToObject(context)
28410 : .ToLocalChecked();
28411 : CompileRun("map.delete(key); it.next(); it.next();");
28412 : bool is_key;
28413 : v8::Local<v8::Array> entries =
28414 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28415 5 : CHECK(!is_key);
28416 5 : CHECK_EQ(0, entries->Length());
28417 : }
28418 : {
28419 : // Create map, create iterator, delete entry, iterate, trigger rehash,
28420 : // preview.
28421 : v8::Local<v8::Object> iterator = CompileRun(
28422 : "var map = new Map();"
28423 : "var key = {}; map.set(key, 1);"
28424 : "map.set({}, 2); map.set({}, 3);"
28425 : "var it = map.values(); it")
28426 5 : ->ToObject(context)
28427 : .ToLocalChecked();
28428 : CompileRun("map.delete(key); it.next();");
28429 : CompileRun("for (var i = 4; i < 20; i++) map.set({}, i);");
28430 : bool is_key;
28431 : v8::Local<v8::Array> entries =
28432 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28433 5 : CHECK(!is_key);
28434 5 : CHECK_EQ(17, entries->Length());
28435 175 : for (uint32_t i = 0; i < 17; i++) {
28436 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28437 : .ToLocalChecked()
28438 : ->Int32Value(context)
28439 : .FromJust());
28440 : }
28441 : }
28442 5 : }
28443 :
28444 26644 : TEST(PreviewMapKeysIteratorEntriesWithDeleted) {
28445 5 : LocalContext env;
28446 10 : v8::HandleScope handle_scope(env->GetIsolate());
28447 5 : v8::Local<v8::Context> context = env.local();
28448 :
28449 : {
28450 : // Create map, delete entry, create iterator, preview.
28451 : v8::Local<v8::Object> iterator = CompileRun(
28452 : "var map = new Map();"
28453 : "var key = 1; map.set(key, {});"
28454 : "map.set(2, {}); map.set(3, {});"
28455 : "map.delete(key);"
28456 : "map.keys()")
28457 5 : ->ToObject(context)
28458 : .ToLocalChecked();
28459 : bool is_key;
28460 : v8::Local<v8::Array> entries =
28461 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28462 5 : CHECK(!is_key);
28463 5 : CHECK_EQ(2, entries->Length());
28464 15 : CHECK_EQ(2, entries->Get(context, 0)
28465 : .ToLocalChecked()
28466 : ->Int32Value(context)
28467 : .FromJust());
28468 15 : CHECK_EQ(3, entries->Get(context, 1)
28469 : .ToLocalChecked()
28470 : ->Int32Value(context)
28471 : .FromJust());
28472 : }
28473 : {
28474 : // Create map, create iterator, delete entry, preview.
28475 : v8::Local<v8::Object> iterator = CompileRun(
28476 : "var map = new Map();"
28477 : "var key = 1; map.set(key, {});"
28478 : "map.set(2, {}); map.set(3, {});"
28479 : "map.keys()")
28480 5 : ->ToObject(context)
28481 : .ToLocalChecked();
28482 : CompileRun("map.delete(key);");
28483 : bool is_key;
28484 : v8::Local<v8::Array> entries =
28485 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28486 5 : CHECK(!is_key);
28487 5 : CHECK_EQ(2, entries->Length());
28488 15 : CHECK_EQ(2, entries->Get(context, 0)
28489 : .ToLocalChecked()
28490 : ->Int32Value(context)
28491 : .FromJust());
28492 15 : CHECK_EQ(3, entries->Get(context, 1)
28493 : .ToLocalChecked()
28494 : ->Int32Value(context)
28495 : .FromJust());
28496 : }
28497 : {
28498 : // Create map, create iterator, delete entry, iterate, preview.
28499 : v8::Local<v8::Object> iterator = CompileRun(
28500 : "var map = new Map();"
28501 : "var key = 1; map.set(key, {});"
28502 : "map.set(2, {}); map.set(3, {});"
28503 : "var it = map.keys(); it")
28504 5 : ->ToObject(context)
28505 : .ToLocalChecked();
28506 : CompileRun("map.delete(key); it.next();");
28507 : bool is_key;
28508 : v8::Local<v8::Array> entries =
28509 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28510 5 : CHECK(!is_key);
28511 5 : CHECK_EQ(1, entries->Length());
28512 15 : CHECK_EQ(3, entries->Get(context, 0)
28513 : .ToLocalChecked()
28514 : ->Int32Value(context)
28515 : .FromJust());
28516 : }
28517 : {
28518 : // Create map, create iterator, delete entry, iterate until empty, preview.
28519 : v8::Local<v8::Object> iterator = CompileRun(
28520 : "var map = new Map();"
28521 : "var key = 1; map.set(key, {});"
28522 : "map.set(2, {}); map.set(3, {});"
28523 : "var it = map.keys(); it")
28524 5 : ->ToObject(context)
28525 : .ToLocalChecked();
28526 : CompileRun("map.delete(key); it.next(); it.next();");
28527 : bool is_key;
28528 : v8::Local<v8::Array> entries =
28529 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28530 5 : CHECK(!is_key);
28531 5 : CHECK_EQ(0, entries->Length());
28532 : }
28533 5 : }
28534 :
28535 : namespace {
28536 : static v8::Isolate* isolate_1;
28537 : static v8::Isolate* isolate_2;
28538 26639 : v8::Persistent<v8::Context> context_1;
28539 26639 : v8::Persistent<v8::Context> context_2;
28540 :
28541 20 : static void CallIsolate1(const v8::FunctionCallbackInfo<v8::Value>& args) {
28542 20 : v8::Isolate::Scope isolate_scope(isolate_1);
28543 40 : v8::HandleScope handle_scope(isolate_1);
28544 : v8::Local<v8::Context> context =
28545 20 : v8::Local<v8::Context>::New(isolate_1, context_1);
28546 : v8::Context::Scope context_scope(context);
28547 : CompileRun("f1() //# sourceURL=isolate1b");
28548 20 : }
28549 :
28550 20 : static void CallIsolate2(const v8::FunctionCallbackInfo<v8::Value>& args) {
28551 20 : v8::Isolate::Scope isolate_scope(isolate_2);
28552 40 : v8::HandleScope handle_scope(isolate_2);
28553 : v8::Local<v8::Context> context =
28554 20 : v8::Local<v8::Context>::New(isolate_2, context_2);
28555 : v8::Context::Scope context_scope(context);
28556 20 : reinterpret_cast<i::Isolate*>(isolate_2)->heap()->CollectAllGarbage(
28557 : i::Heap::kNoGCFlags, i::GarbageCollectionReason::kTesting,
28558 20 : v8::kGCCallbackFlagForced);
28559 : CompileRun("f2() //# sourceURL=isolate2b");
28560 20 : }
28561 :
28562 : } // anonymous namespace
28563 :
28564 26644 : UNINITIALIZED_TEST(NestedIsolates) {
28565 : #ifdef VERIFY_HEAP
28566 : i::FLAG_verify_heap = true;
28567 : #endif // VERIFY_HEAP
28568 : // Create two isolates and set up C++ functions via function templates that
28569 : // call into the other isolate. Recurse a few times, trigger GC along the way,
28570 : // and finally capture a stack trace. Check that the stack trace only includes
28571 : // frames from its own isolate.
28572 : v8::Isolate::CreateParams create_params;
28573 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
28574 5 : isolate_1 = v8::Isolate::New(create_params);
28575 5 : isolate_2 = v8::Isolate::New(create_params);
28576 :
28577 : {
28578 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28579 10 : v8::HandleScope handle_scope(isolate_1);
28580 :
28581 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_1);
28582 : v8::Context::Scope context_scope(context);
28583 :
28584 : v8::Local<v8::FunctionTemplate> fun_templ =
28585 5 : v8::FunctionTemplate::New(isolate_1, CallIsolate2);
28586 5 : fun_templ->SetClassName(v8_str(isolate_1, "call_isolate_2"));
28587 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28588 20 : CHECK(context->Global()
28589 : ->Set(context, v8_str(isolate_1, "call_isolate_2"), fun)
28590 : .FromJust());
28591 : CompileRun(
28592 : "let c = 0;"
28593 : "function f1() {"
28594 : " c++;"
28595 : " return call_isolate_2();"
28596 : "} //# sourceURL=isolate1a");
28597 5 : context_1.Reset(isolate_1, context);
28598 : }
28599 :
28600 : {
28601 5 : v8::Isolate::Scope isolate_scope(isolate_2);
28602 10 : v8::HandleScope handle_scope(isolate_2);
28603 :
28604 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_2);
28605 : v8::Context::Scope context_scope(context);
28606 :
28607 : v8::Local<v8::FunctionTemplate> fun_templ =
28608 5 : v8::FunctionTemplate::New(isolate_2, CallIsolate1);
28609 5 : fun_templ->SetClassName(v8_str(isolate_2, "call_isolate_1"));
28610 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28611 :
28612 20 : CHECK(context->Global()
28613 : ->Set(context, v8_str(isolate_2, "call_isolate_1"), fun)
28614 : .FromJust());
28615 : CompileRun(
28616 : "let c = 4;"
28617 : "let result = undefined;"
28618 : "function f2() {"
28619 : " if (c-- > 0) return call_isolate_1();"
28620 : " else result = new Error().stack;"
28621 : "} //# sourceURL=isolate2a");
28622 5 : context_2.Reset(isolate_2, context);
28623 :
28624 : v8::Local<v8::String> result =
28625 : CompileRun("f2(); result //# sourceURL=isolate2c")
28626 5 : ->ToString(context)
28627 : .ToLocalChecked();
28628 : v8::Local<v8::String> expectation = v8_str(isolate_2,
28629 : "Error\n"
28630 : " at f2 (isolate2a:1:104)\n"
28631 : " at isolate2b:1:1\n"
28632 : " at f2 (isolate2a:1:71)\n"
28633 : " at isolate2b:1:1\n"
28634 : " at f2 (isolate2a:1:71)\n"
28635 : " at isolate2b:1:1\n"
28636 : " at f2 (isolate2a:1:71)\n"
28637 : " at isolate2b:1:1\n"
28638 : " at f2 (isolate2a:1:71)\n"
28639 5 : " at isolate2c:1:1");
28640 5 : CHECK(result->StrictEquals(expectation));
28641 : }
28642 :
28643 : {
28644 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28645 10 : v8::HandleScope handle_scope(isolate_1);
28646 : v8::Local<v8::Context> context =
28647 5 : v8::Local<v8::Context>::New(isolate_1, context_1);
28648 : v8::Context::Scope context_scope(context);
28649 5 : ExpectInt32("c", 4);
28650 : }
28651 :
28652 5 : isolate_1->Dispose();
28653 5 : isolate_2->Dispose();
28654 79922 : }
|