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/futex-emulation.h"
49 : #include "src/global-handles.h"
50 : #include "src/heap/incremental-marking.h"
51 : #include "src/heap/local-allocator.h"
52 : #include "src/lookup.h"
53 : #include "src/objects-inl.h"
54 : #include "src/objects/hash-table-inl.h"
55 : #include "src/objects/js-array-buffer-inl.h"
56 : #include "src/objects/js-array-inl.h"
57 : #include "src/objects/js-promise-inl.h"
58 : #include "src/profiler/cpu-profiler.h"
59 : #include "src/unicode-inl.h"
60 : #include "src/utils.h"
61 : #include "src/vm-state.h"
62 : #include "src/wasm/wasm-js.h"
63 : #include "test/cctest/heap/heap-tester.h"
64 : #include "test/cctest/heap/heap-utils.h"
65 :
66 : static const bool kLogThreading = false;
67 :
68 : using ::v8::Array;
69 : using ::v8::Boolean;
70 : using ::v8::BooleanObject;
71 : using ::v8::Context;
72 : using ::v8::Extension;
73 : using ::v8::Function;
74 : using ::v8::FunctionTemplate;
75 : using ::v8::HandleScope;
76 : using ::v8::Local;
77 : using ::v8::Maybe;
78 : using ::v8::Message;
79 : using ::v8::MessageCallback;
80 : using ::v8::Module;
81 : using ::v8::Name;
82 : using ::v8::None;
83 : using ::v8::Object;
84 : using ::v8::ObjectTemplate;
85 : using ::v8::Persistent;
86 : using ::v8::PropertyAttribute;
87 : using ::v8::Script;
88 : using ::v8::StackTrace;
89 : using ::v8::String;
90 : using ::v8::Symbol;
91 : using ::v8::TryCatch;
92 : using ::v8::Undefined;
93 : using ::v8::V8;
94 : using ::v8::Value;
95 :
96 :
97 : #define THREADED_PROFILED_TEST(Name) \
98 : static void Test##Name(); \
99 : TEST(Name##WithProfiler) { \
100 : RunWithProfiler(&Test##Name); \
101 : } \
102 : THREADED_TEST(Name)
103 :
104 75 : void RunWithProfiler(void (*test)()) {
105 75 : LocalContext env;
106 150 : v8::HandleScope scope(env->GetIsolate());
107 75 : v8::Local<v8::String> profile_name = v8_str("my_profile1");
108 75 : v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
109 75 : cpu_profiler->StartProfiling(profile_name);
110 75 : (*test)();
111 75 : reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
112 150 : cpu_profiler->Dispose();
113 75 : }
114 :
115 :
116 : static int signature_callback_count;
117 : static Local<Value> signature_expected_receiver;
118 3900 : static void IncrementingSignatureCallback(
119 28080 : const v8::FunctionCallbackInfo<v8::Value>& args) {
120 3900 : ApiTestFuzzer::Fuzz();
121 3900 : signature_callback_count++;
122 11700 : CHECK(signature_expected_receiver->Equals(
123 : args.GetIsolate()->GetCurrentContext(),
124 : args.Holder())
125 : .FromJust());
126 11700 : CHECK(signature_expected_receiver->Equals(
127 : args.GetIsolate()->GetCurrentContext(),
128 : args.This())
129 : .FromJust());
130 : v8::Local<v8::Array> result =
131 3900 : v8::Array::New(args.GetIsolate(), args.Length());
132 10920 : for (int i = 0; i < args.Length(); i++) {
133 6240 : CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
134 : v8::Integer::New(args.GetIsolate(), i), args[i])
135 : .FromJust());
136 : }
137 : args.GetReturnValue().Set(result);
138 3900 : }
139 :
140 :
141 215 : static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
142 : info.GetReturnValue().Set(42);
143 215 : }
144 :
145 :
146 : // Tests that call v8::V8::Dispose() cannot be threaded.
147 28342 : UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
148 5 : CHECK(v8::V8::Initialize());
149 5 : CHECK(v8::V8::Dispose());
150 5 : }
151 :
152 :
153 : // Tests that call v8::V8::Dispose() cannot be threaded.
154 28342 : UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
155 5 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
156 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
157 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
158 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
159 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
160 5 : }
161 :
162 : // Tests that Smi::kZero is set up properly.
163 28347 : UNINITIALIZED_TEST(SmiZero) { CHECK_EQ(i::Smi::kZero, i::Smi::kZero); }
164 :
165 28343 : THREADED_TEST(Handles) {
166 6 : v8::HandleScope scope(CcTest::isolate());
167 : Local<Context> local_env;
168 : {
169 6 : LocalContext env;
170 6 : local_env = env.local();
171 : }
172 :
173 : // Local context should still be live.
174 6 : CHECK(!local_env.IsEmpty());
175 6 : local_env->Enter();
176 :
177 6 : v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
178 6 : CHECK(!undef.IsEmpty());
179 6 : CHECK(undef->IsUndefined());
180 :
181 : const char* source = "1 + 2 + 3";
182 6 : Local<Script> script = v8_compile(source);
183 6 : CHECK_EQ(6, v8_run_int32value(script));
184 :
185 6 : local_env->Exit();
186 6 : }
187 :
188 :
189 28343 : THREADED_TEST(IsolateOfContext) {
190 6 : v8::HandleScope scope(CcTest::isolate());
191 6 : v8::Local<Context> env = Context::New(CcTest::isolate());
192 :
193 6 : CHECK(!env->GetIsolate()->InContext());
194 6 : CHECK(env->GetIsolate() == CcTest::isolate());
195 6 : env->Enter();
196 6 : CHECK(env->GetIsolate()->InContext());
197 6 : CHECK(env->GetIsolate() == CcTest::isolate());
198 6 : env->Exit();
199 6 : CHECK(!env->GetIsolate()->InContext());
200 6 : CHECK(env->GetIsolate() == CcTest::isolate());
201 6 : }
202 :
203 420 : static void TestSignatureLooped(const char* operation, Local<Value> receiver,
204 : v8::Isolate* isolate) {
205 : i::ScopedVector<char> source(200);
206 : i::SNPrintF(source,
207 : "for (var i = 0; i < 10; i++) {"
208 : " %s"
209 : "}",
210 420 : operation);
211 420 : signature_callback_count = 0;
212 420 : signature_expected_receiver = receiver;
213 : bool expected_to_throw = receiver.IsEmpty();
214 840 : v8::TryCatch try_catch(isolate);
215 : CompileRun(source.start());
216 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
217 420 : if (!expected_to_throw) {
218 300 : CHECK_EQ(10, signature_callback_count);
219 : } else {
220 600 : CHECK(v8_str("TypeError: Illegal invocation")
221 : ->Equals(isolate->GetCurrentContext(),
222 : try_catch.Exception()
223 : ->ToString(isolate->GetCurrentContext())
224 : .ToLocalChecked())
225 : .FromJust());
226 : }
227 420 : }
228 :
229 420 : static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
230 : v8::Isolate* isolate) {
231 : i::ScopedVector<char> source(200);
232 : i::SNPrintF(source,
233 : "function test() {"
234 : " %s"
235 : "}"
236 : "try { test() } catch(e) {}"
237 : "try { test() } catch(e) {}"
238 : "%%OptimizeFunctionOnNextCall(test);"
239 : "test()",
240 420 : operation);
241 420 : signature_callback_count = 0;
242 420 : signature_expected_receiver = receiver;
243 : bool expected_to_throw = receiver.IsEmpty();
244 840 : v8::TryCatch try_catch(isolate);
245 : CompileRun(source.start());
246 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
247 420 : if (!expected_to_throw) {
248 300 : CHECK_EQ(3, signature_callback_count);
249 : } else {
250 600 : CHECK(v8_str("TypeError: Illegal invocation")
251 : ->Equals(isolate->GetCurrentContext(),
252 : try_catch.Exception()
253 : ->ToString(isolate->GetCurrentContext())
254 : .ToLocalChecked())
255 : .FromJust());
256 : }
257 420 : }
258 :
259 420 : static void TestSignature(const char* operation, Local<Value> receiver,
260 : v8::Isolate* isolate) {
261 420 : TestSignatureLooped(operation, receiver, isolate);
262 420 : TestSignatureOptimized(operation, receiver, isolate);
263 420 : }
264 :
265 28343 : THREADED_TEST(ReceiverSignature) {
266 6 : i::FLAG_allow_natives_syntax = true;
267 6 : LocalContext env;
268 6 : v8::Isolate* isolate = env->GetIsolate();
269 12 : v8::HandleScope scope(isolate);
270 : // Setup templates.
271 6 : v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
272 6 : v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
273 : v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
274 6 : isolate, IncrementingSignatureCallback, Local<Value>(), sig);
275 : v8::Local<v8::FunctionTemplate> callback =
276 6 : v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
277 6 : v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
278 6 : sub_fun->Inherit(fun);
279 : v8::Local<v8::FunctionTemplate> direct_sub_fun =
280 6 : v8::FunctionTemplate::New(isolate);
281 6 : direct_sub_fun->Inherit(fun);
282 : v8::Local<v8::FunctionTemplate> unrel_fun =
283 6 : v8::FunctionTemplate::New(isolate);
284 : // Install properties.
285 6 : v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
286 12 : fun_proto->Set(v8_str("prop_sig"), callback_sig);
287 12 : fun_proto->Set(v8_str("prop"), callback);
288 : fun_proto->SetAccessorProperty(
289 12 : v8_str("accessor_sig"), callback_sig, callback_sig);
290 12 : fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
291 : // Instantiate templates.
292 : Local<Value> fun_instance =
293 18 : fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
294 : Local<Value> sub_fun_instance =
295 18 : sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
296 : // Instance template with properties.
297 : v8::Local<v8::ObjectTemplate> direct_instance_templ =
298 6 : direct_sub_fun->InstanceTemplate();
299 12 : direct_instance_templ->Set(v8_str("prop_sig"), callback_sig);
300 12 : direct_instance_templ->Set(v8_str("prop"), callback);
301 : direct_instance_templ->SetAccessorProperty(v8_str("accessor_sig"),
302 12 : callback_sig, callback_sig);
303 : direct_instance_templ->SetAccessorProperty(v8_str("accessor"), callback,
304 12 : callback);
305 : Local<Value> direct_instance =
306 6 : direct_instance_templ->NewInstance(env.local()).ToLocalChecked();
307 : // Setup global variables.
308 36 : CHECK(env->Global()
309 : ->Set(env.local(), v8_str("Fun"),
310 : fun->GetFunction(env.local()).ToLocalChecked())
311 : .FromJust());
312 42 : CHECK(env->Global()
313 : ->Set(env.local(), v8_str("UnrelFun"),
314 : unrel_fun->GetFunction(env.local()).ToLocalChecked())
315 : .FromJust());
316 30 : CHECK(env->Global()
317 : ->Set(env.local(), v8_str("fun_instance"), fun_instance)
318 : .FromJust());
319 30 : CHECK(env->Global()
320 : ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
321 : .FromJust());
322 30 : CHECK(env->Global()
323 : ->Set(env.local(), v8_str("direct_instance"), direct_instance)
324 : .FromJust());
325 : CompileRun(
326 : "var accessor_sig_key = 'accessor_sig';"
327 : "var accessor_key = 'accessor';"
328 : "var prop_sig_key = 'prop_sig';"
329 : "var prop_key = 'prop';"
330 : ""
331 : "function copy_props(obj) {"
332 : " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
333 : " var source = Fun.prototype;"
334 : " for (var i in keys) {"
335 : " var key = keys[i];"
336 : " var desc = Object.getOwnPropertyDescriptor(source, key);"
337 : " Object.defineProperty(obj, key, desc);"
338 : " }"
339 : "}"
340 : ""
341 : "var plain = {};"
342 : "copy_props(plain);"
343 : "var unrelated = new UnrelFun();"
344 : "copy_props(unrelated);"
345 : "var inherited = { __proto__: fun_instance };"
346 : "var inherited_direct = { __proto__: direct_instance };");
347 : // Test with and without ICs
348 : const char* test_objects[] = {
349 : "fun_instance", "sub_fun_instance", "direct_instance", "plain",
350 6 : "unrelated", "inherited", "inherited_direct"};
351 : unsigned bad_signature_start_offset = 3;
352 48 : for (unsigned i = 0; i < arraysize(test_objects); i++) {
353 : i::ScopedVector<char> source(200);
354 : i::SNPrintF(
355 42 : source, "var test_object = %s; test_object", test_objects[i]);
356 42 : Local<Value> test_object = CompileRun(source.start());
357 42 : TestSignature("test_object.prop();", test_object, isolate);
358 42 : TestSignature("test_object.accessor;", test_object, isolate);
359 42 : TestSignature("test_object[accessor_key];", test_object, isolate);
360 42 : TestSignature("test_object.accessor = 1;", test_object, isolate);
361 42 : TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
362 42 : if (i >= bad_signature_start_offset) test_object = Local<Value>();
363 42 : TestSignature("test_object.prop_sig();", test_object, isolate);
364 42 : TestSignature("test_object.accessor_sig;", test_object, isolate);
365 42 : TestSignature("test_object[accessor_sig_key];", test_object, isolate);
366 42 : TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
367 42 : TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
368 6 : }
369 6 : }
370 :
371 :
372 28343 : THREADED_TEST(HulIgennem) {
373 6 : LocalContext env;
374 6 : v8::Isolate* isolate = env->GetIsolate();
375 12 : v8::HandleScope scope(isolate);
376 : v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
377 6 : Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
378 6 : char* value = i::NewArray<char>(undef_str->Utf8Length(isolate) + 1);
379 6 : undef_str->WriteUtf8(isolate, value);
380 6 : CHECK_EQ(0, strcmp(value, "undefined"));
381 6 : i::DeleteArray(value);
382 6 : }
383 :
384 :
385 28343 : THREADED_TEST(Access) {
386 6 : LocalContext env;
387 6 : v8::Isolate* isolate = env->GetIsolate();
388 12 : v8::HandleScope scope(isolate);
389 6 : Local<v8::Object> obj = v8::Object::New(isolate);
390 : Local<Value> foo_before =
391 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
392 6 : CHECK(foo_before->IsUndefined());
393 6 : Local<String> bar_str = v8_str("bar");
394 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
395 : Local<Value> foo_after =
396 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
397 6 : CHECK(!foo_after->IsUndefined());
398 6 : CHECK(foo_after->IsString());
399 12 : CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
400 :
401 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).ToChecked());
402 : bool result;
403 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).To(&result));
404 12 : CHECK(result);
405 6 : }
406 :
407 :
408 28343 : THREADED_TEST(AccessElement) {
409 6 : LocalContext env;
410 12 : v8::HandleScope scope(env->GetIsolate());
411 6 : Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
412 6 : Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
413 6 : CHECK(before->IsUndefined());
414 6 : Local<String> bar_str = v8_str("bar");
415 12 : CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
416 6 : Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
417 6 : CHECK(!after->IsUndefined());
418 6 : CHECK(after->IsString());
419 12 : CHECK(bar_str->Equals(env.local(), after).FromJust());
420 :
421 : Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
422 24 : CHECK(v8_str("a")
423 : ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
424 : .FromJust());
425 24 : CHECK(v8_str("b")
426 : ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
427 6 : .FromJust());
428 6 : }
429 :
430 :
431 28343 : THREADED_TEST(Script) {
432 6 : LocalContext env;
433 12 : v8::HandleScope scope(env->GetIsolate());
434 : const char* source = "1 + 2 + 3";
435 6 : Local<Script> script = v8_compile(source);
436 12 : CHECK_EQ(6, v8_run_int32value(script));
437 6 : }
438 :
439 :
440 : class TestResource: public String::ExternalStringResource {
441 : public:
442 : explicit TestResource(uint16_t* data, int* counter = nullptr,
443 : bool owning_data = true)
444 17941 : : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
445 3064640 : while (data[length_]) ++length_;
446 : }
447 :
448 35876 : ~TestResource() override {
449 17941 : if (owning_data_) i::DeleteArray(data_);
450 17941 : if (counter_ != nullptr) ++*counter_;
451 35876 : }
452 :
453 56579 : const uint16_t* data() const override { return data_; }
454 :
455 71698 : size_t length() const override { return length_; }
456 :
457 : private:
458 : uint16_t* data_;
459 : size_t length_;
460 : int* counter_;
461 : bool owning_data_;
462 : };
463 :
464 :
465 : class TestOneByteResource : public String::ExternalOneByteStringResource {
466 : public:
467 : explicit TestOneByteResource(const char* data, int* counter = nullptr,
468 : size_t offset = 0)
469 : : orig_data_(data),
470 10 : data_(data + offset),
471 69 : length_(strlen(data) - offset),
472 148 : counter_(counter) {}
473 :
474 128 : ~TestOneByteResource() override {
475 69 : i::DeleteArray(orig_data_);
476 69 : if (counter_ != nullptr) ++*counter_;
477 128 : }
478 :
479 194 : const char* data() const override { return data_; }
480 :
481 183 : size_t length() const override { return length_; }
482 :
483 : private:
484 : const char* orig_data_;
485 : const char* data_;
486 : size_t length_;
487 : int* counter_;
488 : };
489 :
490 :
491 28343 : THREADED_TEST(ScriptUsingStringResource) {
492 6 : int dispose_count = 0;
493 : const char* c_source = "1 + 2 * 3";
494 6 : uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
495 : {
496 6 : LocalContext env;
497 12 : v8::HandleScope scope(env->GetIsolate());
498 6 : TestResource* resource = new TestResource(two_byte_source, &dispose_count);
499 : Local<String> source =
500 6 : String::NewExternalTwoByte(env->GetIsolate(), resource)
501 6 : .ToLocalChecked();
502 6 : Local<Script> script = v8_compile(source);
503 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
504 6 : CHECK(value->IsNumber());
505 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
506 6 : CHECK(source->IsExternal());
507 6 : CHECK_EQ(resource,
508 : static_cast<TestResource*>(source->GetExternalStringResource()));
509 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
510 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
511 : source->GetExternalStringResourceBase(&encoding));
512 6 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
513 6 : CcTest::CollectAllGarbage();
514 12 : CHECK_EQ(0, dispose_count);
515 : }
516 6 : CcTest::i_isolate()->compilation_cache()->Clear();
517 6 : CcTest::CollectAllAvailableGarbage();
518 6 : CHECK_EQ(1, dispose_count);
519 6 : }
520 :
521 :
522 28343 : THREADED_TEST(ScriptUsingOneByteStringResource) {
523 6 : int dispose_count = 0;
524 : const char* c_source = "1 + 2 * 3";
525 : {
526 6 : LocalContext env;
527 12 : v8::HandleScope scope(env->GetIsolate());
528 : TestOneByteResource* resource =
529 6 : new TestOneByteResource(i::StrDup(c_source), &dispose_count);
530 : Local<String> source =
531 6 : String::NewExternalOneByte(env->GetIsolate(), resource)
532 6 : .ToLocalChecked();
533 6 : CHECK(source->IsExternalOneByte());
534 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
535 : source->GetExternalOneByteStringResource());
536 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
537 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
538 : source->GetExternalStringResourceBase(&encoding));
539 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
540 6 : Local<Script> script = v8_compile(source);
541 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
542 6 : CHECK(value->IsNumber());
543 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
544 6 : CcTest::CollectAllGarbage();
545 12 : CHECK_EQ(0, dispose_count);
546 : }
547 6 : CcTest::i_isolate()->compilation_cache()->Clear();
548 6 : CcTest::CollectAllAvailableGarbage();
549 6 : CHECK_EQ(1, dispose_count);
550 6 : }
551 :
552 :
553 28343 : THREADED_TEST(ScriptMakingExternalString) {
554 6 : int dispose_count = 0;
555 6 : uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
556 : {
557 6 : LocalContext env;
558 12 : v8::HandleScope scope(env->GetIsolate());
559 : Local<String> source =
560 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
561 6 : v8::NewStringType::kNormal)
562 6 : .ToLocalChecked();
563 : // Trigger GCs so that the newly allocated string moves to old gen.
564 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
565 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
566 6 : CHECK(!source->IsExternal());
567 6 : CHECK(!source->IsExternalOneByte());
568 6 : String::Encoding encoding = String::UNKNOWN_ENCODING;
569 6 : CHECK(!source->GetExternalStringResourceBase(&encoding));
570 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
571 : bool success = source->MakeExternal(new TestResource(two_byte_source,
572 12 : &dispose_count));
573 6 : CHECK(success);
574 6 : Local<Script> script = v8_compile(source);
575 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
576 6 : CHECK(value->IsNumber());
577 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
578 6 : CcTest::CollectAllGarbage();
579 12 : CHECK_EQ(0, dispose_count);
580 : }
581 6 : CcTest::i_isolate()->compilation_cache()->Clear();
582 6 : CcTest::CollectAllGarbage();
583 6 : CHECK_EQ(1, dispose_count);
584 6 : }
585 :
586 :
587 28343 : THREADED_TEST(ScriptMakingExternalOneByteString) {
588 6 : int dispose_count = 0;
589 : const char* c_source = "1 + 2 * 3";
590 : {
591 6 : LocalContext env;
592 12 : v8::HandleScope scope(env->GetIsolate());
593 6 : Local<String> source = v8_str(c_source);
594 : // Trigger GCs so that the newly allocated string moves to old gen.
595 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
596 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
597 : bool success = source->MakeExternal(
598 12 : new TestOneByteResource(i::StrDup(c_source), &dispose_count));
599 6 : CHECK(success);
600 6 : Local<Script> script = v8_compile(source);
601 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
602 6 : CHECK(value->IsNumber());
603 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
604 6 : CcTest::CollectAllGarbage();
605 12 : CHECK_EQ(0, dispose_count);
606 : }
607 6 : CcTest::i_isolate()->compilation_cache()->Clear();
608 6 : CcTest::CollectAllGarbage();
609 6 : CHECK_EQ(1, dispose_count);
610 6 : }
611 :
612 :
613 28342 : TEST(MakingExternalStringConditions) {
614 5 : LocalContext env;
615 10 : v8::HandleScope scope(env->GetIsolate());
616 :
617 : // Free some space in the new space so that we can check freshness.
618 5 : CcTest::CollectGarbage(i::NEW_SPACE);
619 5 : CcTest::CollectGarbage(i::NEW_SPACE);
620 :
621 5 : uint16_t* two_byte_string = AsciiToTwoByteString("s1");
622 : Local<String> local_string =
623 : String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
624 5 : v8::NewStringType::kNormal)
625 5 : .ToLocalChecked();
626 : i::DeleteArray(two_byte_string);
627 :
628 : // We should refuse to externalize new space strings.
629 5 : CHECK(!local_string->CanMakeExternal());
630 : // Trigger GCs so that the newly allocated string moves to old gen.
631 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
632 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
633 : // Old space strings should be accepted.
634 10 : CHECK(local_string->CanMakeExternal());
635 5 : }
636 :
637 :
638 28342 : TEST(MakingExternalOneByteStringConditions) {
639 5 : LocalContext env;
640 10 : v8::HandleScope scope(env->GetIsolate());
641 :
642 : // Free some space in the new space so that we can check freshness.
643 5 : CcTest::CollectGarbage(i::NEW_SPACE);
644 5 : CcTest::CollectGarbage(i::NEW_SPACE);
645 :
646 5 : Local<String> local_string = v8_str("s1");
647 : // We should refuse to externalize new space strings.
648 5 : CHECK(!local_string->CanMakeExternal());
649 : // Trigger GCs so that the newly allocated string moves to old gen.
650 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
651 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
652 : // Old space strings should be accepted.
653 10 : CHECK(local_string->CanMakeExternal());
654 5 : }
655 :
656 :
657 28342 : TEST(MakingExternalUnalignedOneByteString) {
658 5 : LocalContext env;
659 10 : v8::HandleScope scope(env->GetIsolate());
660 :
661 : CompileRun("function cons(a, b) { return a + b; }"
662 : "function slice(a) { return a.substring(1); }");
663 : // Create a cons string that will land in old pointer space.
664 : Local<String> cons = Local<String>::Cast(CompileRun(
665 : "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
666 : // Create a sliced string that will land in old pointer space.
667 : Local<String> slice = Local<String>::Cast(CompileRun(
668 : "slice('abcdefghijklmnopqrstuvwxyz');"));
669 :
670 : // Trigger GCs so that the newly allocated string moves to old gen.
671 5 : i::heap::SimulateFullSpace(CcTest::heap()->old_space());
672 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
673 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
674 :
675 : // Turn into external string with unaligned resource data.
676 : const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
677 : bool success = cons->MakeExternal(
678 10 : new TestOneByteResource(i::StrDup(c_cons), nullptr, 1));
679 5 : CHECK(success);
680 : const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
681 : success = slice->MakeExternal(
682 10 : new TestOneByteResource(i::StrDup(c_slice), nullptr, 1));
683 5 : CHECK(success);
684 :
685 : // Trigger GCs and force evacuation.
686 5 : CcTest::CollectAllGarbage();
687 : CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask,
688 10 : i::GarbageCollectionReason::kTesting);
689 5 : }
690 :
691 28343 : THREADED_TEST(UsingExternalString) {
692 : i::Factory* factory = CcTest::i_isolate()->factory();
693 : {
694 6 : v8::HandleScope scope(CcTest::isolate());
695 6 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
696 : Local<String> string =
697 : String::NewExternalTwoByte(CcTest::isolate(),
698 12 : new TestResource(two_byte_string))
699 6 : .ToLocalChecked();
700 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
701 : // Trigger GCs so that the newly allocated string moves to old gen.
702 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
703 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
704 : i::Handle<i::String> isymbol =
705 6 : factory->InternalizeString(istring);
706 12 : CHECK(isymbol->IsInternalizedString());
707 : }
708 6 : CcTest::CollectAllGarbage();
709 6 : CcTest::CollectAllGarbage();
710 6 : }
711 :
712 :
713 28343 : THREADED_TEST(UsingExternalOneByteString) {
714 : i::Factory* factory = CcTest::i_isolate()->factory();
715 : {
716 6 : v8::HandleScope scope(CcTest::isolate());
717 : const char* one_byte_string = "test string";
718 : Local<String> string =
719 : String::NewExternalOneByte(
720 : CcTest::isolate(),
721 12 : new TestOneByteResource(i::StrDup(one_byte_string)))
722 6 : .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 6 : class RandomLengthResource : public v8::String::ExternalStringResource {
737 : public:
738 6 : explicit RandomLengthResource(int length) : length_(length) {}
739 6 : const uint16_t* data() const override { return string_; }
740 6 : size_t length() const override { return length_; }
741 :
742 : private:
743 : uint16_t string_[10];
744 : int length_;
745 : };
746 :
747 :
748 16 : class RandomLengthOneByteResource
749 : : public v8::String::ExternalOneByteStringResource {
750 : public:
751 11 : explicit RandomLengthOneByteResource(int length) : length_(length) {}
752 16 : const char* data() const override { return string_; }
753 26 : size_t length() const override { return length_; }
754 :
755 : private:
756 : char string_[10];
757 : int length_;
758 : };
759 :
760 :
761 28343 : THREADED_TEST(NewExternalForVeryLongString) {
762 6 : auto isolate = CcTest::isolate();
763 : {
764 6 : v8::HandleScope scope(isolate);
765 12 : v8::TryCatch try_catch(isolate);
766 : RandomLengthOneByteResource r(1 << 30);
767 : v8::MaybeLocal<v8::String> maybe_str =
768 6 : v8::String::NewExternalOneByte(isolate, &r);
769 6 : CHECK(maybe_str.IsEmpty());
770 12 : CHECK(!try_catch.HasCaught());
771 : }
772 :
773 : {
774 6 : v8::HandleScope scope(isolate);
775 12 : v8::TryCatch try_catch(isolate);
776 : RandomLengthResource r(1 << 30);
777 : v8::MaybeLocal<v8::String> maybe_str =
778 6 : v8::String::NewExternalTwoByte(isolate, &r);
779 6 : CHECK(maybe_str.IsEmpty());
780 12 : CHECK(!try_catch.HasCaught());
781 : }
782 6 : }
783 :
784 28342 : TEST(ScavengeExternalString) {
785 : ManualGCScope manual_gc_scope;
786 5 : i::FLAG_stress_compaction = false;
787 5 : i::FLAG_gc_global = false;
788 5 : int dispose_count = 0;
789 : bool in_new_space = false;
790 : {
791 5 : v8::HandleScope scope(CcTest::isolate());
792 5 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
793 : Local<String> string =
794 : String::NewExternalTwoByte(
795 : CcTest::isolate(),
796 10 : new TestResource(two_byte_string, &dispose_count))
797 5 : .ToLocalChecked();
798 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
799 5 : CcTest::CollectGarbage(i::NEW_SPACE);
800 : in_new_space = i::Heap::InNewSpace(*istring);
801 10 : CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
802 5 : CHECK_EQ(0, dispose_count);
803 : }
804 5 : CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
805 5 : CHECK_EQ(1, dispose_count);
806 5 : }
807 :
808 28342 : TEST(ScavengeExternalOneByteString) {
809 : ManualGCScope manual_gc_scope;
810 5 : i::FLAG_stress_compaction = false;
811 5 : i::FLAG_gc_global = false;
812 5 : int dispose_count = 0;
813 : bool in_new_space = false;
814 : {
815 5 : v8::HandleScope scope(CcTest::isolate());
816 : const char* one_byte_string = "test string";
817 : Local<String> string =
818 : String::NewExternalOneByte(
819 : CcTest::isolate(),
820 10 : new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
821 5 : .ToLocalChecked();
822 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
823 5 : CcTest::CollectGarbage(i::NEW_SPACE);
824 : in_new_space = i::Heap::InNewSpace(*istring);
825 10 : CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
826 5 : CHECK_EQ(0, dispose_count);
827 : }
828 5 : CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
829 5 : CHECK_EQ(1, dispose_count);
830 5 : }
831 :
832 :
833 10 : class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
834 : public:
835 : // Only used by non-threaded tests, so it can use static fields.
836 : static int dispose_calls;
837 : static int dispose_count;
838 :
839 : TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
840 10 : : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
841 :
842 10 : void Dispose() override {
843 10 : ++dispose_calls;
844 10 : if (dispose_) delete this;
845 10 : }
846 : private:
847 : bool dispose_;
848 : };
849 :
850 :
851 : int TestOneByteResourceWithDisposeControl::dispose_count = 0;
852 : int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
853 :
854 :
855 28342 : TEST(ExternalStringWithDisposeHandling) {
856 : const char* c_source = "1 + 2 * 3";
857 :
858 : // Use a stack allocated external string resource allocated object.
859 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
860 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
861 5 : TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
862 : {
863 5 : LocalContext env;
864 10 : v8::HandleScope scope(env->GetIsolate());
865 : Local<String> source =
866 5 : String::NewExternalOneByte(env->GetIsolate(), &res_stack)
867 10 : .ToLocalChecked();
868 5 : Local<Script> script = v8_compile(source);
869 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
870 5 : CHECK(value->IsNumber());
871 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
872 5 : CcTest::CollectAllAvailableGarbage();
873 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
874 : }
875 5 : CcTest::i_isolate()->compilation_cache()->Clear();
876 5 : CcTest::CollectAllAvailableGarbage();
877 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
878 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
879 :
880 : // Use a heap allocated external string resource allocated object.
881 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
882 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
883 : TestOneByteResource* res_heap =
884 5 : new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
885 : {
886 5 : LocalContext env;
887 10 : v8::HandleScope scope(env->GetIsolate());
888 : Local<String> source =
889 5 : String::NewExternalOneByte(env->GetIsolate(), res_heap)
890 10 : .ToLocalChecked();
891 5 : Local<Script> script = v8_compile(source);
892 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
893 5 : CHECK(value->IsNumber());
894 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
895 5 : CcTest::CollectAllAvailableGarbage();
896 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
897 : }
898 5 : CcTest::i_isolate()->compilation_cache()->Clear();
899 5 : CcTest::CollectAllAvailableGarbage();
900 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
901 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
902 5 : }
903 :
904 :
905 28343 : THREADED_TEST(StringConcat) {
906 : {
907 6 : LocalContext env;
908 6 : v8::Isolate* isolate = env->GetIsolate();
909 12 : v8::HandleScope scope(isolate);
910 : const char* one_byte_string_1 = "function a_times_t";
911 : const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
912 : const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
913 : const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
914 : const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
915 : const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
916 : const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
917 6 : Local<String> left = v8_str(one_byte_string_1);
918 :
919 6 : uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
920 : Local<String> right =
921 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
922 6 : v8::NewStringType::kNormal)
923 12 : .ToLocalChecked();
924 : i::DeleteArray(two_byte_source);
925 :
926 6 : Local<String> source = String::Concat(isolate, left, right);
927 : right = String::NewExternalOneByte(
928 : env->GetIsolate(),
929 12 : new TestOneByteResource(i::StrDup(one_byte_extern_1)))
930 12 : .ToLocalChecked();
931 6 : source = String::Concat(isolate, source, right);
932 : right = String::NewExternalTwoByte(
933 : env->GetIsolate(),
934 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
935 12 : .ToLocalChecked();
936 6 : source = String::Concat(isolate, source, right);
937 6 : right = v8_str(one_byte_string_2);
938 6 : source = String::Concat(isolate, source, right);
939 :
940 6 : two_byte_source = AsciiToTwoByteString(two_byte_string_2);
941 : right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
942 6 : v8::NewStringType::kNormal)
943 12 : .ToLocalChecked();
944 : i::DeleteArray(two_byte_source);
945 :
946 6 : source = String::Concat(isolate, source, right);
947 : right = String::NewExternalTwoByte(
948 : env->GetIsolate(),
949 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
950 12 : .ToLocalChecked();
951 6 : source = String::Concat(isolate, source, right);
952 6 : Local<Script> script = v8_compile(source);
953 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
954 6 : CHECK(value->IsNumber());
955 18 : CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
956 : }
957 6 : CcTest::i_isolate()->compilation_cache()->Clear();
958 6 : CcTest::CollectAllGarbage();
959 6 : CcTest::CollectAllGarbage();
960 6 : }
961 :
962 :
963 28343 : THREADED_TEST(GlobalProperties) {
964 6 : LocalContext env;
965 12 : v8::HandleScope scope(env->GetIsolate());
966 6 : v8::Local<v8::Object> global = env->Global();
967 18 : CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
968 18 : Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
969 18 : CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
970 6 : }
971 :
972 :
973 1980 : static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
974 : i::Address callback) {
975 660 : ApiTestFuzzer::Fuzz();
976 660 : CheckReturnValue(info, callback);
977 660 : info.GetReturnValue().Set(v8_str("bad value"));
978 660 : info.GetReturnValue().Set(v8_num(102));
979 660 : }
980 :
981 :
982 330 : static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
983 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
984 : }
985 :
986 :
987 330 : static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
988 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
989 : }
990 :
991 22 : static void construct_callback(
992 154 : const v8::FunctionCallbackInfo<Value>& info) {
993 22 : ApiTestFuzzer::Fuzz();
994 22 : CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
995 88 : CHECK(
996 : info.This()
997 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
998 : .FromJust());
999 88 : CHECK(
1000 : info.This()
1001 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
1002 : .FromJust());
1003 22 : info.GetReturnValue().Set(v8_str("bad value"));
1004 : info.GetReturnValue().Set(info.This());
1005 22 : }
1006 :
1007 :
1008 330 : static void Return239Callback(
1009 : Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1010 330 : ApiTestFuzzer::Fuzz();
1011 330 : CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1012 330 : info.GetReturnValue().Set(v8_str("bad value"));
1013 330 : info.GetReturnValue().Set(v8_num(239));
1014 330 : }
1015 :
1016 :
1017 : template<typename Handler>
1018 11 : static void TestFunctionTemplateInitializer(Handler handler,
1019 : Handler handler_2) {
1020 : // Test constructor calls.
1021 : {
1022 11 : LocalContext env;
1023 11 : v8::Isolate* isolate = env->GetIsolate();
1024 22 : v8::HandleScope scope(isolate);
1025 :
1026 : Local<v8::FunctionTemplate> fun_templ =
1027 11 : v8::FunctionTemplate::New(isolate, handler);
1028 22 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1029 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1030 11 : Local<Script> script = v8_compile("obj()");
1031 341 : for (int i = 0; i < 30; i++) {
1032 330 : CHECK_EQ(102, v8_run_int32value(script));
1033 11 : }
1034 : }
1035 : // Use SetCallHandler to initialize a function template, should work like
1036 : // the previous one.
1037 : {
1038 11 : LocalContext env;
1039 11 : v8::Isolate* isolate = env->GetIsolate();
1040 22 : v8::HandleScope scope(isolate);
1041 :
1042 11 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1043 11 : fun_templ->SetCallHandler(handler_2);
1044 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1045 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1046 11 : Local<Script> script = v8_compile("obj()");
1047 341 : for (int i = 0; i < 30; i++) {
1048 330 : CHECK_EQ(102, v8_run_int32value(script));
1049 11 : }
1050 : }
1051 11 : }
1052 :
1053 :
1054 : template<typename Constructor, typename Accessor>
1055 11 : static void TestFunctionTemplateAccessor(Constructor constructor,
1056 : Accessor accessor) {
1057 11 : LocalContext env;
1058 22 : v8::HandleScope scope(env->GetIsolate());
1059 :
1060 : Local<v8::FunctionTemplate> fun_templ =
1061 11 : v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1062 11 : fun_templ->SetClassName(v8_str("funky"));
1063 22 : fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1064 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1065 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1066 : Local<Value> result =
1067 33 : v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1068 33 : CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1069 : CompileRun("var obj_instance = new obj();");
1070 : Local<Script> script;
1071 11 : script = v8_compile("obj_instance.x");
1072 341 : for (int i = 0; i < 30; i++) {
1073 330 : CHECK_EQ(1, v8_run_int32value(script));
1074 : }
1075 11 : script = v8_compile("obj_instance.m");
1076 341 : for (int i = 0; i < 30; i++) {
1077 330 : CHECK_EQ(239, v8_run_int32value(script));
1078 11 : }
1079 11 : }
1080 :
1081 :
1082 56690 : THREADED_PROFILED_TEST(FunctionTemplate) {
1083 11 : TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1084 11 : TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1085 11 : }
1086 :
1087 18 : static void FunctionCallbackForProxyTest(
1088 36 : const v8::FunctionCallbackInfo<Value>& info) {
1089 : info.GetReturnValue().Set(info.This());
1090 18 : }
1091 :
1092 28343 : THREADED_TEST(FunctionTemplateWithProxy) {
1093 6 : LocalContext env;
1094 6 : v8::Isolate* isolate = env->GetIsolate();
1095 12 : v8::HandleScope scope(isolate);
1096 :
1097 : v8::Local<v8::FunctionTemplate> function_template =
1098 6 : v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
1099 : v8::Local<v8::Function> function =
1100 12 : function_template->GetFunction(env.local()).ToLocalChecked();
1101 30 : CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
1102 : v8::Local<v8::Value> proxy =
1103 : CompileRun("var proxy = new Proxy({}, {}); proxy");
1104 6 : CHECK(proxy->IsProxy());
1105 :
1106 : v8::Local<v8::Value> result = CompileRun("f(proxy)");
1107 18 : CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());
1108 :
1109 : result = CompileRun("f.call(proxy)");
1110 12 : CHECK(result->Equals(env.local(), proxy).FromJust());
1111 :
1112 : result = CompileRun("Reflect.apply(f, proxy, [1])");
1113 18 : CHECK(result->Equals(env.local(), proxy).FromJust());
1114 6 : }
1115 :
1116 1980 : static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1117 660 : ApiTestFuzzer::Fuzz();
1118 660 : CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1119 660 : info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1120 660 : }
1121 :
1122 :
1123 : template<typename Callback>
1124 11 : static void TestSimpleCallback(Callback callback) {
1125 11 : LocalContext env;
1126 11 : v8::Isolate* isolate = env->GetIsolate();
1127 22 : v8::HandleScope scope(isolate);
1128 :
1129 : v8::Local<v8::ObjectTemplate> object_template =
1130 11 : v8::ObjectTemplate::New(isolate);
1131 22 : object_template->Set(isolate, "callback",
1132 : v8::FunctionTemplate::New(isolate, callback));
1133 : v8::Local<v8::Object> object =
1134 11 : object_template->NewInstance(env.local()).ToLocalChecked();
1135 55 : CHECK((*env)
1136 : ->Global()
1137 : ->Set(env.local(), v8_str("callback_object"), object)
1138 : .FromJust());
1139 : v8::Local<v8::Script> script;
1140 11 : script = v8_compile("callback_object.callback(17)");
1141 341 : for (int i = 0; i < 30; i++) {
1142 330 : CHECK_EQ(51424, v8_run_int32value(script));
1143 : }
1144 11 : script = v8_compile("callback_object.callback(17, 24)");
1145 341 : for (int i = 0; i < 30; i++) {
1146 330 : CHECK_EQ(51425, v8_run_int32value(script));
1147 11 : }
1148 11 : }
1149 :
1150 :
1151 56690 : THREADED_PROFILED_TEST(SimpleCallback) {
1152 11 : TestSimpleCallback(SimpleCallback);
1153 11 : }
1154 :
1155 :
1156 : template<typename T>
1157 : void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1158 :
1159 : // constant return values
1160 : static int32_t fast_return_value_int32 = 471;
1161 : static uint32_t fast_return_value_uint32 = 571;
1162 : static const double kFastReturnValueDouble = 2.7;
1163 : // variable return values
1164 : static bool fast_return_value_bool = false;
1165 : enum ReturnValueOddball {
1166 : kNullReturnValue,
1167 : kUndefinedReturnValue,
1168 : kEmptyStringReturnValue
1169 : };
1170 : static ReturnValueOddball fast_return_value_void;
1171 : static bool fast_return_value_object_is_empty = false;
1172 :
1173 : // Helper function to avoid compiler error: insufficient contextual information
1174 : // to determine type when applying FUNCTION_ADDR to a template function.
1175 : static i::Address address_of(v8::FunctionCallback callback) {
1176 396 : return FUNCTION_ADDR(callback);
1177 : }
1178 :
1179 : template<>
1180 165 : void FastReturnValueCallback<int32_t>(
1181 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1182 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1183 165 : info.GetReturnValue().Set(fast_return_value_int32);
1184 165 : }
1185 :
1186 : template<>
1187 165 : void FastReturnValueCallback<uint32_t>(
1188 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1189 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1190 165 : info.GetReturnValue().Set(fast_return_value_uint32);
1191 165 : }
1192 :
1193 : template<>
1194 11 : void FastReturnValueCallback<double>(
1195 11 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1196 11 : CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1197 : info.GetReturnValue().Set(kFastReturnValueDouble);
1198 11 : }
1199 :
1200 : template<>
1201 22 : void FastReturnValueCallback<bool>(
1202 22 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1203 22 : CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1204 22 : info.GetReturnValue().Set(fast_return_value_bool);
1205 22 : }
1206 :
1207 : template<>
1208 33 : void FastReturnValueCallback<void>(
1209 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1210 33 : CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1211 33 : switch (fast_return_value_void) {
1212 : case kNullReturnValue:
1213 : info.GetReturnValue().SetNull();
1214 11 : break;
1215 : case kUndefinedReturnValue:
1216 : info.GetReturnValue().SetUndefined();
1217 11 : break;
1218 : case kEmptyStringReturnValue:
1219 : info.GetReturnValue().SetEmptyString();
1220 11 : break;
1221 : }
1222 33 : }
1223 :
1224 : template<>
1225 22 : void FastReturnValueCallback<Object>(
1226 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1227 : v8::Local<v8::Object> object;
1228 22 : if (!fast_return_value_object_is_empty) {
1229 11 : object = Object::New(info.GetIsolate());
1230 : }
1231 : info.GetReturnValue().Set(object);
1232 22 : }
1233 :
1234 : template <typename T>
1235 418 : Local<Value> TestFastReturnValues() {
1236 418 : LocalContext env;
1237 418 : v8::Isolate* isolate = env->GetIsolate();
1238 418 : v8::EscapableHandleScope scope(isolate);
1239 : v8::Local<v8::ObjectTemplate> object_template =
1240 418 : v8::ObjectTemplate::New(isolate);
1241 : v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1242 : object_template->Set(isolate, "callback",
1243 836 : v8::FunctionTemplate::New(isolate, callback));
1244 : v8::Local<v8::Object> object =
1245 418 : object_template->NewInstance(env.local()).ToLocalChecked();
1246 2090 : CHECK((*env)
1247 : ->Global()
1248 : ->Set(env.local(), v8_str("callback_object"), object)
1249 : .FromJust());
1250 418 : return scope.Escape(CompileRun("callback_object.callback()"));
1251 : }
1252 :
1253 :
1254 56690 : THREADED_PROFILED_TEST(FastReturnValues) {
1255 11 : LocalContext env;
1256 11 : v8::Isolate* isolate = env->GetIsolate();
1257 22 : v8::HandleScope scope(isolate);
1258 : v8::Local<v8::Value> value;
1259 : // check int32_t and uint32_t
1260 : int32_t int_values[] = {
1261 : 0, 234, -723,
1262 : i::Smi::kMinValue, i::Smi::kMaxValue
1263 11 : };
1264 66 : for (size_t i = 0; i < arraysize(int_values); i++) {
1265 165 : for (int modifier = -1; modifier <= 1; modifier++) {
1266 165 : int int_value = v8::base::AddWithWraparound(int_values[i], modifier);
1267 : // check int32_t
1268 165 : fast_return_value_int32 = int_value;
1269 165 : value = TestFastReturnValues<int32_t>();
1270 165 : CHECK(value->IsInt32());
1271 330 : CHECK_EQ(fast_return_value_int32,
1272 : value->Int32Value(env.local()).FromJust());
1273 : // check uint32_t
1274 165 : fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1275 165 : value = TestFastReturnValues<uint32_t>();
1276 165 : CHECK(value->IsUint32());
1277 330 : CHECK_EQ(fast_return_value_uint32,
1278 : value->Uint32Value(env.local()).FromJust());
1279 : }
1280 : }
1281 : // check double
1282 11 : value = TestFastReturnValues<double>();
1283 11 : CHECK(value->IsNumber());
1284 22 : CHECK_EQ(kFastReturnValueDouble,
1285 : value->ToNumber(env.local()).ToLocalChecked()->Value());
1286 : // check bool values
1287 22 : for (int i = 0; i < 2; i++) {
1288 22 : fast_return_value_bool = i == 0;
1289 22 : value = TestFastReturnValues<bool>();
1290 22 : CHECK(value->IsBoolean());
1291 22 : CHECK_EQ(fast_return_value_bool, value->BooleanValue(isolate));
1292 : }
1293 : // check oddballs
1294 : ReturnValueOddball oddballs[] = {
1295 : kNullReturnValue,
1296 : kUndefinedReturnValue,
1297 : kEmptyStringReturnValue
1298 11 : };
1299 44 : for (size_t i = 0; i < arraysize(oddballs); i++) {
1300 33 : fast_return_value_void = oddballs[i];
1301 33 : value = TestFastReturnValues<void>();
1302 33 : switch (fast_return_value_void) {
1303 : case kNullReturnValue:
1304 11 : CHECK(value->IsNull());
1305 : break;
1306 : case kUndefinedReturnValue:
1307 11 : CHECK(value->IsUndefined());
1308 : break;
1309 : case kEmptyStringReturnValue:
1310 11 : CHECK(value->IsString());
1311 11 : CHECK_EQ(0, v8::String::Cast(*value)->Length());
1312 : break;
1313 : }
1314 : }
1315 : // check handles
1316 11 : fast_return_value_object_is_empty = false;
1317 11 : value = TestFastReturnValues<Object>();
1318 11 : CHECK(value->IsObject());
1319 11 : fast_return_value_object_is_empty = true;
1320 11 : value = TestFastReturnValues<Object>();
1321 22 : CHECK(value->IsUndefined());
1322 11 : }
1323 :
1324 :
1325 28343 : THREADED_TEST(FunctionTemplateSetLength) {
1326 6 : LocalContext env;
1327 6 : v8::Isolate* isolate = env->GetIsolate();
1328 12 : v8::HandleScope scope(isolate);
1329 : {
1330 : Local<v8::FunctionTemplate> fun_templ =
1331 : v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1332 6 : Local<v8::Signature>(), 23);
1333 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1334 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1335 6 : Local<Script> script = v8_compile("obj.length");
1336 6 : CHECK_EQ(23, v8_run_int32value(script));
1337 : }
1338 : {
1339 : Local<v8::FunctionTemplate> fun_templ =
1340 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1341 6 : fun_templ->SetLength(22);
1342 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1343 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1344 6 : Local<Script> script = v8_compile("obj.length");
1345 6 : CHECK_EQ(22, v8_run_int32value(script));
1346 : }
1347 : {
1348 : // Without setting length it defaults to 0.
1349 : Local<v8::FunctionTemplate> fun_templ =
1350 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1351 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1352 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1353 6 : Local<Script> script = v8_compile("obj.length");
1354 6 : CHECK_EQ(0, v8_run_int32value(script));
1355 6 : }
1356 6 : }
1357 :
1358 :
1359 : static void* expected_ptr;
1360 16848 : static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1361 8424 : void* ptr = v8::External::Cast(*args.Data())->Value();
1362 8424 : CHECK_EQ(expected_ptr, ptr);
1363 : args.GetReturnValue().Set(true);
1364 8424 : }
1365 :
1366 :
1367 648 : static void TestExternalPointerWrapping() {
1368 648 : LocalContext env;
1369 648 : v8::Isolate* isolate = env->GetIsolate();
1370 1296 : v8::HandleScope scope(isolate);
1371 :
1372 648 : v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1373 :
1374 648 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
1375 4536 : CHECK(obj->Set(env.local(), v8_str("func"),
1376 : v8::FunctionTemplate::New(isolate, callback, data)
1377 : ->GetFunction(env.local())
1378 : .ToLocalChecked())
1379 : .FromJust());
1380 3240 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1381 :
1382 648 : CHECK(CompileRun("function foo() {\n"
1383 : " for (var i = 0; i < 13; i++) obj.func();\n"
1384 : "}\n"
1385 : "foo(), true")
1386 648 : ->BooleanValue(isolate));
1387 648 : }
1388 :
1389 :
1390 28343 : THREADED_TEST(ExternalWrap) {
1391 : // Check heap allocated object.
1392 6 : int* ptr = new int;
1393 6 : expected_ptr = ptr;
1394 6 : TestExternalPointerWrapping();
1395 6 : delete ptr;
1396 :
1397 : // Check stack allocated object.
1398 : int foo;
1399 6 : expected_ptr = &foo;
1400 6 : TestExternalPointerWrapping();
1401 :
1402 : // Check not aligned addresses.
1403 : const int n = 100;
1404 6 : char* s = new char[n];
1405 606 : for (int i = 0; i < n; i++) {
1406 600 : expected_ptr = s + i;
1407 600 : TestExternalPointerWrapping();
1408 : }
1409 :
1410 6 : delete[] s;
1411 :
1412 : // Check several invalid addresses.
1413 6 : expected_ptr = reinterpret_cast<void*>(1);
1414 6 : TestExternalPointerWrapping();
1415 :
1416 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF);
1417 6 : TestExternalPointerWrapping();
1418 :
1419 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEF + 1);
1420 6 : TestExternalPointerWrapping();
1421 :
1422 : #if defined(V8_HOST_ARCH_X64)
1423 : // Check a value with a leading 1 bit in x64 Smi encoding.
1424 6 : expected_ptr = reinterpret_cast<void*>(0x400000000);
1425 6 : TestExternalPointerWrapping();
1426 :
1427 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF);
1428 6 : TestExternalPointerWrapping();
1429 :
1430 6 : expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF + 1);
1431 6 : TestExternalPointerWrapping();
1432 : #endif
1433 6 : }
1434 :
1435 :
1436 28343 : THREADED_TEST(FindInstanceInPrototypeChain) {
1437 6 : LocalContext env;
1438 6 : v8::Isolate* isolate = env->GetIsolate();
1439 12 : v8::HandleScope scope(isolate);
1440 :
1441 6 : Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1442 6 : Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1443 6 : Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1444 6 : derived->Inherit(base);
1445 :
1446 : Local<v8::Function> base_function =
1447 12 : base->GetFunction(env.local()).ToLocalChecked();
1448 : Local<v8::Function> derived_function =
1449 6 : derived->GetFunction(env.local()).ToLocalChecked();
1450 : Local<v8::Function> other_function =
1451 12 : other->GetFunction(env.local()).ToLocalChecked();
1452 :
1453 : Local<v8::Object> base_instance =
1454 6 : base_function->NewInstance(env.local()).ToLocalChecked();
1455 : Local<v8::Object> derived_instance =
1456 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1457 : Local<v8::Object> derived_instance2 =
1458 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1459 : Local<v8::Object> other_instance =
1460 6 : other_function->NewInstance(env.local()).ToLocalChecked();
1461 18 : CHECK(
1462 : derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1463 : .FromJust());
1464 18 : CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1465 : .FromJust());
1466 :
1467 : // base_instance is only an instance of base.
1468 18 : CHECK(base_instance->Equals(env.local(),
1469 : base_instance->FindInstanceInPrototypeChain(base))
1470 : .FromJust());
1471 12 : CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1472 12 : CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1473 :
1474 : // derived_instance is an instance of base and derived.
1475 18 : CHECK(derived_instance->Equals(env.local(),
1476 : derived_instance->FindInstanceInPrototypeChain(
1477 : base))
1478 : .FromJust());
1479 18 : CHECK(derived_instance->Equals(env.local(),
1480 : derived_instance->FindInstanceInPrototypeChain(
1481 : derived))
1482 : .FromJust());
1483 12 : CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1484 :
1485 : // other_instance is an instance of other and its immediate
1486 : // prototype derived_instance2 is an instance of base and derived.
1487 : // Note, derived_instance is an instance of base and derived too,
1488 : // but it comes after derived_instance2 in the prototype chain of
1489 : // other_instance.
1490 18 : CHECK(derived_instance2->Equals(
1491 : env.local(),
1492 : other_instance->FindInstanceInPrototypeChain(base))
1493 : .FromJust());
1494 18 : CHECK(derived_instance2->Equals(env.local(),
1495 : other_instance->FindInstanceInPrototypeChain(
1496 : derived))
1497 : .FromJust());
1498 18 : CHECK(other_instance->Equals(
1499 : env.local(),
1500 : other_instance->FindInstanceInPrototypeChain(other))
1501 6 : .FromJust());
1502 6 : }
1503 :
1504 :
1505 28343 : THREADED_TEST(TinyInteger) {
1506 6 : LocalContext env;
1507 6 : v8::Isolate* isolate = env->GetIsolate();
1508 12 : v8::HandleScope scope(isolate);
1509 :
1510 : int32_t value = 239;
1511 6 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1512 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1513 6 : }
1514 :
1515 :
1516 28343 : THREADED_TEST(BigSmiInteger) {
1517 6 : LocalContext env;
1518 12 : v8::HandleScope scope(env->GetIsolate());
1519 6 : v8::Isolate* isolate = CcTest::isolate();
1520 :
1521 : int32_t value = i::Smi::kMaxValue;
1522 : // We cannot add one to a Smi::kMaxValue without wrapping.
1523 : if (i::SmiValuesAre31Bits()) {
1524 : CHECK(i::Smi::IsValid(value));
1525 : CHECK(!i::Smi::IsValid(value + 1));
1526 :
1527 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1528 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529 6 : }
1530 6 : }
1531 :
1532 :
1533 28343 : THREADED_TEST(BigInteger) {
1534 6 : LocalContext env;
1535 12 : v8::HandleScope scope(env->GetIsolate());
1536 6 : v8::Isolate* isolate = CcTest::isolate();
1537 :
1538 : // We cannot add one to a Smi::kMaxValue without wrapping.
1539 : if (i::SmiValuesAre31Bits()) {
1540 : // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1541 : // The code will not be run in that case, due to the "if" guard.
1542 : int32_t value =
1543 : static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1544 : CHECK_GT(value, i::Smi::kMaxValue);
1545 : CHECK(!i::Smi::IsValid(value));
1546 :
1547 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1548 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1549 6 : }
1550 6 : }
1551 :
1552 :
1553 28343 : THREADED_TEST(TinyUnsignedInteger) {
1554 6 : LocalContext env;
1555 12 : v8::HandleScope scope(env->GetIsolate());
1556 6 : v8::Isolate* isolate = CcTest::isolate();
1557 :
1558 : uint32_t value = 239;
1559 :
1560 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1561 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1562 6 : }
1563 :
1564 :
1565 28343 : THREADED_TEST(BigUnsignedSmiInteger) {
1566 6 : LocalContext env;
1567 12 : v8::HandleScope scope(env->GetIsolate());
1568 6 : v8::Isolate* isolate = CcTest::isolate();
1569 :
1570 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1571 : CHECK(i::Smi::IsValid(value));
1572 : CHECK(!i::Smi::IsValid(value + 1));
1573 :
1574 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576 6 : }
1577 :
1578 :
1579 28343 : THREADED_TEST(BigUnsignedInteger) {
1580 6 : LocalContext env;
1581 12 : v8::HandleScope scope(env->GetIsolate());
1582 6 : v8::Isolate* isolate = CcTest::isolate();
1583 :
1584 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1585 : CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1586 : CHECK(!i::Smi::IsValid(value));
1587 :
1588 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1589 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1590 6 : }
1591 :
1592 :
1593 28343 : THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1594 6 : LocalContext env;
1595 12 : v8::HandleScope scope(env->GetIsolate());
1596 6 : v8::Isolate* isolate = CcTest::isolate();
1597 :
1598 : uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1599 : uint32_t value = INT32_MAX_AS_UINT + 1;
1600 : CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1601 :
1602 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1603 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1604 6 : }
1605 :
1606 :
1607 28343 : THREADED_TEST(IsNativeError) {
1608 6 : LocalContext env;
1609 12 : v8::HandleScope scope(env->GetIsolate());
1610 : v8::Local<Value> syntax_error = CompileRun(
1611 : "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1612 6 : CHECK(syntax_error->IsNativeError());
1613 : v8::Local<Value> not_error = CompileRun("{a:42}");
1614 6 : CHECK(!not_error->IsNativeError());
1615 : v8::Local<Value> not_object = CompileRun("42");
1616 12 : CHECK(!not_object->IsNativeError());
1617 6 : }
1618 :
1619 :
1620 28343 : THREADED_TEST(IsGeneratorFunctionOrObject) {
1621 6 : LocalContext env;
1622 12 : v8::HandleScope scope(env->GetIsolate());
1623 :
1624 : CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1625 : v8::Local<Value> gen = CompileRun("gen");
1626 : v8::Local<Value> genObj = CompileRun("gen()");
1627 : v8::Local<Value> object = CompileRun("{a:42}");
1628 : v8::Local<Value> func = CompileRun("func");
1629 :
1630 6 : CHECK(gen->IsGeneratorFunction());
1631 6 : CHECK(gen->IsFunction());
1632 6 : CHECK(!gen->IsGeneratorObject());
1633 :
1634 6 : CHECK(!genObj->IsGeneratorFunction());
1635 6 : CHECK(!genObj->IsFunction());
1636 6 : CHECK(genObj->IsGeneratorObject());
1637 :
1638 6 : CHECK(!object->IsGeneratorFunction());
1639 6 : CHECK(!object->IsFunction());
1640 6 : CHECK(!object->IsGeneratorObject());
1641 :
1642 6 : CHECK(!func->IsGeneratorFunction());
1643 6 : CHECK(func->IsFunction());
1644 12 : CHECK(!func->IsGeneratorObject());
1645 6 : }
1646 :
1647 28343 : THREADED_TEST(IsAsyncFunction) {
1648 6 : LocalContext env;
1649 6 : v8::Isolate* isolate = env->GetIsolate();
1650 12 : v8::HandleScope scope(isolate);
1651 :
1652 : CompileRun("async function foo() {}");
1653 : v8::Local<Value> foo = CompileRun("foo");
1654 :
1655 6 : CHECK(foo->IsAsyncFunction());
1656 6 : CHECK(foo->IsFunction());
1657 6 : CHECK(!foo->IsGeneratorFunction());
1658 6 : CHECK(!foo->IsGeneratorObject());
1659 :
1660 : CompileRun("function bar() {}");
1661 : v8::Local<Value> bar = CompileRun("bar");
1662 :
1663 6 : CHECK(!bar->IsAsyncFunction());
1664 12 : CHECK(bar->IsFunction());
1665 6 : }
1666 :
1667 28343 : THREADED_TEST(ArgumentsObject) {
1668 6 : LocalContext env;
1669 12 : v8::HandleScope scope(env->GetIsolate());
1670 : v8::Local<Value> arguments_object =
1671 : CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1672 6 : CHECK(arguments_object->IsArgumentsObject());
1673 : v8::Local<Value> array = CompileRun("[1,2,3]");
1674 6 : CHECK(!array->IsArgumentsObject());
1675 : v8::Local<Value> object = CompileRun("{a:42}");
1676 12 : CHECK(!object->IsArgumentsObject());
1677 6 : }
1678 :
1679 :
1680 28343 : THREADED_TEST(IsMapOrSet) {
1681 6 : LocalContext env;
1682 12 : v8::HandleScope scope(env->GetIsolate());
1683 : v8::Local<Value> map = CompileRun("new Map()");
1684 : v8::Local<Value> set = CompileRun("new Set()");
1685 : v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1686 : v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1687 6 : CHECK(map->IsMap());
1688 6 : CHECK(set->IsSet());
1689 6 : CHECK(weak_map->IsWeakMap());
1690 6 : CHECK(weak_set->IsWeakSet());
1691 :
1692 6 : CHECK(!map->IsSet());
1693 6 : CHECK(!map->IsWeakMap());
1694 6 : CHECK(!map->IsWeakSet());
1695 :
1696 6 : CHECK(!set->IsMap());
1697 6 : CHECK(!set->IsWeakMap());
1698 6 : CHECK(!set->IsWeakSet());
1699 :
1700 6 : CHECK(!weak_map->IsMap());
1701 6 : CHECK(!weak_map->IsSet());
1702 6 : CHECK(!weak_map->IsWeakSet());
1703 :
1704 6 : CHECK(!weak_set->IsMap());
1705 6 : CHECK(!weak_set->IsSet());
1706 6 : CHECK(!weak_set->IsWeakMap());
1707 :
1708 : v8::Local<Value> object = CompileRun("{a:42}");
1709 6 : CHECK(!object->IsMap());
1710 6 : CHECK(!object->IsSet());
1711 6 : CHECK(!object->IsWeakMap());
1712 12 : CHECK(!object->IsWeakSet());
1713 6 : }
1714 :
1715 :
1716 28343 : THREADED_TEST(StringObject) {
1717 6 : LocalContext env;
1718 12 : v8::HandleScope scope(env->GetIsolate());
1719 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1720 6 : CHECK(boxed_string->IsStringObject());
1721 : v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1722 6 : CHECK(!unboxed_string->IsStringObject());
1723 : v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1724 6 : CHECK(!boxed_not_string->IsStringObject());
1725 : v8::Local<Value> not_object = CompileRun("0");
1726 6 : CHECK(!not_object->IsStringObject());
1727 : v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1728 6 : CHECK(!as_boxed.IsEmpty());
1729 6 : Local<v8::String> the_string = as_boxed->ValueOf();
1730 6 : CHECK(!the_string.IsEmpty());
1731 6 : ExpectObject("\"test\"", the_string);
1732 : v8::Local<v8::Value> new_boxed_string =
1733 6 : v8::StringObject::New(CcTest::isolate(), the_string);
1734 6 : CHECK(new_boxed_string->IsStringObject());
1735 : as_boxed = new_boxed_string.As<v8::StringObject>();
1736 6 : the_string = as_boxed->ValueOf();
1737 6 : CHECK(!the_string.IsEmpty());
1738 12 : ExpectObject("\"test\"", the_string);
1739 6 : }
1740 :
1741 :
1742 28342 : TEST(StringObjectDelete) {
1743 5 : LocalContext context;
1744 10 : v8::HandleScope scope(context->GetIsolate());
1745 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1746 5 : CHECK(boxed_string->IsStringObject());
1747 : v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1748 10 : CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1749 15 : CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1750 5 : }
1751 :
1752 :
1753 28343 : THREADED_TEST(NumberObject) {
1754 6 : LocalContext env;
1755 12 : v8::HandleScope scope(env->GetIsolate());
1756 : v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1757 6 : CHECK(boxed_number->IsNumberObject());
1758 : v8::Local<Value> unboxed_number = CompileRun("42");
1759 6 : CHECK(!unboxed_number->IsNumberObject());
1760 : v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1761 6 : CHECK(!boxed_not_number->IsNumberObject());
1762 : v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1763 6 : CHECK(!as_boxed.IsEmpty());
1764 6 : double the_number = as_boxed->ValueOf();
1765 6 : CHECK_EQ(42.0, the_number);
1766 : v8::Local<v8::Value> new_boxed_number =
1767 6 : v8::NumberObject::New(env->GetIsolate(), 43);
1768 6 : CHECK(new_boxed_number->IsNumberObject());
1769 : as_boxed = new_boxed_number.As<v8::NumberObject>();
1770 6 : the_number = as_boxed->ValueOf();
1771 12 : CHECK_EQ(43.0, the_number);
1772 6 : }
1773 :
1774 28343 : THREADED_TEST(BigIntObject) {
1775 6 : LocalContext env;
1776 6 : v8::Isolate* isolate = env->GetIsolate();
1777 12 : v8::HandleScope scope(isolate);
1778 6 : v8::Local<v8::Context> context(env.local());
1779 : v8::Local<Value> boxed_bigint = CompileRun("new Object(42n)");
1780 6 : CHECK(!boxed_bigint->IsBigInt());
1781 6 : CHECK(boxed_bigint->IsBigIntObject());
1782 : v8::Local<Value> unboxed_bigint = CompileRun("42n");
1783 6 : CHECK(unboxed_bigint->IsBigInt());
1784 6 : CHECK(!unboxed_bigint->IsBigIntObject());
1785 : v8::Local<v8::BigIntObject> as_boxed = boxed_bigint.As<v8::BigIntObject>();
1786 6 : CHECK(!as_boxed.IsEmpty());
1787 6 : v8::Local<v8::BigInt> unpacked = as_boxed->ValueOf();
1788 6 : CHECK(!unpacked.IsEmpty());
1789 6 : v8::Local<v8::Value> new_boxed_bigint = v8::BigIntObject::New(isolate, 43);
1790 6 : CHECK(new_boxed_bigint->IsBigIntObject());
1791 6 : v8::Local<v8::Value> new_unboxed_bigint = v8::BigInt::New(isolate, 44);
1792 6 : CHECK(new_unboxed_bigint->IsBigInt());
1793 :
1794 : // Test functionality inherited from v8::Value.
1795 6 : CHECK(unboxed_bigint->BooleanValue(isolate));
1796 : v8::Local<v8::String> string =
1797 6 : unboxed_bigint->ToString(context).ToLocalChecked();
1798 6 : CHECK_EQ(0, strcmp("42", *v8::String::Utf8Value(isolate, string)));
1799 :
1800 : // IntegerValue throws.
1801 18 : CHECK(unboxed_bigint->IntegerValue(context).IsNothing());
1802 6 : }
1803 :
1804 28343 : THREADED_TEST(BooleanObject) {
1805 6 : LocalContext env;
1806 12 : v8::HandleScope scope(env->GetIsolate());
1807 : v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1808 6 : CHECK(boxed_boolean->IsBooleanObject());
1809 : v8::Local<Value> unboxed_boolean = CompileRun("true");
1810 6 : CHECK(!unboxed_boolean->IsBooleanObject());
1811 : v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1812 6 : CHECK(!boxed_not_boolean->IsBooleanObject());
1813 : v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1814 6 : CHECK(!as_boxed.IsEmpty());
1815 6 : bool the_boolean = as_boxed->ValueOf();
1816 6 : CHECK(the_boolean);
1817 : v8::Local<v8::Value> boxed_true =
1818 6 : v8::BooleanObject::New(env->GetIsolate(), true);
1819 : v8::Local<v8::Value> boxed_false =
1820 6 : v8::BooleanObject::New(env->GetIsolate(), false);
1821 6 : CHECK(boxed_true->IsBooleanObject());
1822 6 : CHECK(boxed_false->IsBooleanObject());
1823 : as_boxed = boxed_true.As<v8::BooleanObject>();
1824 6 : CHECK(as_boxed->ValueOf());
1825 : as_boxed = boxed_false.As<v8::BooleanObject>();
1826 12 : CHECK(!as_boxed->ValueOf());
1827 6 : }
1828 :
1829 :
1830 28343 : THREADED_TEST(PrimitiveAndWrappedBooleans) {
1831 6 : LocalContext env;
1832 6 : v8::Isolate* isolate = env->GetIsolate();
1833 12 : v8::HandleScope scope(isolate);
1834 :
1835 : Local<Value> primitive_false = Boolean::New(isolate, false);
1836 6 : CHECK(primitive_false->IsBoolean());
1837 6 : CHECK(!primitive_false->IsBooleanObject());
1838 6 : CHECK(!primitive_false->BooleanValue(isolate));
1839 6 : CHECK(!primitive_false->IsTrue());
1840 6 : CHECK(primitive_false->IsFalse());
1841 :
1842 6 : Local<Value> false_value = BooleanObject::New(isolate, false);
1843 6 : CHECK(!false_value->IsBoolean());
1844 6 : CHECK(false_value->IsBooleanObject());
1845 6 : CHECK(false_value->BooleanValue(isolate));
1846 6 : CHECK(!false_value->IsTrue());
1847 6 : CHECK(!false_value->IsFalse());
1848 :
1849 : Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1850 6 : CHECK(!false_boolean_object->IsBoolean());
1851 6 : CHECK(false_boolean_object->IsBooleanObject());
1852 6 : CHECK(false_boolean_object->BooleanValue(isolate));
1853 6 : CHECK(!false_boolean_object->ValueOf());
1854 6 : CHECK(!false_boolean_object->IsTrue());
1855 6 : CHECK(!false_boolean_object->IsFalse());
1856 :
1857 : Local<Value> primitive_true = Boolean::New(isolate, true);
1858 6 : CHECK(primitive_true->IsBoolean());
1859 6 : CHECK(!primitive_true->IsBooleanObject());
1860 6 : CHECK(primitive_true->BooleanValue(isolate));
1861 6 : CHECK(primitive_true->IsTrue());
1862 6 : CHECK(!primitive_true->IsFalse());
1863 :
1864 6 : Local<Value> true_value = BooleanObject::New(isolate, true);
1865 6 : CHECK(!true_value->IsBoolean());
1866 6 : CHECK(true_value->IsBooleanObject());
1867 6 : CHECK(true_value->BooleanValue(isolate));
1868 6 : CHECK(!true_value->IsTrue());
1869 6 : CHECK(!true_value->IsFalse());
1870 :
1871 : Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1872 6 : CHECK(!true_boolean_object->IsBoolean());
1873 6 : CHECK(true_boolean_object->IsBooleanObject());
1874 6 : CHECK(true_boolean_object->BooleanValue(isolate));
1875 6 : CHECK(true_boolean_object->ValueOf());
1876 6 : CHECK(!true_boolean_object->IsTrue());
1877 12 : CHECK(!true_boolean_object->IsFalse());
1878 6 : }
1879 :
1880 :
1881 28343 : THREADED_TEST(Number) {
1882 6 : LocalContext env;
1883 12 : v8::HandleScope scope(env->GetIsolate());
1884 : double PI = 3.1415926;
1885 6 : Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1886 24 : CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1887 6 : }
1888 :
1889 :
1890 28343 : THREADED_TEST(ToNumber) {
1891 6 : LocalContext env;
1892 6 : v8::Isolate* isolate = CcTest::isolate();
1893 12 : v8::HandleScope scope(isolate);
1894 6 : Local<String> str = v8_str("3.1415926");
1895 18 : CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1896 : v8::Local<v8::Boolean> t = v8::True(isolate);
1897 12 : CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1898 : v8::Local<v8::Boolean> f = v8::False(isolate);
1899 18 : CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1900 6 : }
1901 :
1902 :
1903 28343 : THREADED_TEST(Date) {
1904 6 : LocalContext env;
1905 12 : v8::HandleScope scope(env->GetIsolate());
1906 : double PI = 3.1415926;
1907 6 : Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1908 12 : CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1909 24 : CHECK(date.As<v8::Date>()
1910 : ->Set(env.local(), v8_str("property"),
1911 : v8::Integer::New(env->GetIsolate(), 42))
1912 : .FromJust());
1913 24 : CHECK_EQ(42, date.As<v8::Date>()
1914 : ->Get(env.local(), v8_str("property"))
1915 : .ToLocalChecked()
1916 : ->Int32Value(env.local())
1917 6 : .FromJust());
1918 6 : }
1919 :
1920 :
1921 28343 : THREADED_TEST(Boolean) {
1922 6 : LocalContext env;
1923 6 : v8::Isolate* isolate = env->GetIsolate();
1924 12 : v8::HandleScope scope(isolate);
1925 : v8::Local<v8::Boolean> t = v8::True(isolate);
1926 6 : CHECK(t->Value());
1927 : v8::Local<v8::Boolean> f = v8::False(isolate);
1928 6 : CHECK(!f->Value());
1929 : v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1930 6 : CHECK(!u->BooleanValue(isolate));
1931 : v8::Local<v8::Primitive> n = v8::Null(isolate);
1932 6 : CHECK(!n->BooleanValue(isolate));
1933 6 : v8::Local<String> str1 = v8_str("");
1934 6 : CHECK(!str1->BooleanValue(isolate));
1935 6 : v8::Local<String> str2 = v8_str("x");
1936 6 : CHECK(str2->BooleanValue(isolate));
1937 12 : CHECK(!v8::Number::New(isolate, 0)->BooleanValue(isolate));
1938 12 : CHECK(v8::Number::New(isolate, -1)->BooleanValue(isolate));
1939 12 : CHECK(v8::Number::New(isolate, 1)->BooleanValue(isolate));
1940 12 : CHECK(v8::Number::New(isolate, 42)->BooleanValue(isolate));
1941 18 : CHECK(!v8_compile("NaN")
1942 : ->Run(env.local())
1943 : .ToLocalChecked()
1944 6 : ->BooleanValue(isolate));
1945 6 : }
1946 :
1947 :
1948 12 : static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1949 6 : ApiTestFuzzer::Fuzz();
1950 6 : args.GetReturnValue().Set(v8_num(13.4));
1951 6 : }
1952 :
1953 :
1954 6 : static void GetM(Local<String> name,
1955 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1956 6 : ApiTestFuzzer::Fuzz();
1957 6 : info.GetReturnValue().Set(v8_num(876));
1958 6 : }
1959 :
1960 :
1961 28343 : THREADED_TEST(GlobalPrototype) {
1962 6 : v8::Isolate* isolate = CcTest::isolate();
1963 6 : v8::HandleScope scope(isolate);
1964 : v8::Local<v8::FunctionTemplate> func_templ =
1965 6 : v8::FunctionTemplate::New(isolate);
1966 12 : func_templ->PrototypeTemplate()->Set(
1967 12 : isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1968 6 : v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1969 6 : templ->Set(isolate, "x", v8_num(200));
1970 6 : templ->SetAccessor(v8_str("m"), GetM);
1971 12 : LocalContext env(nullptr, templ);
1972 : v8::Local<Script> script(v8_compile("dummy()"));
1973 6 : v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1974 12 : CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
1975 6 : CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
1976 12 : CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
1977 6 : }
1978 :
1979 :
1980 28343 : THREADED_TEST(ObjectTemplate) {
1981 6 : LocalContext env;
1982 6 : v8::Isolate* isolate = CcTest::isolate();
1983 12 : v8::HandleScope scope(isolate);
1984 : Local<v8::FunctionTemplate> acc =
1985 6 : v8::FunctionTemplate::New(isolate, Returns42);
1986 42 : CHECK(env->Global()
1987 : ->Set(env.local(), v8_str("acc"),
1988 : acc->GetFunction(env.local()).ToLocalChecked())
1989 : .FromJust());
1990 :
1991 6 : Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1992 6 : v8::Local<v8::String> class_name = v8_str("the_class_name");
1993 6 : fun->SetClassName(class_name);
1994 6 : Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
1995 6 : templ1->Set(isolate, "x", v8_num(10));
1996 6 : templ1->Set(isolate, "y", v8_num(13));
1997 12 : templ1->Set(v8_str("foo"), acc);
1998 : Local<v8::Object> instance1 =
1999 6 : templ1->NewInstance(env.local()).ToLocalChecked();
2000 12 : CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
2001 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
2002 6 : CHECK(CompileRun("(p.x == 10)")->BooleanValue(isolate));
2003 6 : CHECK(CompileRun("(p.y == 13)")->BooleanValue(isolate));
2004 6 : CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(isolate));
2005 6 : CHECK(CompileRun("(p.foo == acc)")->BooleanValue(isolate));
2006 : // Ensure that foo become a data field.
2007 : CompileRun("p.foo = function() {}");
2008 6 : Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
2009 12 : fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
2010 6 : Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
2011 6 : templ2->Set(isolate, "a", v8_num(12));
2012 : templ2->Set(isolate, "b", templ1);
2013 12 : templ2->Set(v8_str("bar"), acc);
2014 12 : templ2->SetAccessorProperty(v8_str("acc"), acc);
2015 : Local<v8::Object> instance2 =
2016 6 : templ2->NewInstance(env.local()).ToLocalChecked();
2017 30 : CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
2018 6 : CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(isolate));
2019 6 : CHECK(CompileRun("(q.a == 12)")->BooleanValue(isolate));
2020 6 : CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(isolate));
2021 6 : CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(isolate));
2022 6 : CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(isolate));
2023 6 : CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(isolate));
2024 6 : CHECK(CompileRun("(q.b !== p)")->BooleanValue(isolate));
2025 6 : CHECK(CompileRun("(q.acc == 42)")->BooleanValue(isolate));
2026 6 : CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(isolate));
2027 6 : CHECK(CompileRun("(q.bar == acc)")->BooleanValue(isolate));
2028 :
2029 6 : instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
2030 30 : CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
2031 6 : CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(isolate));
2032 6 : CHECK(CompileRun("(q2.a == 12)")->BooleanValue(isolate));
2033 6 : CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(isolate));
2034 6 : CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(isolate));
2035 6 : CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(isolate));
2036 6 : CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(isolate));
2037 6 : CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(isolate));
2038 6 : CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(isolate));
2039 6 : CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(isolate));
2040 :
2041 6 : CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(isolate));
2042 6 : CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")->BooleanValue(isolate));
2043 6 : CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
2044 : "(desc1.get === acc)")
2045 : ->BooleanValue(isolate));
2046 6 : CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
2047 : "(desc2.get === acc)")
2048 6 : ->BooleanValue(isolate));
2049 6 : }
2050 :
2051 28343 : THREADED_TEST(IntegerValue) {
2052 6 : LocalContext env;
2053 6 : v8::Isolate* isolate = CcTest::isolate();
2054 12 : v8::HandleScope scope(isolate);
2055 :
2056 24 : CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
2057 6 : }
2058 :
2059 126 : static void GetNirk(Local<String> name,
2060 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2061 126 : ApiTestFuzzer::Fuzz();
2062 126 : info.GetReturnValue().Set(v8_num(900));
2063 126 : }
2064 :
2065 126 : static void GetRino(Local<String> name,
2066 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2067 126 : ApiTestFuzzer::Fuzz();
2068 126 : info.GetReturnValue().Set(v8_num(560));
2069 126 : }
2070 :
2071 : enum ObjectInstantiationMode {
2072 : // Create object using ObjectTemplate::NewInstance.
2073 : ObjectTemplate_NewInstance,
2074 : // Create object using FunctionTemplate::NewInstance on constructor.
2075 : Constructor_GetFunction_NewInstance,
2076 : // Create object using new operator on constructor.
2077 : Constructor_GetFunction_New
2078 : };
2079 :
2080 : // Test object instance creation using a function template with an instance
2081 : // template inherited from another function template with accessors and data
2082 : // properties in prototype template.
2083 18 : static void TestObjectTemplateInheritedWithPrototype(
2084 : ObjectInstantiationMode mode) {
2085 18 : LocalContext env;
2086 18 : v8::Isolate* isolate = CcTest::isolate();
2087 36 : v8::HandleScope scope(isolate);
2088 :
2089 18 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2090 18 : fun_A->SetClassName(v8_str("A"));
2091 18 : v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
2092 18 : prototype_templ->Set(isolate, "a", v8_num(113));
2093 18 : prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2094 18 : prototype_templ->Set(isolate, "b", v8_num(153));
2095 :
2096 18 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2097 18 : v8::Local<v8::String> class_name = v8_str("B");
2098 18 : fun_B->SetClassName(class_name);
2099 18 : fun_B->Inherit(fun_A);
2100 18 : prototype_templ = fun_B->PrototypeTemplate();
2101 18 : prototype_templ->Set(isolate, "c", v8_num(713));
2102 18 : prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
2103 18 : prototype_templ->Set(isolate, "d", v8_num(753));
2104 :
2105 18 : Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
2106 18 : templ->Set(isolate, "x", v8_num(10));
2107 18 : templ->Set(isolate, "y", v8_num(13));
2108 :
2109 : // Perform several iterations to trigger creation from cached boilerplate.
2110 72 : for (int i = 0; i < 3; i++) {
2111 : Local<v8::Object> instance;
2112 54 : switch (mode) {
2113 : case ObjectTemplate_NewInstance:
2114 18 : instance = templ->NewInstance(env.local()).ToLocalChecked();
2115 18 : break;
2116 :
2117 : case Constructor_GetFunction_NewInstance: {
2118 : Local<v8::Function> function_B =
2119 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2120 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2121 : break;
2122 : }
2123 : case Constructor_GetFunction_New: {
2124 : Local<v8::Function> function_B =
2125 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2126 18 : if (i == 0) {
2127 24 : CHECK(env->Global()
2128 : ->Set(env.local(), class_name, function_B)
2129 : .FromJust());
2130 : }
2131 : instance =
2132 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2133 : break;
2134 : }
2135 : default:
2136 0 : UNREACHABLE();
2137 : }
2138 :
2139 108 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2140 270 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2141 :
2142 162 : CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2143 162 : CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2144 :
2145 162 : CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2146 162 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2147 162 : CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2148 162 : CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2149 162 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2150 162 : CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2151 18 : }
2152 18 : }
2153 :
2154 28343 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2155 6 : TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2156 6 : }
2157 :
2158 28343 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2159 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2160 6 : }
2161 :
2162 28343 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2163 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2164 6 : }
2165 :
2166 : // Test object instance creation using a function template without an instance
2167 : // template inherited from another function template.
2168 12 : static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2169 : ObjectInstantiationMode mode) {
2170 12 : LocalContext env;
2171 12 : v8::Isolate* isolate = CcTest::isolate();
2172 24 : v8::HandleScope scope(isolate);
2173 :
2174 12 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2175 12 : fun_A->SetClassName(v8_str("A"));
2176 :
2177 12 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2178 12 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2179 12 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2180 :
2181 12 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2182 12 : v8::Local<v8::String> class_name = v8_str("B");
2183 12 : fun_B->SetClassName(class_name);
2184 12 : fun_B->Inherit(fun_A);
2185 :
2186 : // Perform several iterations to trigger creation from cached boilerplate.
2187 48 : for (int i = 0; i < 3; i++) {
2188 : Local<v8::Object> instance;
2189 36 : switch (mode) {
2190 : case Constructor_GetFunction_NewInstance: {
2191 : Local<v8::Function> function_B =
2192 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2193 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2194 : break;
2195 : }
2196 : case Constructor_GetFunction_New: {
2197 : Local<v8::Function> function_B =
2198 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2199 18 : if (i == 0) {
2200 24 : CHECK(env->Global()
2201 : ->Set(env.local(), class_name, function_B)
2202 : .FromJust());
2203 : }
2204 : instance =
2205 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2206 : break;
2207 : }
2208 : default:
2209 0 : UNREACHABLE();
2210 : }
2211 :
2212 72 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2213 180 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2214 :
2215 108 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2216 108 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2217 12 : }
2218 12 : }
2219 :
2220 28343 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2221 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2222 6 : Constructor_GetFunction_NewInstance);
2223 6 : }
2224 :
2225 28343 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2226 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2227 6 : Constructor_GetFunction_New);
2228 6 : }
2229 :
2230 28343 : THREADED_TEST(TestObjectTemplateClassInheritance) {
2231 6 : LocalContext env;
2232 6 : v8::Isolate* isolate = CcTest::isolate();
2233 12 : v8::HandleScope scope(isolate);
2234 :
2235 6 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2236 6 : fun_A->SetClassName(v8_str("A"));
2237 :
2238 6 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2239 6 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2240 6 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2241 :
2242 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2243 6 : v8::Local<v8::String> class_name = v8_str("B");
2244 6 : fun_B->SetClassName(class_name);
2245 6 : fun_B->Inherit(fun_A);
2246 :
2247 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2248 : v8::Local<v8::Object> b_proto;
2249 : v8::Local<v8::Object> c_proto;
2250 : // Perform several iterations to make sure the cache doesn't break
2251 : // subclassing.
2252 24 : for (int i = 0; i < 3; i++) {
2253 : Local<v8::Function> function_B =
2254 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2255 18 : if (i == 0) {
2256 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2257 : CompileRun("class C extends B {}");
2258 : b_proto =
2259 12 : CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2260 : c_proto =
2261 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2262 12 : CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2263 : }
2264 : Local<v8::Object> instance =
2265 36 : CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2266 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2267 :
2268 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2269 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2270 :
2271 54 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2272 54 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2273 6 : }
2274 6 : }
2275 :
2276 276 : static void NamedPropertyGetterWhichReturns42(
2277 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2278 276 : info.GetReturnValue().Set(v8_num(42));
2279 276 : }
2280 :
2281 28343 : THREADED_TEST(TestObjectTemplateReflectConstruct) {
2282 6 : LocalContext env;
2283 6 : v8::Isolate* isolate = CcTest::isolate();
2284 12 : v8::HandleScope scope(isolate);
2285 :
2286 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2287 : fun_B->InstanceTemplate()->SetHandler(
2288 12 : v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2289 6 : v8::Local<v8::String> class_name = v8_str("B");
2290 6 : fun_B->SetClassName(class_name);
2291 :
2292 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2293 : v8::Local<v8::Object> b_proto;
2294 : v8::Local<v8::Object> c_proto;
2295 : // Perform several iterations to make sure the cache doesn't break
2296 : // subclassing.
2297 24 : for (int i = 0; i < 3; i++) {
2298 : Local<v8::Function> function_B =
2299 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2300 18 : if (i == 0) {
2301 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2302 : CompileRun("function C() {}");
2303 : c_proto =
2304 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2305 : }
2306 : Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2307 18 : ->ToObject(env.local())
2308 18 : .ToLocalChecked();
2309 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2310 :
2311 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2312 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2313 :
2314 54 : CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2315 54 : CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2316 6 : }
2317 6 : }
2318 :
2319 24 : static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2320 12 : ApiTestFuzzer::Fuzz();
2321 12 : args.GetReturnValue().Set(v8_num(17.2));
2322 12 : }
2323 :
2324 :
2325 30 : static void GetKnurd(Local<String> property,
2326 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2327 30 : ApiTestFuzzer::Fuzz();
2328 30 : info.GetReturnValue().Set(v8_num(15.2));
2329 30 : }
2330 :
2331 :
2332 28343 : THREADED_TEST(DescriptorInheritance) {
2333 6 : v8::Isolate* isolate = CcTest::isolate();
2334 6 : v8::HandleScope scope(isolate);
2335 6 : v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2336 12 : super->PrototypeTemplate()->Set(isolate, "flabby",
2337 : v8::FunctionTemplate::New(isolate,
2338 12 : GetFlabby));
2339 12 : super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2340 :
2341 12 : super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2342 :
2343 6 : v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2344 6 : base1->Inherit(super);
2345 12 : base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2346 :
2347 6 : v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2348 6 : base2->Inherit(super);
2349 12 : base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2350 :
2351 12 : LocalContext env;
2352 :
2353 36 : CHECK(env->Global()
2354 : ->Set(env.local(), v8_str("s"),
2355 : super->GetFunction(env.local()).ToLocalChecked())
2356 : .FromJust());
2357 36 : CHECK(env->Global()
2358 : ->Set(env.local(), v8_str("base1"),
2359 : base1->GetFunction(env.local()).ToLocalChecked())
2360 : .FromJust());
2361 36 : CHECK(env->Global()
2362 : ->Set(env.local(), v8_str("base2"),
2363 : base2->GetFunction(env.local()).ToLocalChecked())
2364 : .FromJust());
2365 :
2366 : // Checks right __proto__ chain.
2367 6 : CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2368 : ->BooleanValue(isolate));
2369 6 : CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2370 : ->BooleanValue(isolate));
2371 :
2372 18 : CHECK(v8_compile("s.prototype.PI == 3.14")
2373 : ->Run(env.local())
2374 : .ToLocalChecked()
2375 : ->BooleanValue(isolate));
2376 :
2377 : // Instance accessor should not be visible on function object or its prototype
2378 6 : CHECK(CompileRun("s.knurd == undefined")->BooleanValue(isolate));
2379 6 : CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue(isolate));
2380 6 : CHECK(
2381 : CompileRun("base1.prototype.knurd == undefined")->BooleanValue(isolate));
2382 :
2383 36 : CHECK(env->Global()
2384 : ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2385 : .ToLocalChecked()
2386 : ->NewInstance(env.local())
2387 : .ToLocalChecked())
2388 : .FromJust());
2389 18 : CHECK_EQ(17.2,
2390 : CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2391 6 : CHECK(CompileRun("'flabby' in obj")->BooleanValue(isolate));
2392 18 : CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2393 6 : CHECK(CompileRun("'knurd' in obj")->BooleanValue(isolate));
2394 18 : CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2395 :
2396 36 : CHECK(env->Global()
2397 : ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2398 : .ToLocalChecked()
2399 : ->NewInstance(env.local())
2400 : .ToLocalChecked())
2401 : .FromJust());
2402 18 : CHECK_EQ(17.2,
2403 : CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2404 6 : CHECK(CompileRun("'flabby' in obj2")->BooleanValue(isolate));
2405 18 : CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2406 6 : CHECK(CompileRun("'knurd' in obj2")->BooleanValue(isolate));
2407 18 : CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2408 :
2409 : // base1 and base2 cannot cross reference to each's prototype
2410 6 : CHECK(CompileRun("obj.v2")->IsUndefined());
2411 12 : CHECK(CompileRun("obj2.v1")->IsUndefined());
2412 6 : }
2413 :
2414 28343 : THREADED_TEST(DescriptorInheritance2) {
2415 6 : LocalContext env;
2416 6 : v8::Isolate* isolate = CcTest::isolate();
2417 12 : v8::HandleScope scope(isolate);
2418 6 : v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2419 6 : fun_A->SetClassName(v8_str("A"));
2420 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2421 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2422 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2423 :
2424 6 : v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2425 6 : fun_B->SetClassName(v8_str("B"));
2426 6 : fun_B->Inherit(fun_A);
2427 :
2428 6 : v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2429 6 : fun_C->SetClassName(v8_str("C"));
2430 6 : fun_C->Inherit(fun_B);
2431 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2432 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2433 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2434 :
2435 6 : v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2436 6 : fun_D->SetClassName(v8_str("D"));
2437 6 : fun_D->Inherit(fun_C);
2438 :
2439 6 : v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2440 6 : fun_E->SetClassName(v8_str("E"));
2441 6 : fun_E->Inherit(fun_D);
2442 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2443 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2444 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2445 :
2446 6 : v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2447 6 : fun_F->SetClassName(v8_str("F"));
2448 6 : fun_F->Inherit(fun_E);
2449 6 : v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2450 : const int kDataPropertiesNumber = 100;
2451 606 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2452 600 : v8::Local<v8::Value> val = v8_num(i);
2453 1200 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2454 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2455 :
2456 600 : templ->Set(name, val);
2457 600 : templ->Set(val_str, val);
2458 : }
2459 :
2460 36 : CHECK(env->Global()
2461 : ->Set(env.local(), v8_str("F"),
2462 : fun_F->GetFunction(env.local()).ToLocalChecked())
2463 : .FromJust());
2464 :
2465 : v8::Local<v8::Script> script = v8_compile("o = new F()");
2466 :
2467 606 : for (int i = 0; i < 100; i++) {
2468 600 : v8::HandleScope scope(isolate);
2469 600 : script->Run(env.local()).ToLocalChecked();
2470 600 : }
2471 6 : v8::Local<v8::Object> object = script->Run(env.local())
2472 6 : .ToLocalChecked()
2473 6 : ->ToObject(env.local())
2474 6 : .ToLocalChecked();
2475 :
2476 18 : CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2477 18 : CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2478 18 : CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2479 :
2480 18 : CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2481 18 : CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2482 18 : CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2483 :
2484 18 : CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2485 18 : CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2486 18 : CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2487 :
2488 600 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2489 600 : v8::Local<v8::Value> val = v8_num(i);
2490 1800 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2491 600 : v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2492 :
2493 2400 : CHECK_EQ(i, object->Get(env.local(), name)
2494 : .ToLocalChecked()
2495 : ->IntegerValue(env.local())
2496 : .FromJust());
2497 1800 : CHECK_EQ(i, object->Get(env.local(), val)
2498 : .ToLocalChecked()
2499 : ->IntegerValue(env.local())
2500 : .FromJust());
2501 6 : }
2502 6 : }
2503 :
2504 :
2505 : // Helper functions for Interceptor/Accessor interaction tests
2506 :
2507 36 : void SimpleAccessorGetter(Local<String> name,
2508 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2509 : Local<Object> self = Local<Object>::Cast(info.This());
2510 : info.GetReturnValue().Set(
2511 : self->Get(info.GetIsolate()->GetCurrentContext(),
2512 144 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
2513 36 : .ToLocalChecked());
2514 36 : }
2515 :
2516 6 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2517 : const v8::PropertyCallbackInfo<void>& info) {
2518 : Local<Object> self = Local<Object>::Cast(info.This());
2519 24 : CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2520 : String::Concat(info.GetIsolate(), v8_str("accessor_"), name),
2521 : value)
2522 : .FromJust());
2523 6 : }
2524 :
2525 36 : void SymbolAccessorGetter(Local<Name> name,
2526 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2527 36 : CHECK(name->IsSymbol());
2528 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2529 72 : if (sym->Name()->IsUndefined())
2530 36 : return;
2531 36 : SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2532 : }
2533 :
2534 6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2535 : const v8::PropertyCallbackInfo<void>& info) {
2536 6 : CHECK(name->IsSymbol());
2537 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2538 12 : if (sym->Name()->IsUndefined())
2539 6 : return;
2540 6 : SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2541 : }
2542 :
2543 5 : void SymbolAccessorGetterReturnsDefault(
2544 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2545 5 : CHECK(name->IsSymbol());
2546 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2547 15 : if (sym->Name()->IsUndefined()) return;
2548 : info.GetReturnValue().Set(info.Data());
2549 : }
2550 :
2551 5 : static void ThrowingSymbolAccessorGetter(
2552 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2553 10 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2554 5 : }
2555 :
2556 :
2557 28343 : THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2558 6 : v8::Isolate* isolate = CcTest::isolate();
2559 6 : v8::HandleScope scope(isolate);
2560 12 : LocalContext env;
2561 : v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2562 : i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2563 12 : CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
2564 : CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2565 12 : CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
2566 : // But we should still have an AccessorInfo.
2567 12 : i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2568 : i::LookupIterator it(CcTest::i_isolate(), a, name,
2569 6 : i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2570 6 : CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2571 24 : CHECK(it.GetAccessors()->IsAccessorInfo());
2572 6 : }
2573 :
2574 :
2575 28343 : THREADED_TEST(UndefinedIsNotEnumerable) {
2576 6 : LocalContext env;
2577 12 : v8::HandleScope scope(env->GetIsolate());
2578 : v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2579 12 : CHECK(result->IsFalse());
2580 6 : }
2581 :
2582 :
2583 : v8::Local<Script> call_recursively_script;
2584 : static const int kTargetRecursionDepth = 100; // near maximum
2585 :
2586 606 : static void CallScriptRecursivelyCall(
2587 3012 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2588 606 : ApiTestFuzzer::Fuzz();
2589 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2590 : int depth = args.This()
2591 1212 : ->Get(context, v8_str("depth"))
2592 606 : .ToLocalChecked()
2593 : ->Int32Value(context)
2594 1212 : .FromJust();
2595 612 : if (depth == kTargetRecursionDepth) return;
2596 3000 : CHECK(args.This()
2597 : ->Set(context, v8_str("depth"),
2598 : v8::Integer::New(args.GetIsolate(), depth + 1))
2599 : .FromJust());
2600 : args.GetReturnValue().Set(
2601 600 : call_recursively_script->Run(context).ToLocalChecked());
2602 : }
2603 :
2604 :
2605 606 : static void CallFunctionRecursivelyCall(
2606 4212 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2607 606 : ApiTestFuzzer::Fuzz();
2608 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2609 : int depth = args.This()
2610 1212 : ->Get(context, v8_str("depth"))
2611 606 : .ToLocalChecked()
2612 : ->Int32Value(context)
2613 1212 : .FromJust();
2614 606 : if (depth == kTargetRecursionDepth) {
2615 : printf("[depth = %d]\n", depth);
2616 612 : return;
2617 : }
2618 3000 : CHECK(args.This()
2619 : ->Set(context, v8_str("depth"),
2620 : v8::Integer::New(args.GetIsolate(), depth + 1))
2621 : .FromJust());
2622 : v8::Local<Value> function =
2623 : args.This()
2624 1200 : ->Get(context, v8_str("callFunctionRecursively"))
2625 600 : .ToLocalChecked();
2626 : args.GetReturnValue().Set(function.As<Function>()
2627 600 : ->Call(context, args.This(), 0, nullptr)
2628 600 : .ToLocalChecked());
2629 : }
2630 :
2631 :
2632 28343 : THREADED_TEST(DeepCrossLanguageRecursion) {
2633 6 : v8::Isolate* isolate = CcTest::isolate();
2634 6 : v8::HandleScope scope(isolate);
2635 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2636 : global->Set(v8_str("callScriptRecursively"),
2637 18 : v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2638 : global->Set(v8_str("callFunctionRecursively"),
2639 18 : v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2640 12 : LocalContext env(nullptr, global);
2641 :
2642 36 : CHECK(env->Global()
2643 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2644 : .FromJust());
2645 6 : call_recursively_script = v8_compile("callScriptRecursively()");
2646 12 : call_recursively_script->Run(env.local()).ToLocalChecked();
2647 6 : call_recursively_script = v8::Local<Script>();
2648 :
2649 36 : CHECK(env->Global()
2650 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2651 : .FromJust());
2652 6 : CompileRun("callFunctionRecursively()");
2653 6 : }
2654 :
2655 :
2656 24 : static void ThrowingPropertyHandlerGet(
2657 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2658 : // Since this interceptor is used on "with" objects, the runtime will look up
2659 : // @@unscopables. Punt.
2660 48 : if (key->IsSymbol()) return;
2661 12 : ApiTestFuzzer::Fuzz();
2662 24 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2663 : }
2664 :
2665 :
2666 0 : static void ThrowingPropertyHandlerSet(
2667 : Local<Name> key, Local<Value>,
2668 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2669 0 : info.GetIsolate()->ThrowException(key);
2670 : info.GetReturnValue().SetUndefined(); // not the same as empty handle
2671 0 : }
2672 :
2673 :
2674 28343 : THREADED_TEST(CallbackExceptionRegression) {
2675 6 : v8::Isolate* isolate = CcTest::isolate();
2676 6 : v8::HandleScope scope(isolate);
2677 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2678 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2679 6 : ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2680 12 : LocalContext env;
2681 36 : CHECK(env->Global()
2682 : ->Set(env.local(), v8_str("obj"),
2683 : obj->NewInstance(env.local()).ToLocalChecked())
2684 : .FromJust());
2685 : v8::Local<Value> otto =
2686 6 : CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2687 18 : CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2688 : v8::Local<Value> netto =
2689 6 : CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2690 24 : CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2691 6 : }
2692 :
2693 :
2694 28343 : THREADED_TEST(FunctionPrototype) {
2695 6 : v8::Isolate* isolate = CcTest::isolate();
2696 6 : v8::HandleScope scope(isolate);
2697 6 : Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2698 24 : Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2699 12 : LocalContext env;
2700 36 : CHECK(env->Global()
2701 : ->Set(env.local(), v8_str("Foo"),
2702 : Foo->GetFunction(env.local()).ToLocalChecked())
2703 : .FromJust());
2704 6 : Local<Script> script = v8_compile("Foo.prototype.plak");
2705 12 : CHECK_EQ(v8_run_int32value(script), 321);
2706 6 : }
2707 :
2708 28343 : THREADED_TEST(InternalFields) {
2709 6 : LocalContext env;
2710 6 : v8::Isolate* isolate = env->GetIsolate();
2711 12 : v8::HandleScope scope(isolate);
2712 :
2713 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2714 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2715 6 : instance_templ->SetInternalFieldCount(1);
2716 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2717 6 : .ToLocalChecked()
2718 6 : ->NewInstance(env.local())
2719 : .ToLocalChecked();
2720 6 : CHECK_EQ(1, obj->InternalFieldCount());
2721 6 : CHECK(obj->GetInternalField(0)->IsUndefined());
2722 6 : obj->SetInternalField(0, v8_num(17));
2723 24 : CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2724 6 : }
2725 :
2726 28342 : TEST(InternalFieldsSubclassing) {
2727 5 : LocalContext env;
2728 5 : v8::Isolate* isolate = env->GetIsolate();
2729 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2730 10 : v8::HandleScope scope(isolate);
2731 65 : for (int nof_embedder_fields = 0;
2732 : nof_embedder_fields < i::JSObject::kMaxEmbedderFields;
2733 : nof_embedder_fields++) {
2734 60 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2735 60 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2736 60 : instance_templ->SetInternalFieldCount(nof_embedder_fields);
2737 : Local<Function> constructor =
2738 60 : templ->GetFunction(env.local()).ToLocalChecked();
2739 : // Check that instances have the correct NOF properties.
2740 : Local<v8::Object> obj =
2741 60 : constructor->NewInstance(env.local()).ToLocalChecked();
2742 :
2743 : i::Handle<i::JSObject> i_obj =
2744 60 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
2745 60 : CHECK_EQ(nof_embedder_fields, obj->InternalFieldCount());
2746 60 : CHECK_EQ(0, i_obj->map()->GetInObjectProperties());
2747 : // Check writing and reading internal fields.
2748 330 : for (int j = 0; j < nof_embedder_fields; j++) {
2749 330 : CHECK(obj->GetInternalField(j)->IsUndefined());
2750 330 : int value = 17 + j;
2751 330 : obj->SetInternalField(j, v8_num(value));
2752 : }
2753 330 : for (int j = 0; j < nof_embedder_fields; j++) {
2754 330 : int value = 17 + j;
2755 990 : CHECK_EQ(value,
2756 : obj->GetInternalField(j)->Int32Value(env.local()).FromJust());
2757 : }
2758 300 : CHECK(env->Global()
2759 : ->Set(env.local(), v8_str("BaseClass"), constructor)
2760 : .FromJust());
2761 : // Create various levels of subclasses to stress instance size calculation.
2762 : const int kMaxNofProperties =
2763 : i::JSObject::kMaxInObjectProperties -
2764 60 : nof_embedder_fields * i::kEmbedderDataSlotSizeInTaggedSlots;
2765 : // Select only a few values to speed up the test.
2766 : int sizes[] = {0,
2767 : 1,
2768 : 2,
2769 : 3,
2770 : 4,
2771 : 5,
2772 : 6,
2773 60 : kMaxNofProperties / 4,
2774 60 : kMaxNofProperties / 2,
2775 60 : kMaxNofProperties - 2,
2776 60 : kMaxNofProperties - 1,
2777 60 : kMaxNofProperties + 1,
2778 60 : kMaxNofProperties + 2,
2779 60 : kMaxNofProperties * 2,
2780 480 : kMaxNofProperties * 2};
2781 960 : for (size_t i = 0; i < arraysize(sizes); i++) {
2782 900 : int nof_properties = sizes[i];
2783 900 : bool in_object_only = nof_properties <= kMaxNofProperties;
2784 900 : std::ostringstream src;
2785 : // Assembler source string for a subclass with {nof_properties}
2786 : // in-object properties.
2787 900 : src << "(function() {\n"
2788 900 : << " class SubClass extends BaseClass {\n"
2789 900 : << " constructor() {\n"
2790 900 : << " super();\n";
2791 : // Set {nof_properties} instance properties in the constructor.
2792 131535 : for (int j = 0; j < nof_properties; j++) {
2793 130635 : src << " this.property" << j << " = " << j << ";\n";
2794 : }
2795 900 : src << " }\n"
2796 900 : << " };\n"
2797 900 : << " let instance;\n"
2798 900 : << " for (let i = 0; i < 3; i++) {\n"
2799 900 : << " instance = new SubClass();\n"
2800 900 : << " }"
2801 900 : << " return instance;\n"
2802 900 : << "})();";
2803 900 : Local<v8::Object> value = CompileRun(src.str().c_str()).As<v8::Object>();
2804 :
2805 : i::Handle<i::JSObject> i_value =
2806 900 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*value));
2807 : #ifdef VERIFY_HEAP
2808 : i_value->HeapObjectVerify(i_isolate);
2809 : i_value->map()->HeapObjectVerify(i_isolate);
2810 : i_value->map()->FindRootMap(i_isolate)->HeapObjectVerify(i_isolate);
2811 : #endif
2812 900 : CHECK_EQ(nof_embedder_fields, value->InternalFieldCount());
2813 900 : if (in_object_only) {
2814 660 : CHECK_LE(nof_properties, i_value->map()->GetInObjectProperties());
2815 : } else {
2816 240 : CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
2817 : }
2818 :
2819 : // Make Sure we get the precise property count.
2820 1800 : i_value->map()->FindRootMap(i_isolate)->CompleteInobjectSlackTracking(
2821 900 : i_isolate);
2822 : // TODO(cbruni): fix accounting to make this condition true.
2823 : // CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
2824 900 : if (in_object_only) {
2825 660 : CHECK_EQ(nof_properties, i_value->map()->GetInObjectProperties());
2826 : } else {
2827 240 : CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
2828 : }
2829 900 : }
2830 5 : }
2831 5 : }
2832 :
2833 28343 : THREADED_TEST(InternalFieldsOfRegularObjects) {
2834 6 : LocalContext env;
2835 6 : v8::Isolate* isolate = env->GetIsolate();
2836 12 : v8::HandleScope scope(isolate);
2837 :
2838 6 : const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"};
2839 24 : for (size_t i = 0; i < arraysize(sources); ++i) {
2840 : i::ScopedVector<char> source(128);
2841 18 : i::SNPrintF(source, "(function() { return %s })()", sources[i]);
2842 : v8::Local<v8::Object> obj = CompileRun(source.start()).As<v8::Object>();
2843 18 : CHECK_EQ(0, obj->InternalFieldCount());
2844 6 : }
2845 6 : }
2846 :
2847 28343 : THREADED_TEST(GlobalObjectInternalFields) {
2848 6 : v8::Isolate* isolate = CcTest::isolate();
2849 6 : v8::HandleScope scope(isolate);
2850 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2851 6 : global_template->SetInternalFieldCount(1);
2852 12 : LocalContext env(nullptr, global_template);
2853 6 : v8::Local<v8::Object> global_proxy = env->Global();
2854 6 : v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2855 6 : CHECK_EQ(1, global->InternalFieldCount());
2856 6 : CHECK(global->GetInternalField(0)->IsUndefined());
2857 6 : global->SetInternalField(0, v8_num(17));
2858 24 : CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2859 6 : }
2860 :
2861 :
2862 28343 : THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2863 6 : LocalContext env;
2864 12 : v8::HandleScope scope(CcTest::isolate());
2865 :
2866 6 : v8::Local<v8::Object> global = env->Global();
2867 18 : CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2868 18 : CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2869 6 : }
2870 :
2871 24 : static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2872 : void* value) {
2873 24 : CHECK(HAS_SMI_TAG(reinterpret_cast<i::Address>(value)));
2874 24 : obj->SetAlignedPointerInInternalField(0, value);
2875 24 : CcTest::CollectAllGarbage();
2876 24 : CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2877 24 : }
2878 :
2879 28343 : THREADED_TEST(InternalFieldsAlignedPointers) {
2880 6 : LocalContext env;
2881 6 : v8::Isolate* isolate = env->GetIsolate();
2882 12 : v8::HandleScope scope(isolate);
2883 :
2884 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2885 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2886 6 : instance_templ->SetInternalFieldCount(1);
2887 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2888 6 : .ToLocalChecked()
2889 6 : ->NewInstance(env.local())
2890 : .ToLocalChecked();
2891 6 : CHECK_EQ(1, obj->InternalFieldCount());
2892 :
2893 6 : CheckAlignedPointerInInternalField(obj, nullptr);
2894 :
2895 6 : int* heap_allocated = new int[100];
2896 6 : CheckAlignedPointerInInternalField(obj, heap_allocated);
2897 6 : delete[] heap_allocated;
2898 :
2899 : int stack_allocated[100];
2900 6 : CheckAlignedPointerInInternalField(obj, stack_allocated);
2901 :
2902 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2903 6 : CheckAlignedPointerInInternalField(obj, huge);
2904 :
2905 : v8::Global<v8::Object> persistent(isolate, obj);
2906 6 : CHECK_EQ(1, Object::InternalFieldCount(persistent));
2907 12 : CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2908 6 : }
2909 :
2910 28343 : THREADED_TEST(SetAlignedPointerInInternalFields) {
2911 6 : LocalContext env;
2912 6 : v8::Isolate* isolate = env->GetIsolate();
2913 12 : v8::HandleScope scope(isolate);
2914 :
2915 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2916 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2917 6 : instance_templ->SetInternalFieldCount(2);
2918 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2919 6 : .ToLocalChecked()
2920 6 : ->NewInstance(env.local())
2921 : .ToLocalChecked();
2922 6 : CHECK_EQ(2, obj->InternalFieldCount());
2923 :
2924 6 : int* heap_allocated_1 = new int[100];
2925 6 : int* heap_allocated_2 = new int[100];
2926 6 : int indices[] = {0, 1};
2927 6 : void* values[] = {heap_allocated_1, heap_allocated_2};
2928 :
2929 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2930 6 : CcTest::CollectAllGarbage();
2931 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0));
2932 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1));
2933 :
2934 6 : indices[0] = 1;
2935 6 : indices[1] = 0;
2936 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2937 6 : CcTest::CollectAllGarbage();
2938 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0));
2939 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1));
2940 :
2941 6 : delete[] heap_allocated_1;
2942 12 : delete[] heap_allocated_2;
2943 6 : }
2944 :
2945 24 : static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2946 : void* value) {
2947 24 : CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2948 24 : (*env)->SetAlignedPointerInEmbedderData(index, value);
2949 24 : CcTest::CollectAllGarbage();
2950 24 : CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2951 24 : }
2952 :
2953 :
2954 : static void* AlignedTestPointer(int i) {
2955 1200 : return reinterpret_cast<void*>(i * 1234);
2956 : }
2957 :
2958 :
2959 28343 : THREADED_TEST(EmbedderDataAlignedPointers) {
2960 6 : LocalContext env;
2961 12 : v8::HandleScope scope(env->GetIsolate());
2962 :
2963 6 : CheckAlignedPointerInEmbedderData(&env, 0, nullptr);
2964 6 : CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields());
2965 :
2966 6 : int* heap_allocated = new int[100];
2967 6 : CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2968 6 : CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields());
2969 6 : delete[] heap_allocated;
2970 :
2971 : int stack_allocated[100];
2972 6 : CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2973 6 : CHECK_EQ(3, (*env)->GetNumberOfEmbedderDataFields());
2974 :
2975 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2976 6 : CheckAlignedPointerInEmbedderData(&env, 3, huge);
2977 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
2978 :
2979 : // Test growing of the embedder data's backing store.
2980 600 : for (int i = 0; i < 100; i++) {
2981 600 : env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2982 : }
2983 6 : CcTest::CollectAllGarbage();
2984 606 : for (int i = 0; i < 100; i++) {
2985 600 : CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2986 6 : }
2987 6 : }
2988 :
2989 30 : static void CheckEmbedderData(LocalContext* env, int index,
2990 : v8::Local<Value> data) {
2991 30 : (*env)->SetEmbedderData(index, data);
2992 30 : CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2993 30 : }
2994 :
2995 :
2996 28343 : THREADED_TEST(EmbedderData) {
2997 6 : LocalContext env;
2998 6 : v8::Isolate* isolate = env->GetIsolate();
2999 12 : v8::HandleScope scope(isolate);
3000 :
3001 6 : CHECK_EQ(0, (*env)->GetNumberOfEmbedderDataFields());
3002 12 : CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
3003 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3004 12 : CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
3005 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3006 12 : CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
3007 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3008 6 : CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
3009 6 : CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3010 6 : CheckEmbedderData(&env, 211, v8::Boolean::New(isolate, true));
3011 12 : CHECK_EQ(212, (*env)->GetNumberOfEmbedderDataFields());
3012 6 : }
3013 :
3014 :
3015 28343 : THREADED_TEST(IdentityHash) {
3016 6 : LocalContext env;
3017 6 : v8::Isolate* isolate = env->GetIsolate();
3018 12 : v8::HandleScope scope(isolate);
3019 :
3020 : // Ensure that the test starts with an fresh heap to test whether the hash
3021 : // code is based on the address.
3022 6 : CcTest::CollectAllGarbage();
3023 6 : Local<v8::Object> obj = v8::Object::New(isolate);
3024 6 : int hash = obj->GetIdentityHash();
3025 6 : int hash1 = obj->GetIdentityHash();
3026 6 : CHECK_EQ(hash, hash1);
3027 12 : int hash2 = v8::Object::New(isolate)->GetIdentityHash();
3028 : // Since the identity hash is essentially a random number two consecutive
3029 : // objects should not be assigned the same hash code. If the test below fails
3030 : // the random number generator should be evaluated.
3031 6 : CHECK_NE(hash, hash2);
3032 6 : CcTest::CollectAllGarbage();
3033 12 : int hash3 = v8::Object::New(isolate)->GetIdentityHash();
3034 : // Make sure that the identity hash is not based on the initial address of
3035 : // the object alone. If the test below fails the random number generator
3036 : // should be evaluated.
3037 6 : CHECK_NE(hash, hash3);
3038 6 : int hash4 = obj->GetIdentityHash();
3039 6 : CHECK_EQ(hash, hash4);
3040 :
3041 : // Check identity hashes behaviour in the presence of JS accessors.
3042 : // Put a getter for 'v8::IdentityHash' on the Object's prototype:
3043 : {
3044 : CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
3045 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3046 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3047 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3048 : }
3049 : {
3050 : CompileRun(
3051 : "function cnst() { return 42; };\n"
3052 : "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3053 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
3054 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
3055 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3056 6 : }
3057 6 : }
3058 :
3059 :
3060 12 : void GlobalProxyIdentityHash(bool set_in_js) {
3061 12 : LocalContext env;
3062 12 : v8::Isolate* isolate = env->GetIsolate();
3063 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3064 24 : v8::HandleScope scope(isolate);
3065 12 : Local<Object> global_proxy = env->Global();
3066 : i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
3067 60 : CHECK(env->Global()
3068 : ->Set(env.local(), v8_str("global"), global_proxy)
3069 : .FromJust());
3070 : int32_t hash1;
3071 12 : if (set_in_js) {
3072 : CompileRun("var m = new Set(); m.add(global);");
3073 6 : i::Object original_hash = i_global_proxy->GetHash();
3074 6 : CHECK(original_hash->IsSmi());
3075 6 : hash1 = i::Smi::ToInt(original_hash);
3076 : } else {
3077 12 : hash1 = i_global_proxy->GetOrCreateHash(i_isolate)->value();
3078 : }
3079 : // Hash should be retained after being detached.
3080 12 : env->DetachGlobal();
3081 12 : int hash2 = global_proxy->GetIdentityHash();
3082 12 : CHECK_EQ(hash1, hash2);
3083 : {
3084 : // Re-attach global proxy to a new context, hash should stay the same.
3085 12 : LocalContext env2(nullptr, Local<ObjectTemplate>(), global_proxy);
3086 12 : int hash3 = global_proxy->GetIdentityHash();
3087 12 : CHECK_EQ(hash1, hash3);
3088 12 : }
3089 12 : }
3090 :
3091 :
3092 28343 : THREADED_TEST(GlobalProxyIdentityHash) {
3093 6 : GlobalProxyIdentityHash(true);
3094 6 : GlobalProxyIdentityHash(false);
3095 6 : }
3096 :
3097 :
3098 28342 : TEST(SymbolIdentityHash) {
3099 5 : LocalContext env;
3100 5 : v8::Isolate* isolate = env->GetIsolate();
3101 10 : v8::HandleScope scope(isolate);
3102 :
3103 : {
3104 5 : Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3105 5 : int hash = symbol->GetIdentityHash();
3106 5 : int hash1 = symbol->GetIdentityHash();
3107 5 : CHECK_EQ(hash, hash1);
3108 5 : CcTest::CollectAllGarbage();
3109 5 : int hash3 = symbol->GetIdentityHash();
3110 5 : CHECK_EQ(hash, hash3);
3111 : }
3112 :
3113 : {
3114 : v8::Local<v8::Symbol> js_symbol =
3115 : CompileRun("Symbol('foo')").As<v8::Symbol>();
3116 5 : int hash = js_symbol->GetIdentityHash();
3117 5 : int hash1 = js_symbol->GetIdentityHash();
3118 5 : CHECK_EQ(hash, hash1);
3119 5 : CcTest::CollectAllGarbage();
3120 5 : int hash3 = js_symbol->GetIdentityHash();
3121 5 : CHECK_EQ(hash, hash3);
3122 5 : }
3123 5 : }
3124 :
3125 :
3126 28342 : TEST(StringIdentityHash) {
3127 5 : LocalContext env;
3128 5 : v8::Isolate* isolate = env->GetIsolate();
3129 10 : v8::HandleScope scope(isolate);
3130 :
3131 5 : Local<v8::String> str = v8_str("str1");
3132 5 : int hash = str->GetIdentityHash();
3133 5 : int hash1 = str->GetIdentityHash();
3134 5 : CHECK_EQ(hash, hash1);
3135 5 : CcTest::CollectAllGarbage();
3136 5 : int hash3 = str->GetIdentityHash();
3137 5 : CHECK_EQ(hash, hash3);
3138 :
3139 5 : Local<v8::String> str2 = v8_str("str1");
3140 5 : int hash4 = str2->GetIdentityHash();
3141 10 : CHECK_EQ(hash, hash4);
3142 5 : }
3143 :
3144 :
3145 28343 : THREADED_TEST(SymbolProperties) {
3146 6 : LocalContext env;
3147 6 : v8::Isolate* isolate = env->GetIsolate();
3148 12 : v8::HandleScope scope(isolate);
3149 :
3150 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3151 6 : v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3152 6 : v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
3153 6 : v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
3154 6 : v8::Local<v8::Symbol> sym4 = v8::Symbol::New(isolate, v8_str("native"));
3155 :
3156 6 : CcTest::CollectAllGarbage();
3157 :
3158 : // Check basic symbol functionality.
3159 6 : CHECK(sym1->IsSymbol());
3160 6 : CHECK(sym2->IsSymbol());
3161 6 : CHECK(!obj->IsSymbol());
3162 :
3163 12 : CHECK(sym1->Equals(env.local(), sym1).FromJust());
3164 12 : CHECK(sym2->Equals(env.local(), sym2).FromJust());
3165 12 : CHECK(!sym1->Equals(env.local(), sym2).FromJust());
3166 12 : CHECK(!sym2->Equals(env.local(), sym1).FromJust());
3167 6 : CHECK(sym1->StrictEquals(sym1));
3168 6 : CHECK(sym2->StrictEquals(sym2));
3169 6 : CHECK(!sym1->StrictEquals(sym2));
3170 6 : CHECK(!sym2->StrictEquals(sym1));
3171 :
3172 24 : CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
3173 :
3174 : v8::Local<v8::Value> sym_val = sym2;
3175 6 : CHECK(sym_val->IsSymbol());
3176 12 : CHECK(sym_val->Equals(env.local(), sym2).FromJust());
3177 6 : CHECK(sym_val->StrictEquals(sym2));
3178 12 : CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
3179 :
3180 6 : v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3181 6 : CHECK(sym_obj->IsSymbolObject());
3182 6 : CHECK(!sym2->IsSymbolObject());
3183 6 : CHECK(!obj->IsSymbolObject());
3184 12 : CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
3185 6 : CHECK(!sym_obj->StrictEquals(sym2));
3186 12 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3187 : ->Equals(env.local(), sym_obj)
3188 : .FromJust());
3189 18 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3190 : ->ValueOf()
3191 : ->Equals(env.local(), sym2)
3192 : .FromJust());
3193 :
3194 : // Make sure delete of a non-existent symbol property works.
3195 12 : CHECK(obj->Delete(env.local(), sym1).FromJust());
3196 12 : CHECK(!obj->Has(env.local(), sym1).FromJust());
3197 :
3198 18 : CHECK(
3199 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
3200 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3201 24 : CHECK_EQ(1503, obj->Get(env.local(), sym1)
3202 : .ToLocalChecked()
3203 : ->Int32Value(env.local())
3204 : .FromJust());
3205 18 : CHECK(
3206 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
3207 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3208 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3209 : .ToLocalChecked()
3210 : ->Int32Value(env.local())
3211 : .FromJust());
3212 12 : CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
3213 :
3214 12 : CHECK_EQ(0u,
3215 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3216 : unsigned num_props =
3217 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3218 24 : CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
3219 : .FromJust());
3220 12 : CHECK_EQ(1u,
3221 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3222 12 : CHECK_EQ(num_props + 1,
3223 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3224 :
3225 6 : CcTest::CollectAllGarbage();
3226 :
3227 12 : CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
3228 : SymbolAccessorSetter)
3229 : .FromJust());
3230 12 : CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
3231 18 : CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
3232 30 : CHECK(obj->Get(env.local(), sym3)
3233 : .ToLocalChecked()
3234 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3235 : .FromJust());
3236 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3237 : .ToLocalChecked()
3238 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3239 : .FromJust());
3240 :
3241 12 : CHECK(obj->SetNativeDataProperty(env.local(), sym4, SymbolAccessorGetter)
3242 : .FromJust());
3243 12 : CHECK(obj->Get(env.local(), sym4).ToLocalChecked()->IsUndefined());
3244 24 : CHECK(obj->Set(env.local(), v8_str("accessor_native"),
3245 : v8::Integer::New(isolate, 123))
3246 : .FromJust());
3247 24 : CHECK_EQ(123, obj->Get(env.local(), sym4)
3248 : .ToLocalChecked()
3249 : ->Int32Value(env.local())
3250 : .FromJust());
3251 18 : CHECK(obj->Set(env.local(), sym4, v8::Integer::New(isolate, 314)).FromJust());
3252 30 : CHECK(obj->Get(env.local(), sym4)
3253 : .ToLocalChecked()
3254 : ->Equals(env.local(), v8::Integer::New(isolate, 314))
3255 : .FromJust());
3256 18 : CHECK(obj->Delete(env.local(), v8_str("accessor_native")).FromJust());
3257 :
3258 : // Add another property and delete it afterwards to force the object in
3259 : // slow case.
3260 18 : CHECK(
3261 : obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
3262 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3263 : .ToLocalChecked()
3264 : ->Int32Value(env.local())
3265 : .FromJust());
3266 24 : CHECK_EQ(2008, obj->Get(env.local(), sym2)
3267 : .ToLocalChecked()
3268 : ->Int32Value(env.local())
3269 : .FromJust());
3270 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3271 : .ToLocalChecked()
3272 : ->Int32Value(env.local())
3273 : .FromJust());
3274 12 : CHECK_EQ(2u,
3275 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3276 :
3277 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3278 12 : CHECK(obj->Has(env.local(), sym2).FromJust());
3279 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3280 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3281 12 : CHECK(obj->Delete(env.local(), sym2).FromJust());
3282 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3283 12 : CHECK(!obj->Has(env.local(), sym2).FromJust());
3284 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3285 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3286 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3287 : .ToLocalChecked()
3288 : ->Int32Value(env.local())
3289 : .FromJust());
3290 30 : CHECK(obj->Get(env.local(), sym3)
3291 : .ToLocalChecked()
3292 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3293 : .FromJust());
3294 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3295 : .ToLocalChecked()
3296 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3297 : .FromJust());
3298 12 : CHECK_EQ(2u,
3299 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3300 :
3301 : // Symbol properties are inherited.
3302 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3303 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3304 12 : CHECK(child->Has(env.local(), sym1).FromJust());
3305 24 : CHECK_EQ(2002, child->Get(env.local(), sym1)
3306 : .ToLocalChecked()
3307 : ->Int32Value(env.local())
3308 : .FromJust());
3309 30 : CHECK(obj->Get(env.local(), sym3)
3310 : .ToLocalChecked()
3311 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3312 : .FromJust());
3313 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3314 : .ToLocalChecked()
3315 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3316 : .FromJust());
3317 12 : CHECK_EQ(0u,
3318 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3319 6 : }
3320 :
3321 :
3322 28343 : THREADED_TEST(SymbolTemplateProperties) {
3323 6 : LocalContext env;
3324 6 : v8::Isolate* isolate = env->GetIsolate();
3325 12 : v8::HandleScope scope(isolate);
3326 6 : v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3327 6 : v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3328 6 : CHECK(!name.IsEmpty());
3329 18 : foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3330 : v8::Local<v8::Object> new_instance =
3331 18 : foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3332 6 : CHECK(!new_instance.IsEmpty());
3333 18 : CHECK(new_instance->Has(env.local(), name).FromJust());
3334 6 : }
3335 :
3336 :
3337 28343 : THREADED_TEST(PrivatePropertiesOnProxies) {
3338 6 : LocalContext env;
3339 6 : v8::Isolate* isolate = env->GetIsolate();
3340 12 : v8::HandleScope scope(isolate);
3341 :
3342 6 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3343 6 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3344 :
3345 : v8::Local<v8::Proxy> proxy =
3346 6 : v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3347 :
3348 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3349 : v8::Local<v8::Private> priv2 =
3350 6 : v8::Private::New(isolate, v8_str("my-private"));
3351 :
3352 6 : CcTest::CollectAllGarbage();
3353 :
3354 30 : CHECK(priv2->Name()
3355 : ->Equals(env.local(),
3356 : v8::String::NewFromUtf8(isolate, "my-private",
3357 : v8::NewStringType::kNormal)
3358 : .ToLocalChecked())
3359 : .FromJust());
3360 :
3361 : // Make sure delete of a non-existent private symbol property works.
3362 12 : proxy->DeletePrivate(env.local(), priv1).FromJust();
3363 12 : CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3364 :
3365 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3366 : .FromJust());
3367 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3368 18 : CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3369 : .ToLocalChecked()
3370 : ->Int32Value(env.local())
3371 : .FromJust());
3372 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3373 : .FromJust());
3374 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3375 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3376 : .ToLocalChecked()
3377 : ->Int32Value(env.local())
3378 : .FromJust());
3379 :
3380 12 : CHECK_EQ(0u,
3381 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3382 : unsigned num_props =
3383 12 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3384 24 : CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3385 : isolate, "bla", v8::NewStringType::kNormal)
3386 : .ToLocalChecked(),
3387 : v8::Integer::New(isolate, 20))
3388 : .FromJust());
3389 12 : CHECK_EQ(1u,
3390 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3391 12 : CHECK_EQ(num_props + 1,
3392 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3393 :
3394 6 : CcTest::CollectAllGarbage();
3395 :
3396 : // Add another property and delete it afterwards to force the object in
3397 : // slow case.
3398 18 : CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3399 : .FromJust());
3400 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3401 : .ToLocalChecked()
3402 : ->Int32Value(env.local())
3403 : .FromJust());
3404 18 : CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3405 : .ToLocalChecked()
3406 : ->Int32Value(env.local())
3407 : .FromJust());
3408 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3409 : .ToLocalChecked()
3410 : ->Int32Value(env.local())
3411 : .FromJust());
3412 12 : CHECK_EQ(1u,
3413 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3414 :
3415 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3416 12 : CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3417 12 : CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3418 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3419 12 : CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3420 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3421 : .ToLocalChecked()
3422 : ->Int32Value(env.local())
3423 : .FromJust());
3424 12 : CHECK_EQ(1u,
3425 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3426 :
3427 : // Private properties are not inherited (for the time being).
3428 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3429 12 : CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3430 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3431 12 : CHECK_EQ(0u,
3432 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3433 6 : }
3434 :
3435 :
3436 28343 : THREADED_TEST(PrivateProperties) {
3437 6 : LocalContext env;
3438 6 : v8::Isolate* isolate = env->GetIsolate();
3439 12 : v8::HandleScope scope(isolate);
3440 :
3441 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3442 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3443 : v8::Local<v8::Private> priv2 =
3444 6 : v8::Private::New(isolate, v8_str("my-private"));
3445 :
3446 6 : CcTest::CollectAllGarbage();
3447 :
3448 30 : CHECK(priv2->Name()
3449 : ->Equals(env.local(),
3450 : v8::String::NewFromUtf8(isolate, "my-private",
3451 : v8::NewStringType::kNormal)
3452 : .ToLocalChecked())
3453 : .FromJust());
3454 :
3455 : // Make sure delete of a non-existent private symbol property works.
3456 12 : obj->DeletePrivate(env.local(), priv1).FromJust();
3457 12 : CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3458 :
3459 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3460 : .FromJust());
3461 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3462 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3463 : .ToLocalChecked()
3464 : ->Int32Value(env.local())
3465 : .FromJust());
3466 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3467 : .FromJust());
3468 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3469 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3470 : .ToLocalChecked()
3471 : ->Int32Value(env.local())
3472 : .FromJust());
3473 :
3474 12 : CHECK_EQ(0u,
3475 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3476 : unsigned num_props =
3477 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3478 24 : CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3479 : isolate, "bla", v8::NewStringType::kNormal)
3480 : .ToLocalChecked(),
3481 : v8::Integer::New(isolate, 20))
3482 : .FromJust());
3483 12 : CHECK_EQ(1u,
3484 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3485 12 : CHECK_EQ(num_props + 1,
3486 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3487 :
3488 6 : CcTest::CollectAllGarbage();
3489 :
3490 : // Add another property and delete it afterwards to force the object in
3491 : // slow case.
3492 18 : CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3493 : .FromJust());
3494 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3495 : .ToLocalChecked()
3496 : ->Int32Value(env.local())
3497 : .FromJust());
3498 18 : CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3499 : .ToLocalChecked()
3500 : ->Int32Value(env.local())
3501 : .FromJust());
3502 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3503 : .ToLocalChecked()
3504 : ->Int32Value(env.local())
3505 : .FromJust());
3506 12 : CHECK_EQ(1u,
3507 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3508 :
3509 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3510 12 : CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3511 12 : CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3512 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3513 12 : CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3514 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3515 : .ToLocalChecked()
3516 : ->Int32Value(env.local())
3517 : .FromJust());
3518 12 : CHECK_EQ(1u,
3519 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3520 :
3521 : // Private properties are not inherited (for the time being).
3522 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3523 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3524 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3525 12 : CHECK_EQ(0u,
3526 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3527 6 : }
3528 :
3529 :
3530 28343 : THREADED_TEST(GlobalSymbols) {
3531 6 : LocalContext env;
3532 6 : v8::Isolate* isolate = env->GetIsolate();
3533 12 : v8::HandleScope scope(isolate);
3534 :
3535 6 : v8::Local<String> name = v8_str("my-symbol");
3536 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3537 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3538 6 : CHECK(glob2->SameValue(glob));
3539 :
3540 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3541 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3542 6 : CHECK(glob_api2->SameValue(glob_api));
3543 6 : CHECK(!glob_api->SameValue(glob));
3544 :
3545 6 : v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3546 6 : CHECK(!sym->SameValue(glob));
3547 :
3548 : CompileRun("var sym2 = Symbol.for('my-symbol')");
3549 : v8::Local<Value> sym2 =
3550 30 : env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3551 6 : CHECK(sym2->SameValue(glob));
3552 12 : CHECK(!sym2->SameValue(glob_api));
3553 6 : }
3554 :
3555 28343 : THREADED_TEST(GlobalSymbolsNoContext) {
3556 6 : v8::Isolate* isolate = CcTest::isolate();
3557 6 : v8::HandleScope scope(isolate);
3558 :
3559 6 : v8::Local<String> name = v8_str("my-symbol");
3560 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3561 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3562 6 : CHECK(glob2->SameValue(glob));
3563 :
3564 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3565 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3566 6 : CHECK(glob_api2->SameValue(glob_api));
3567 6 : CHECK(!glob_api->SameValue(glob));
3568 6 : }
3569 :
3570 60 : static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3571 : const char* name) {
3572 60 : LocalContext env;
3573 60 : v8::Isolate* isolate = env->GetIsolate();
3574 120 : v8::HandleScope scope(isolate);
3575 :
3576 60 : v8::Local<v8::Symbol> symbol = getter(isolate);
3577 120 : std::string script = std::string("var sym = ") + name;
3578 : CompileRun(script.c_str());
3579 : v8::Local<Value> value =
3580 300 : env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3581 :
3582 60 : CHECK(!value.IsEmpty());
3583 60 : CHECK(!symbol.IsEmpty());
3584 120 : CHECK(value->SameValue(symbol));
3585 60 : }
3586 :
3587 :
3588 28343 : THREADED_TEST(WellKnownSymbols) {
3589 6 : CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3590 6 : CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3591 6 : CheckWellKnownSymbol(v8::Symbol::GetHasInstance, "Symbol.hasInstance");
3592 : CheckWellKnownSymbol(v8::Symbol::GetIsConcatSpreadable,
3593 6 : "Symbol.isConcatSpreadable");
3594 6 : CheckWellKnownSymbol(v8::Symbol::GetMatch, "Symbol.match");
3595 6 : CheckWellKnownSymbol(v8::Symbol::GetReplace, "Symbol.replace");
3596 6 : CheckWellKnownSymbol(v8::Symbol::GetSearch, "Symbol.search");
3597 6 : CheckWellKnownSymbol(v8::Symbol::GetSplit, "Symbol.split");
3598 6 : CheckWellKnownSymbol(v8::Symbol::GetToPrimitive, "Symbol.toPrimitive");
3599 6 : CheckWellKnownSymbol(v8::Symbol::GetToStringTag, "Symbol.toStringTag");
3600 6 : }
3601 :
3602 :
3603 28343 : THREADED_TEST(GlobalPrivates) {
3604 6 : i::FLAG_allow_natives_syntax = true;
3605 6 : LocalContext env;
3606 6 : v8::Isolate* isolate = env->GetIsolate();
3607 12 : v8::HandleScope scope(isolate);
3608 :
3609 6 : v8::Local<String> name = v8_str("my-private");
3610 6 : v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3611 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3612 18 : CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3613 : .FromJust());
3614 :
3615 6 : v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3616 12 : CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3617 :
3618 6 : v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3619 12 : CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3620 :
3621 : CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3622 : v8::Local<Value> intern =
3623 30 : env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3624 18 : CHECK(!obj->Has(env.local(), intern).FromJust());
3625 6 : }
3626 :
3627 :
3628 : class ScopedArrayBufferContents {
3629 : public:
3630 : explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3631 36 : : contents_(contents) {}
3632 36 : ~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
3633 : void* Data() const { return contents_.Data(); }
3634 : size_t ByteLength() const { return contents_.ByteLength(); }
3635 :
3636 : void* AllocationBase() const { return contents_.AllocationBase(); }
3637 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3638 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3639 : return contents_.AllocationMode();
3640 : }
3641 :
3642 : private:
3643 : const v8::ArrayBuffer::Contents contents_;
3644 : };
3645 :
3646 : template <typename T>
3647 282 : static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3648 282 : CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3649 564 : for (int i = 0; i < value->InternalFieldCount(); i++) {
3650 1692 : CHECK_EQ(0, value->GetInternalField(i)
3651 : ->Int32Value(CcTest::isolate()->GetCurrentContext())
3652 : .FromJust());
3653 : }
3654 282 : }
3655 :
3656 :
3657 28343 : THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3658 6 : LocalContext env;
3659 6 : v8::Isolate* isolate = env->GetIsolate();
3660 12 : v8::HandleScope handle_scope(isolate);
3661 :
3662 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3663 6 : CheckInternalFieldsAreZero(ab);
3664 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3665 6 : CHECK(!ab->IsExternal());
3666 6 : CcTest::CollectAllGarbage();
3667 :
3668 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3669 6 : CHECK(ab->IsExternal());
3670 :
3671 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3672 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3673 6 : CHECK_NOT_NULL(data);
3674 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3675 :
3676 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3677 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3678 :
3679 : result = CompileRun(
3680 : "var u8 = new Uint8Array(ab);"
3681 : "u8[0] = 0xFF;"
3682 : "u8[1] = 0xAA;"
3683 : "u8.length");
3684 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3685 12 : CHECK_EQ(0xFF, data[0]);
3686 12 : CHECK_EQ(0xAA, data[1]);
3687 6 : data[0] = 0xCC;
3688 6 : data[1] = 0x11;
3689 : result = CompileRun("u8[0] + u8[1]");
3690 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3691 6 : }
3692 :
3693 :
3694 28343 : THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3695 6 : LocalContext env;
3696 6 : v8::Isolate* isolate = env->GetIsolate();
3697 12 : v8::HandleScope handle_scope(isolate);
3698 :
3699 :
3700 : v8::Local<v8::Value> result = CompileRun(
3701 : "var ab1 = new ArrayBuffer(2);"
3702 : "var u8_a = new Uint8Array(ab1);"
3703 : "u8_a[0] = 0xAA;"
3704 : "u8_a[1] = 0xFF; u8_a.buffer");
3705 : Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3706 6 : CheckInternalFieldsAreZero(ab1);
3707 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3708 6 : CHECK(!ab1->IsExternal());
3709 12 : ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3710 6 : CHECK(ab1->IsExternal());
3711 :
3712 : result = CompileRun("ab1.byteLength");
3713 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3714 : result = CompileRun("u8_a[0]");
3715 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3716 : result = CompileRun("u8_a[1]");
3717 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3718 : result = CompileRun(
3719 : "var u8_b = new Uint8Array(ab1);"
3720 : "u8_b[0] = 0xBB;"
3721 : "u8_a[0]");
3722 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3723 : result = CompileRun("u8_b[1]");
3724 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3725 :
3726 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3727 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3728 12 : CHECK_EQ(0xBB, ab1_data[0]);
3729 12 : CHECK_EQ(0xFF, ab1_data[1]);
3730 6 : ab1_data[0] = 0xCC;
3731 6 : ab1_data[1] = 0x11;
3732 : result = CompileRun("u8_a[0] + u8_a[1]");
3733 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3734 6 : }
3735 :
3736 :
3737 28343 : THREADED_TEST(ArrayBuffer_External) {
3738 6 : LocalContext env;
3739 6 : v8::Isolate* isolate = env->GetIsolate();
3740 12 : v8::HandleScope handle_scope(isolate);
3741 :
3742 : i::ScopedVector<uint8_t> my_data(100);
3743 : memset(my_data.start(), 0, 100);
3744 : Local<v8::ArrayBuffer> ab3 =
3745 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3746 6 : CheckInternalFieldsAreZero(ab3);
3747 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3748 6 : CHECK(ab3->IsExternal());
3749 :
3750 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3751 :
3752 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3753 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3754 :
3755 : result = CompileRun(
3756 : "var u8_b = new Uint8Array(ab3);"
3757 : "u8_b[0] = 0xBB;"
3758 : "u8_b[1] = 0xCC;"
3759 : "u8_b.length");
3760 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3761 12 : CHECK_EQ(0xBB, my_data[0]);
3762 12 : CHECK_EQ(0xCC, my_data[1]);
3763 6 : my_data[0] = 0xCC;
3764 6 : my_data[1] = 0x11;
3765 : result = CompileRun("u8_b[0] + u8_b[1]");
3766 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3767 6 : }
3768 :
3769 28343 : THREADED_TEST(ArrayBuffer_DisableDetach) {
3770 6 : LocalContext env;
3771 6 : v8::Isolate* isolate = env->GetIsolate();
3772 12 : v8::HandleScope handle_scope(isolate);
3773 :
3774 : i::ScopedVector<uint8_t> my_data(100);
3775 : memset(my_data.start(), 0, 100);
3776 : Local<v8::ArrayBuffer> ab =
3777 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3778 6 : CHECK(ab->IsDetachable());
3779 :
3780 : i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3781 : buf->set_is_detachable(false);
3782 :
3783 12 : CHECK(!ab->IsDetachable());
3784 6 : }
3785 :
3786 12 : static void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
3787 12 : CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3788 12 : CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3789 12 : }
3790 :
3791 108 : static void CheckIsDetached(v8::Local<v8::TypedArray> ta) {
3792 108 : CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3793 108 : CHECK_EQ(0, static_cast<int>(ta->Length()));
3794 108 : CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3795 108 : }
3796 :
3797 54 : static void CheckIsTypedArrayVarDetached(const char* name) {
3798 : i::ScopedVector<char> source(1024);
3799 : i::SNPrintF(source,
3800 : "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3801 54 : name, name, name);
3802 54 : CHECK(CompileRun(source.start())->IsTrue());
3803 : v8::Local<v8::TypedArray> ta =
3804 54 : v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3805 54 : CheckIsDetached(ta);
3806 54 : }
3807 :
3808 : template <typename TypedArray, int kElementSize>
3809 54 : static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3810 : int byteOffset, int length) {
3811 54 : v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3812 54 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3813 54 : CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3814 54 : CHECK_EQ(length, static_cast<int>(ta->Length()));
3815 54 : CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3816 54 : return ta;
3817 : }
3818 :
3819 28343 : THREADED_TEST(ArrayBuffer_DetachingApi) {
3820 6 : LocalContext env;
3821 6 : v8::Isolate* isolate = env->GetIsolate();
3822 12 : v8::HandleScope handle_scope(isolate);
3823 :
3824 6 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3825 :
3826 : v8::Local<v8::Uint8Array> u8a =
3827 6 : CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3828 : v8::Local<v8::Uint8ClampedArray> u8c =
3829 6 : CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3830 : v8::Local<v8::Int8Array> i8a =
3831 6 : CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3832 :
3833 : v8::Local<v8::Uint16Array> u16a =
3834 6 : CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3835 : v8::Local<v8::Int16Array> i16a =
3836 6 : CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3837 :
3838 : v8::Local<v8::Uint32Array> u32a =
3839 6 : CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3840 : v8::Local<v8::Int32Array> i32a =
3841 6 : CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3842 :
3843 : v8::Local<v8::Float32Array> f32a =
3844 6 : CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3845 : v8::Local<v8::Float64Array> f64a =
3846 6 : CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3847 :
3848 6 : v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3849 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3850 6 : CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3851 6 : CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3852 :
3853 12 : ScopedArrayBufferContents contents(buffer->Externalize());
3854 6 : buffer->Detach();
3855 6 : CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3856 6 : CheckIsDetached(u8a);
3857 6 : CheckIsDetached(u8c);
3858 6 : CheckIsDetached(i8a);
3859 6 : CheckIsDetached(u16a);
3860 6 : CheckIsDetached(i16a);
3861 6 : CheckIsDetached(u32a);
3862 6 : CheckIsDetached(i32a);
3863 6 : CheckIsDetached(f32a);
3864 6 : CheckIsDetached(f64a);
3865 12 : CheckDataViewIsDetached(dv);
3866 6 : }
3867 :
3868 28343 : THREADED_TEST(ArrayBuffer_DetachingScript) {
3869 6 : LocalContext env;
3870 6 : v8::Isolate* isolate = env->GetIsolate();
3871 12 : v8::HandleScope handle_scope(isolate);
3872 :
3873 : CompileRun(
3874 : "var ab = new ArrayBuffer(1024);"
3875 : "var u8a = new Uint8Array(ab, 1, 1023);"
3876 : "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3877 : "var i8a = new Int8Array(ab, 1, 1023);"
3878 : "var u16a = new Uint16Array(ab, 2, 511);"
3879 : "var i16a = new Int16Array(ab, 2, 511);"
3880 : "var u32a = new Uint32Array(ab, 4, 255);"
3881 : "var i32a = new Int32Array(ab, 4, 255);"
3882 : "var f32a = new Float32Array(ab, 4, 255);"
3883 : "var f64a = new Float64Array(ab, 8, 127);"
3884 : "var dv = new DataView(ab, 1, 1023);");
3885 :
3886 : v8::Local<v8::ArrayBuffer> ab =
3887 : Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3888 :
3889 6 : v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3890 :
3891 12 : ScopedArrayBufferContents contents(ab->Externalize());
3892 6 : ab->Detach();
3893 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3894 6 : CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3895 :
3896 6 : CheckIsTypedArrayVarDetached("u8a");
3897 6 : CheckIsTypedArrayVarDetached("u8c");
3898 6 : CheckIsTypedArrayVarDetached("i8a");
3899 6 : CheckIsTypedArrayVarDetached("u16a");
3900 6 : CheckIsTypedArrayVarDetached("i16a");
3901 6 : CheckIsTypedArrayVarDetached("u32a");
3902 6 : CheckIsTypedArrayVarDetached("i32a");
3903 6 : CheckIsTypedArrayVarDetached("f32a");
3904 6 : CheckIsTypedArrayVarDetached("f64a");
3905 :
3906 6 : CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3907 12 : CheckDataViewIsDetached(dv);
3908 6 : }
3909 :
3910 28343 : THREADED_TEST(ArrayBuffer_AllocationInformation) {
3911 6 : LocalContext env;
3912 6 : v8::Isolate* isolate = env->GetIsolate();
3913 12 : v8::HandleScope handle_scope(isolate);
3914 :
3915 : const size_t ab_size = 1024;
3916 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
3917 12 : ScopedArrayBufferContents contents(ab->Externalize());
3918 :
3919 : // Array buffers should have normal allocation mode.
3920 6 : CHECK_EQ(contents.AllocationMode(),
3921 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
3922 : // The allocation must contain the buffer (normally they will be equal, but
3923 : // this is not required by the contract).
3924 6 : CHECK_NOT_NULL(contents.AllocationBase());
3925 : const uintptr_t alloc =
3926 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
3927 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
3928 6 : CHECK_LE(alloc, data);
3929 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
3930 6 : }
3931 :
3932 28343 : THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
3933 6 : LocalContext env;
3934 6 : v8::Isolate* isolate = env->GetIsolate();
3935 12 : v8::HandleScope handle_scope(isolate);
3936 :
3937 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 0);
3938 6 : CheckInternalFieldsAreZero(ab);
3939 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3940 6 : CHECK(!ab->IsExternal());
3941 :
3942 : // Externalize the buffer (taking ownership of the backing store memory).
3943 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3944 :
3945 6 : Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0);
3946 : // Calling Buffer() will materialize the ArrayBuffer (transitioning it from
3947 : // on-heap to off-heap if need be). This should not affect whether it is
3948 : // marked as is_external or not.
3949 6 : USE(u8a->Buffer());
3950 :
3951 12 : CHECK(ab->IsExternal());
3952 6 : }
3953 :
3954 : class ScopedSharedArrayBufferContents {
3955 : public:
3956 : explicit ScopedSharedArrayBufferContents(
3957 : const v8::SharedArrayBuffer::Contents& contents)
3958 18 : : contents_(contents) {}
3959 18 : ~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
3960 : void* Data() const { return contents_.Data(); }
3961 : size_t ByteLength() const { return contents_.ByteLength(); }
3962 :
3963 : void* AllocationBase() const { return contents_.AllocationBase(); }
3964 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3965 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3966 : return contents_.AllocationMode();
3967 : }
3968 :
3969 : private:
3970 : const v8::SharedArrayBuffer::Contents contents_;
3971 : };
3972 :
3973 :
3974 28343 : THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
3975 6 : i::FLAG_harmony_sharedarraybuffer = true;
3976 6 : LocalContext env;
3977 6 : v8::Isolate* isolate = env->GetIsolate();
3978 12 : v8::HandleScope handle_scope(isolate);
3979 :
3980 6 : Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
3981 6 : CheckInternalFieldsAreZero(ab);
3982 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3983 6 : CHECK(!ab->IsExternal());
3984 6 : CcTest::CollectAllGarbage();
3985 :
3986 12 : ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
3987 6 : CHECK(ab->IsExternal());
3988 :
3989 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3990 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3991 6 : CHECK_NOT_NULL(data);
3992 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3993 :
3994 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3995 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3996 :
3997 : result = CompileRun(
3998 : "var u8 = new Uint8Array(ab);"
3999 : "u8[0] = 0xFF;"
4000 : "u8[1] = 0xAA;"
4001 : "u8.length");
4002 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4003 12 : CHECK_EQ(0xFF, data[0]);
4004 12 : CHECK_EQ(0xAA, data[1]);
4005 6 : data[0] = 0xCC;
4006 6 : data[1] = 0x11;
4007 : result = CompileRun("u8[0] + u8[1]");
4008 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4009 6 : }
4010 :
4011 :
4012 28343 : THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
4013 6 : i::FLAG_harmony_sharedarraybuffer = true;
4014 6 : LocalContext env;
4015 6 : v8::Isolate* isolate = env->GetIsolate();
4016 12 : v8::HandleScope handle_scope(isolate);
4017 :
4018 :
4019 : v8::Local<v8::Value> result = CompileRun(
4020 : "var ab1 = new SharedArrayBuffer(2);"
4021 : "var u8_a = new Uint8Array(ab1);"
4022 : "u8_a[0] = 0xAA;"
4023 : "u8_a[1] = 0xFF; u8_a.buffer");
4024 : Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
4025 6 : CheckInternalFieldsAreZero(ab1);
4026 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
4027 6 : CHECK(!ab1->IsExternal());
4028 12 : ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
4029 6 : CHECK(ab1->IsExternal());
4030 :
4031 : result = CompileRun("ab1.byteLength");
4032 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
4033 : result = CompileRun("u8_a[0]");
4034 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
4035 : result = CompileRun("u8_a[1]");
4036 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4037 : result = CompileRun(
4038 : "var u8_b = new Uint8Array(ab1);"
4039 : "u8_b[0] = 0xBB;"
4040 : "u8_a[0]");
4041 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
4042 : result = CompileRun("u8_b[1]");
4043 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4044 :
4045 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
4046 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
4047 12 : CHECK_EQ(0xBB, ab1_data[0]);
4048 12 : CHECK_EQ(0xFF, ab1_data[1]);
4049 6 : ab1_data[0] = 0xCC;
4050 6 : ab1_data[1] = 0x11;
4051 : result = CompileRun("u8_a[0] + u8_a[1]");
4052 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4053 6 : }
4054 :
4055 :
4056 28343 : THREADED_TEST(SharedArrayBuffer_External) {
4057 6 : i::FLAG_harmony_sharedarraybuffer = true;
4058 6 : LocalContext env;
4059 6 : v8::Isolate* isolate = env->GetIsolate();
4060 12 : v8::HandleScope handle_scope(isolate);
4061 :
4062 : i::ScopedVector<uint8_t> my_data(100);
4063 : memset(my_data.start(), 0, 100);
4064 : Local<v8::SharedArrayBuffer> ab3 =
4065 6 : v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
4066 6 : CheckInternalFieldsAreZero(ab3);
4067 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
4068 6 : CHECK(ab3->IsExternal());
4069 :
4070 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
4071 :
4072 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
4073 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4074 :
4075 : result = CompileRun(
4076 : "var u8_b = new Uint8Array(ab3);"
4077 : "u8_b[0] = 0xBB;"
4078 : "u8_b[1] = 0xCC;"
4079 : "u8_b.length");
4080 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4081 12 : CHECK_EQ(0xBB, my_data[0]);
4082 12 : CHECK_EQ(0xCC, my_data[1]);
4083 6 : my_data[0] = 0xCC;
4084 6 : my_data[1] = 0x11;
4085 : result = CompileRun("u8_b[0] + u8_b[1]");
4086 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4087 6 : }
4088 :
4089 :
4090 28343 : THREADED_TEST(HiddenProperties) {
4091 6 : LocalContext env;
4092 6 : v8::Isolate* isolate = env->GetIsolate();
4093 12 : v8::HandleScope scope(isolate);
4094 :
4095 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4096 : v8::Local<v8::Private> key =
4097 6 : v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
4098 6 : v8::Local<v8::String> empty = v8_str("");
4099 6 : v8::Local<v8::String> prop_name = v8_str("prop_name");
4100 :
4101 6 : CcTest::CollectAllGarbage();
4102 :
4103 : // Make sure delete of a non-existent hidden value works
4104 12 : obj->DeletePrivate(env.local(), key).FromJust();
4105 :
4106 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
4107 : .FromJust());
4108 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
4109 : .ToLocalChecked()
4110 : ->Int32Value(env.local())
4111 : .FromJust());
4112 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4113 : .FromJust());
4114 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4115 : .ToLocalChecked()
4116 : ->Int32Value(env.local())
4117 : .FromJust());
4118 :
4119 6 : CcTest::CollectAllGarbage();
4120 :
4121 : // Make sure we do not find the hidden property.
4122 12 : CHECK(!obj->Has(env.local(), empty).FromJust());
4123 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4124 : .ToLocalChecked()
4125 : ->Int32Value(env.local())
4126 : .FromJust());
4127 12 : CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
4128 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4129 : .ToLocalChecked()
4130 : ->Int32Value(env.local())
4131 : .FromJust());
4132 18 : CHECK(
4133 : obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
4134 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4135 : .ToLocalChecked()
4136 : ->Int32Value(env.local())
4137 : .FromJust());
4138 24 : CHECK_EQ(2003, obj->Get(env.local(), empty)
4139 : .ToLocalChecked()
4140 : ->Int32Value(env.local())
4141 : .FromJust());
4142 :
4143 6 : CcTest::CollectAllGarbage();
4144 :
4145 : // Add another property and delete it afterwards to force the object in
4146 : // slow case.
4147 18 : CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
4148 : .FromJust());
4149 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4150 : .ToLocalChecked()
4151 : ->Int32Value(env.local())
4152 : .FromJust());
4153 24 : CHECK_EQ(2008, obj->Get(env.local(), prop_name)
4154 : .ToLocalChecked()
4155 : ->Int32Value(env.local())
4156 : .FromJust());
4157 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4158 : .ToLocalChecked()
4159 : ->Int32Value(env.local())
4160 : .FromJust());
4161 12 : CHECK(obj->Delete(env.local(), prop_name).FromJust());
4162 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4163 : .ToLocalChecked()
4164 : ->Int32Value(env.local())
4165 : .FromJust());
4166 :
4167 6 : CcTest::CollectAllGarbage();
4168 :
4169 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4170 : .FromJust());
4171 12 : CHECK(obj->DeletePrivate(env.local(), key).FromJust());
4172 18 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4173 6 : }
4174 :
4175 :
4176 28343 : THREADED_TEST(Regress97784) {
4177 : // Regression test for crbug.com/97784
4178 : // Messing with the Object.prototype should not have effect on
4179 : // hidden properties.
4180 6 : LocalContext env;
4181 12 : v8::HandleScope scope(env->GetIsolate());
4182 :
4183 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4184 : v8::Local<v8::Private> key =
4185 12 : v8::Private::New(env->GetIsolate(), v8_str("hidden"));
4186 :
4187 : CompileRun(
4188 : "set_called = false;"
4189 : "Object.defineProperty("
4190 : " Object.prototype,"
4191 : " 'hidden',"
4192 : " {get: function() { return 45; },"
4193 : " set: function() { set_called = true; }})");
4194 :
4195 12 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4196 : // Make sure that the getter and setter from Object.prototype is not invoked.
4197 : // If it did we would have full access to the hidden properties in
4198 : // the accessor.
4199 18 : CHECK(
4200 : obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
4201 : .FromJust());
4202 : ExpectFalse("set_called");
4203 18 : CHECK_EQ(42, obj->GetPrivate(env.local(), key)
4204 : .ToLocalChecked()
4205 : ->Int32Value(env.local())
4206 6 : .FromJust());
4207 6 : }
4208 :
4209 :
4210 28343 : THREADED_TEST(External) {
4211 6 : v8::HandleScope scope(CcTest::isolate());
4212 6 : int x = 3;
4213 6 : Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
4214 12 : LocalContext env;
4215 30 : CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
4216 : Local<Value> reext_obj = CompileRun("this.ext");
4217 : v8::Local<v8::External> reext = reext_obj.As<v8::External>();
4218 6 : int* ptr = static_cast<int*>(reext->Value());
4219 6 : CHECK_EQ(3, x);
4220 6 : *ptr = 10;
4221 6 : CHECK_EQ(x, 10);
4222 :
4223 : {
4224 : i::Handle<i::Object> obj = v8::Utils::OpenHandle(*ext);
4225 18 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4226 6 : CHECK(ext->IsExternal());
4227 6 : CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty());
4228 18 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4229 6 : CHECK(ext->IsExternal());
4230 : }
4231 :
4232 : // Make sure unaligned pointers are wrapped properly.
4233 6 : char* data = i::StrDup("0123456789");
4234 6 : Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
4235 6 : Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
4236 6 : Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
4237 6 : Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
4238 :
4239 6 : char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
4240 6 : CHECK_EQ('0', *char_ptr);
4241 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
4242 6 : CHECK_EQ('1', *char_ptr);
4243 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
4244 6 : CHECK_EQ('2', *char_ptr);
4245 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
4246 6 : CHECK_EQ('3', *char_ptr);
4247 6 : i::DeleteArray(data);
4248 6 : }
4249 :
4250 :
4251 28343 : THREADED_TEST(GlobalHandle) {
4252 6 : v8::Isolate* isolate = CcTest::isolate();
4253 : v8::Persistent<String> global;
4254 : {
4255 6 : v8::HandleScope scope(isolate);
4256 12 : global.Reset(isolate, v8_str("str"));
4257 : }
4258 : {
4259 6 : v8::HandleScope scope(isolate);
4260 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4261 : }
4262 : global.Reset();
4263 : {
4264 6 : v8::HandleScope scope(isolate);
4265 12 : global.Reset(isolate, v8_str("str"));
4266 : }
4267 : {
4268 6 : v8::HandleScope scope(isolate);
4269 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4270 : }
4271 : global.Reset();
4272 6 : }
4273 :
4274 :
4275 28343 : THREADED_TEST(ResettingGlobalHandle) {
4276 12 : v8::Isolate* isolate = CcTest::isolate();
4277 : v8::Persistent<String> global;
4278 : {
4279 6 : v8::HandleScope scope(isolate);
4280 12 : global.Reset(isolate, v8_str("str"));
4281 : }
4282 18 : v8::internal::GlobalHandles* global_handles =
4283 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4284 : int initial_handle_count = global_handles->global_handles_count();
4285 : {
4286 6 : v8::HandleScope scope(isolate);
4287 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4288 : }
4289 : {
4290 6 : v8::HandleScope scope(isolate);
4291 12 : global.Reset(isolate, v8_str("longer"));
4292 : }
4293 6 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
4294 : {
4295 6 : v8::HandleScope scope(isolate);
4296 6 : CHECK_EQ(6, v8::Local<String>::New(isolate, global)->Length());
4297 : }
4298 : global.Reset();
4299 12 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
4300 6 : }
4301 :
4302 :
4303 28343 : THREADED_TEST(ResettingGlobalHandleToEmpty) {
4304 12 : v8::Isolate* isolate = CcTest::isolate();
4305 : v8::Persistent<String> global;
4306 : {
4307 6 : v8::HandleScope scope(isolate);
4308 12 : global.Reset(isolate, v8_str("str"));
4309 : }
4310 12 : v8::internal::GlobalHandles* global_handles =
4311 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4312 : int initial_handle_count = global_handles->global_handles_count();
4313 : {
4314 6 : v8::HandleScope scope(isolate);
4315 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4316 : }
4317 : {
4318 6 : v8::HandleScope scope(isolate);
4319 : Local<String> empty;
4320 6 : global.Reset(isolate, empty);
4321 : }
4322 6 : CHECK(global.IsEmpty());
4323 12 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
4324 6 : }
4325 :
4326 :
4327 : template <class T>
4328 : static v8::Global<T> PassUnique(v8::Global<T> unique) {
4329 : return unique.Pass();
4330 : }
4331 :
4332 :
4333 : template <class T>
4334 : static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
4335 : const v8::Persistent<T>& global) {
4336 : v8::Global<String> unique(isolate, global);
4337 : return unique.Pass();
4338 : }
4339 :
4340 :
4341 28343 : THREADED_TEST(Global) {
4342 12 : v8::Isolate* isolate = CcTest::isolate();
4343 : v8::Persistent<String> global;
4344 : {
4345 6 : v8::HandleScope scope(isolate);
4346 12 : global.Reset(isolate, v8_str("str"));
4347 : }
4348 42 : v8::internal::GlobalHandles* global_handles =
4349 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4350 : int initial_handle_count = global_handles->global_handles_count();
4351 : {
4352 : v8::Global<String> unique(isolate, global);
4353 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4354 : // Test assignment via Pass
4355 : {
4356 : v8::Global<String> copy = unique.Pass();
4357 6 : CHECK(unique.IsEmpty());
4358 6 : CHECK(copy == global);
4359 6 : CHECK_EQ(initial_handle_count + 1,
4360 : global_handles->global_handles_count());
4361 : unique = copy.Pass();
4362 : }
4363 : // Test ctor via Pass
4364 : {
4365 : v8::Global<String> copy(unique.Pass());
4366 6 : CHECK(unique.IsEmpty());
4367 6 : CHECK(copy == global);
4368 6 : CHECK_EQ(initial_handle_count + 1,
4369 : global_handles->global_handles_count());
4370 : unique = copy.Pass();
4371 : }
4372 : // Test pass through function call
4373 : {
4374 : v8::Global<String> copy = PassUnique(unique.Pass());
4375 6 : CHECK(unique.IsEmpty());
4376 6 : CHECK(copy == global);
4377 6 : CHECK_EQ(initial_handle_count + 1,
4378 : global_handles->global_handles_count());
4379 : unique = copy.Pass();
4380 : }
4381 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4382 : }
4383 : // Test pass from function call
4384 : {
4385 : v8::Global<String> unique = ReturnUnique(isolate, global);
4386 6 : CHECK(unique == global);
4387 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4388 : }
4389 6 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4390 : global.Reset();
4391 6 : }
4392 :
4393 :
4394 : namespace {
4395 :
4396 : class TwoPassCallbackData;
4397 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4398 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4399 :
4400 :
4401 : class TwoPassCallbackData {
4402 : public:
4403 215 : TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4404 : : first_pass_called_(false),
4405 : second_pass_called_(false),
4406 : trigger_gc_(false),
4407 430 : instance_counter_(instance_counter) {
4408 215 : HandleScope scope(isolate);
4409 : i::ScopedVector<char> buffer(40);
4410 215 : i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4411 : auto string =
4412 : v8::String::NewFromUtf8(isolate, buffer.start(),
4413 215 : v8::NewStringType::kNormal).ToLocalChecked();
4414 : cell_.Reset(isolate, string);
4415 430 : (*instance_counter_)++;
4416 215 : }
4417 :
4418 215 : ~TwoPassCallbackData() {
4419 215 : CHECK(first_pass_called_);
4420 215 : CHECK(second_pass_called_);
4421 215 : CHECK(cell_.IsEmpty());
4422 215 : (*instance_counter_)--;
4423 215 : }
4424 :
4425 215 : void FirstPass() {
4426 215 : CHECK(!first_pass_called_);
4427 215 : CHECK(!second_pass_called_);
4428 215 : CHECK(!cell_.IsEmpty());
4429 : cell_.Reset();
4430 215 : first_pass_called_ = true;
4431 215 : }
4432 :
4433 215 : void SecondPass() {
4434 215 : CHECK(first_pass_called_);
4435 215 : CHECK(!second_pass_called_);
4436 215 : CHECK(cell_.IsEmpty());
4437 215 : second_pass_called_ = true;
4438 215 : delete this;
4439 215 : }
4440 :
4441 : void SetWeak() {
4442 : cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4443 : }
4444 :
4445 15 : void MarkTriggerGc() { trigger_gc_ = true; }
4446 : bool trigger_gc() { return trigger_gc_; }
4447 :
4448 : int* instance_counter() { return instance_counter_; }
4449 :
4450 : private:
4451 : bool first_pass_called_;
4452 : bool second_pass_called_;
4453 : bool trigger_gc_;
4454 : v8::Global<v8::String> cell_;
4455 : int* instance_counter_;
4456 : };
4457 :
4458 :
4459 445 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4460 215 : ApiTestFuzzer::Fuzz();
4461 215 : bool trigger_gc = data.GetParameter()->trigger_gc();
4462 215 : int* instance_counter = data.GetParameter()->instance_counter();
4463 215 : data.GetParameter()->SecondPass();
4464 430 : if (!trigger_gc) return;
4465 15 : auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4466 : data_2->SetWeak();
4467 15 : CcTest::CollectAllGarbage();
4468 : }
4469 :
4470 :
4471 430 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4472 215 : data.GetParameter()->FirstPass();
4473 : data.SetSecondPassCallback(SecondPassCallback);
4474 215 : }
4475 :
4476 : } // namespace
4477 :
4478 :
4479 28342 : TEST(TwoPassPhantomCallbacks) {
4480 5 : auto isolate = CcTest::isolate();
4481 : const size_t kLength = 20;
4482 5 : int instance_counter = 0;
4483 105 : for (size_t i = 0; i < kLength; ++i) {
4484 100 : auto data = new TwoPassCallbackData(isolate, &instance_counter);
4485 : data->SetWeak();
4486 : }
4487 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4488 5 : CcTest::CollectAllGarbage();
4489 5 : EmptyMessageQueues(isolate);
4490 5 : CHECK_EQ(0, instance_counter);
4491 5 : }
4492 :
4493 :
4494 28342 : TEST(TwoPassPhantomCallbacksNestedGc) {
4495 5 : auto isolate = CcTest::isolate();
4496 : const size_t kLength = 20;
4497 : TwoPassCallbackData* array[kLength];
4498 5 : int instance_counter = 0;
4499 105 : for (size_t i = 0; i < kLength; ++i) {
4500 100 : array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4501 : array[i]->SetWeak();
4502 : }
4503 5 : array[5]->MarkTriggerGc();
4504 5 : array[10]->MarkTriggerGc();
4505 5 : array[15]->MarkTriggerGc();
4506 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4507 5 : CcTest::CollectAllGarbage();
4508 5 : EmptyMessageQueues(isolate);
4509 5 : CHECK_EQ(0, instance_counter);
4510 5 : }
4511 :
4512 :
4513 : namespace {
4514 :
4515 30 : void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4516 :
4517 :
4518 20 : Local<v8::Object> NewObjectForIntKey(
4519 : v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4520 : int key) {
4521 : auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4522 20 : auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4523 20 : obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4524 20 : return obj;
4525 : }
4526 :
4527 :
4528 : template <typename K, typename V>
4529 : class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4530 : public:
4531 : typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4532 : static const v8::PersistentContainerCallbackType kCallbackType =
4533 : v8::kWeakWithInternalFields;
4534 : struct WeakCallbackDataType {
4535 : MapType* map;
4536 : K key;
4537 : };
4538 : static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4539 : Local<V> value) {
4540 25 : WeakCallbackDataType* data = new WeakCallbackDataType;
4541 25 : data->map = map;
4542 25 : data->key = key;
4543 : return data;
4544 : }
4545 : static MapType* MapFromWeakCallbackInfo(
4546 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4547 5 : return data.GetParameter()->map;
4548 : }
4549 : static K KeyFromWeakCallbackInfo(
4550 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4551 10 : return data.GetParameter()->key;
4552 : }
4553 25 : static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
4554 5 : static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4555 5 : CHECK_EQ(IntKeyToVoidPointer(key),
4556 : v8::Object::GetAlignedPointerFromInternalField(value, 0));
4557 5 : }
4558 : static void OnWeakCallback(
4559 : const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
4560 5 : static void DisposeWeak(
4561 : const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4562 : K key = KeyFromWeakCallbackInfo(info);
4563 5 : CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4564 : DisposeCallbackData(info.GetParameter());
4565 5 : }
4566 : };
4567 :
4568 :
4569 : template <typename Map>
4570 10 : void TestGlobalValueMap() {
4571 10 : LocalContext env;
4572 20 : v8::Isolate* isolate = env->GetIsolate();
4573 : v8::Global<ObjectTemplate> templ;
4574 : {
4575 10 : HandleScope scope(isolate);
4576 10 : auto t = ObjectTemplate::New(isolate);
4577 10 : t->SetInternalFieldCount(1);
4578 10 : templ.Reset(isolate, t);
4579 : }
4580 : Map map(isolate);
4581 40 : v8::internal::GlobalHandles* global_handles =
4582 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4583 : int initial_handle_count = global_handles->global_handles_count();
4584 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4585 : {
4586 10 : HandleScope scope(isolate);
4587 10 : Local<v8::Object> obj = map.Get(7);
4588 10 : CHECK(obj.IsEmpty());
4589 10 : Local<v8::Object> expected = v8::Object::New(isolate);
4590 20 : map.Set(7, expected);
4591 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4592 10 : obj = map.Get(7);
4593 20 : CHECK(expected->Equals(env.local(), obj).FromJust());
4594 : {
4595 10 : typename Map::PersistentValueReference ref = map.GetReference(7);
4596 20 : CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4597 : }
4598 5 : v8::Global<v8::Object> removed = map.Remove(7);
4599 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4600 10 : CHECK(expected == removed);
4601 10 : removed = map.Remove(7);
4602 10 : CHECK(removed.IsEmpty());
4603 20 : map.Set(8, expected);
4604 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4605 20 : map.Set(8, expected);
4606 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4607 : {
4608 : typename Map::PersistentValueReference ref;
4609 10 : Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4610 30 : removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4611 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4612 10 : CHECK(expected == removed);
4613 20 : CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4614 10 : }
4615 : }
4616 10 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4617 : if (map.IsWeak()) {
4618 5 : CcTest::PreciseCollectAllGarbage();
4619 : } else {
4620 5 : map.Clear();
4621 : }
4622 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4623 10 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4624 : {
4625 10 : HandleScope scope(isolate);
4626 10 : Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4627 20 : map.Set(9, value);
4628 10 : map.Clear();
4629 : }
4630 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4631 20 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4632 10 : }
4633 :
4634 : } // namespace
4635 :
4636 :
4637 28342 : TEST(GlobalValueMap) {
4638 : // Default case, w/o weak callbacks:
4639 5 : TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4640 :
4641 : // Custom traits with weak callbacks:
4642 : typedef v8::GlobalValueMap<int, v8::Object,
4643 : PhantomStdMapTraits<int, v8::Object>> WeakMap;
4644 5 : TestGlobalValueMap<WeakMap>();
4645 5 : }
4646 :
4647 :
4648 28342 : TEST(PersistentValueVector) {
4649 5 : LocalContext env;
4650 5 : v8::Isolate* isolate = env->GetIsolate();
4651 15 : v8::internal::GlobalHandles* global_handles =
4652 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4653 : int handle_count = global_handles->global_handles_count();
4654 10 : HandleScope scope(isolate);
4655 :
4656 5 : v8::PersistentValueVector<v8::Object> vector(isolate);
4657 :
4658 5 : Local<v8::Object> obj1 = v8::Object::New(isolate);
4659 5 : Local<v8::Object> obj2 = v8::Object::New(isolate);
4660 5 : v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4661 :
4662 5 : CHECK(vector.IsEmpty());
4663 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4664 :
4665 : vector.ReserveCapacity(3);
4666 5 : CHECK(vector.IsEmpty());
4667 :
4668 5 : vector.Append(obj1);
4669 5 : vector.Append(obj2);
4670 5 : vector.Append(obj1);
4671 : vector.Append(obj3.Pass());
4672 5 : vector.Append(obj1);
4673 :
4674 5 : CHECK(!vector.IsEmpty());
4675 5 : CHECK_EQ(5, static_cast<int>(vector.Size()));
4676 5 : CHECK(obj3.IsEmpty());
4677 15 : CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4678 15 : CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4679 15 : CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4680 20 : CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4681 :
4682 5 : CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4683 :
4684 5 : vector.Clear();
4685 5 : CHECK(vector.IsEmpty());
4686 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4687 10 : CHECK_EQ(handle_count, global_handles->global_handles_count());
4688 5 : }
4689 :
4690 :
4691 28343 : THREADED_TEST(GlobalHandleUpcast) {
4692 6 : v8::Isolate* isolate = CcTest::isolate();
4693 6 : v8::HandleScope scope(isolate);
4694 6 : v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4695 : v8::Persistent<String> global_string(isolate, local);
4696 : v8::Persistent<Value>& global_value =
4697 : v8::Persistent<Value>::Cast(global_string);
4698 6 : CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4699 6 : CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4700 6 : global_string.Reset();
4701 6 : }
4702 :
4703 :
4704 28343 : THREADED_TEST(HandleEquality) {
4705 6 : v8::Isolate* isolate = CcTest::isolate();
4706 : v8::Persistent<String> global1;
4707 : v8::Persistent<String> global2;
4708 : {
4709 6 : v8::HandleScope scope(isolate);
4710 12 : global1.Reset(isolate, v8_str("str"));
4711 12 : global2.Reset(isolate, v8_str("str2"));
4712 : }
4713 6 : CHECK(global1 == global1);
4714 6 : CHECK(!(global1 != global1));
4715 : {
4716 6 : v8::HandleScope scope(isolate);
4717 : Local<String> local1 = Local<String>::New(isolate, global1);
4718 : Local<String> local2 = Local<String>::New(isolate, global2);
4719 :
4720 6 : CHECK(global1 == local1);
4721 6 : CHECK(!(global1 != local1));
4722 6 : CHECK(local1 == global1);
4723 6 : CHECK(!(local1 != global1));
4724 :
4725 6 : CHECK(!(global1 == local2));
4726 6 : CHECK(global1 != local2);
4727 6 : CHECK(!(local2 == global1));
4728 6 : CHECK(local2 != global1);
4729 :
4730 6 : CHECK(!(local1 == local2));
4731 6 : CHECK(local1 != local2);
4732 :
4733 : Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4734 6 : CHECK(local1 == anotherLocal1);
4735 6 : CHECK(!(local1 != anotherLocal1));
4736 : }
4737 : global1.Reset();
4738 : global2.Reset();
4739 6 : }
4740 :
4741 :
4742 28343 : THREADED_TEST(LocalHandle) {
4743 6 : v8::HandleScope scope(CcTest::isolate());
4744 : v8::Local<String> local =
4745 6 : v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4746 6 : CHECK_EQ(3, local->Length());
4747 6 : }
4748 :
4749 :
4750 : class WeakCallCounter {
4751 : public:
4752 5 : explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
4753 : int id() { return id_; }
4754 10 : void increment() { number_of_weak_calls_++; }
4755 : int NumberOfWeakCalls() { return number_of_weak_calls_; }
4756 :
4757 : private:
4758 : int id_;
4759 : int number_of_weak_calls_;
4760 : };
4761 :
4762 :
4763 : template <typename T>
4764 : struct WeakCallCounterAndPersistent {
4765 : explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4766 10 : : counter(counter) {}
4767 : WeakCallCounter* counter;
4768 : v8::Persistent<T> handle;
4769 : };
4770 :
4771 :
4772 : template <typename T>
4773 10 : static void WeakPointerCallback(
4774 20 : const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4775 10 : CHECK_EQ(1234, data.GetParameter()->counter->id());
4776 : data.GetParameter()->counter->increment();
4777 : data.GetParameter()->handle.Reset();
4778 10 : }
4779 :
4780 28343 : THREADED_TEST(ScriptException) {
4781 6 : LocalContext env;
4782 12 : v8::HandleScope scope(env->GetIsolate());
4783 : Local<Script> script = v8_compile("throw 'panama!';");
4784 12 : v8::TryCatch try_catch(env->GetIsolate());
4785 6 : v8::MaybeLocal<Value> result = script->Run(env.local());
4786 6 : CHECK(result.IsEmpty());
4787 6 : CHECK(try_catch.HasCaught());
4788 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
4789 12 : CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4790 6 : }
4791 :
4792 :
4793 28342 : TEST(TryCatchCustomException) {
4794 5 : LocalContext env;
4795 5 : v8::Isolate* isolate = env->GetIsolate();
4796 10 : v8::HandleScope scope(isolate);
4797 10 : v8::TryCatch try_catch(isolate);
4798 : CompileRun(
4799 : "function CustomError() { this.a = 'b'; }"
4800 : "(function f() { throw new CustomError(); })();");
4801 5 : CHECK(try_catch.HasCaught());
4802 35 : CHECK(try_catch.Exception()
4803 : ->ToObject(env.local())
4804 : .ToLocalChecked()
4805 : ->Get(env.local(), v8_str("a"))
4806 : .ToLocalChecked()
4807 : ->Equals(env.local(), v8_str("b"))
4808 5 : .FromJust());
4809 5 : }
4810 :
4811 :
4812 : bool message_received;
4813 :
4814 :
4815 6 : static void check_message_0(v8::Local<v8::Message> message,
4816 : v8::Local<Value> data) {
4817 18 : CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4818 : .FromJust());
4819 12 : CHECK_EQ(6.75, message->GetScriptOrigin()
4820 : .ResourceName()
4821 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4822 : .FromJust());
4823 6 : CHECK(!message->IsSharedCrossOrigin());
4824 6 : message_received = true;
4825 6 : }
4826 :
4827 :
4828 28343 : THREADED_TEST(MessageHandler0) {
4829 6 : message_received = false;
4830 6 : v8::HandleScope scope(CcTest::isolate());
4831 6 : CHECK(!message_received);
4832 12 : LocalContext context;
4833 6 : CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4834 6 : v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4835 18 : CHECK(script->Run(context.local()).IsEmpty());
4836 6 : CHECK(message_received);
4837 : // clear out the message listener
4838 12 : CcTest::isolate()->RemoveMessageListeners(check_message_0);
4839 6 : }
4840 :
4841 :
4842 5 : static void check_message_1(v8::Local<v8::Message> message,
4843 : v8::Local<Value> data) {
4844 5 : CHECK(data->IsNumber());
4845 10 : CHECK_EQ(1337,
4846 : data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4847 5 : CHECK(!message->IsSharedCrossOrigin());
4848 5 : message_received = true;
4849 5 : }
4850 :
4851 :
4852 28342 : TEST(MessageHandler1) {
4853 5 : message_received = false;
4854 5 : v8::HandleScope scope(CcTest::isolate());
4855 5 : CHECK(!message_received);
4856 5 : CcTest::isolate()->AddMessageListener(check_message_1);
4857 10 : LocalContext context;
4858 : CompileRun("throw 1337;");
4859 5 : CHECK(message_received);
4860 : // clear out the message listener
4861 10 : CcTest::isolate()->RemoveMessageListeners(check_message_1);
4862 5 : }
4863 :
4864 :
4865 5 : static void check_message_2(v8::Local<v8::Message> message,
4866 : v8::Local<Value> data) {
4867 5 : LocalContext context;
4868 5 : CHECK(data->IsObject());
4869 : v8::Local<v8::Value> hidden_property =
4870 : v8::Object::Cast(*data)
4871 : ->GetPrivate(
4872 : context.local(),
4873 5 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4874 10 : .ToLocalChecked();
4875 15 : CHECK(v8_str("hidden value")
4876 : ->Equals(context.local(), hidden_property)
4877 : .FromJust());
4878 5 : CHECK(!message->IsSharedCrossOrigin());
4879 5 : message_received = true;
4880 5 : }
4881 :
4882 :
4883 28342 : TEST(MessageHandler2) {
4884 5 : message_received = false;
4885 5 : v8::HandleScope scope(CcTest::isolate());
4886 5 : CHECK(!message_received);
4887 5 : CcTest::isolate()->AddMessageListener(check_message_2);
4888 10 : LocalContext context;
4889 5 : v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4890 : v8::Object::Cast(*error)
4891 : ->SetPrivate(context.local(),
4892 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4893 15 : v8_str("hidden value"))
4894 10 : .FromJust();
4895 25 : CHECK(context->Global()
4896 : ->Set(context.local(), v8_str("error"), error)
4897 : .FromJust());
4898 : CompileRun("throw error;");
4899 5 : CHECK(message_received);
4900 : // clear out the message listener
4901 10 : CcTest::isolate()->RemoveMessageListeners(check_message_2);
4902 5 : }
4903 :
4904 :
4905 5 : static void check_message_3(v8::Local<v8::Message> message,
4906 : v8::Local<Value> data) {
4907 5 : CHECK(message->IsSharedCrossOrigin());
4908 10 : CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4909 10 : CHECK(message->GetScriptOrigin().Options().IsOpaque());
4910 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4911 : .ResourceName()
4912 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4913 : .FromJust());
4914 10 : CHECK_EQ(7.40, message->GetScriptOrigin()
4915 : .SourceMapUrl()
4916 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4917 : .FromJust());
4918 5 : message_received = true;
4919 5 : }
4920 :
4921 :
4922 28342 : TEST(MessageHandler3) {
4923 5 : message_received = false;
4924 5 : v8::Isolate* isolate = CcTest::isolate();
4925 5 : v8::HandleScope scope(isolate);
4926 5 : CHECK(!message_received);
4927 5 : isolate->AddMessageListener(check_message_3);
4928 10 : LocalContext context;
4929 : v8::ScriptOrigin origin =
4930 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4931 : v8::Integer::New(isolate, 2), v8::True(isolate),
4932 5 : Local<v8::Integer>(), v8_str("7.40"), v8::True(isolate));
4933 : v8::Local<v8::Script> script =
4934 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4935 5 : .ToLocalChecked();
4936 10 : CHECK(script->Run(context.local()).IsEmpty());
4937 5 : CHECK(message_received);
4938 : // clear out the message listener
4939 10 : isolate->RemoveMessageListeners(check_message_3);
4940 5 : }
4941 :
4942 :
4943 5 : static void check_message_4(v8::Local<v8::Message> message,
4944 : v8::Local<Value> data) {
4945 5 : CHECK(!message->IsSharedCrossOrigin());
4946 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4947 : .ResourceName()
4948 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4949 : .FromJust());
4950 5 : message_received = true;
4951 5 : }
4952 :
4953 :
4954 28342 : TEST(MessageHandler4) {
4955 5 : message_received = false;
4956 5 : v8::Isolate* isolate = CcTest::isolate();
4957 5 : v8::HandleScope scope(isolate);
4958 5 : CHECK(!message_received);
4959 5 : isolate->AddMessageListener(check_message_4);
4960 10 : LocalContext context;
4961 : v8::ScriptOrigin origin =
4962 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4963 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
4964 : v8::Local<v8::Script> script =
4965 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4966 5 : .ToLocalChecked();
4967 10 : CHECK(script->Run(context.local()).IsEmpty());
4968 5 : CHECK(message_received);
4969 : // clear out the message listener
4970 10 : isolate->RemoveMessageListeners(check_message_4);
4971 5 : }
4972 :
4973 :
4974 5 : static void check_message_5a(v8::Local<v8::Message> message,
4975 : v8::Local<Value> data) {
4976 5 : CHECK(message->IsSharedCrossOrigin());
4977 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4978 : .ResourceName()
4979 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4980 : .FromJust());
4981 5 : message_received = true;
4982 5 : }
4983 :
4984 :
4985 5 : static void check_message_5b(v8::Local<v8::Message> message,
4986 : v8::Local<Value> data) {
4987 5 : CHECK(!message->IsSharedCrossOrigin());
4988 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4989 : .ResourceName()
4990 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4991 : .FromJust());
4992 5 : message_received = true;
4993 5 : }
4994 :
4995 :
4996 28342 : TEST(MessageHandler5) {
4997 5 : message_received = false;
4998 5 : v8::Isolate* isolate = CcTest::isolate();
4999 5 : v8::HandleScope scope(isolate);
5000 5 : CHECK(!message_received);
5001 5 : isolate->AddMessageListener(check_message_5a);
5002 10 : LocalContext context;
5003 : v8::ScriptOrigin origin1 =
5004 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5005 5 : v8::Integer::New(isolate, 2), v8::True(isolate));
5006 : v8::Local<v8::Script> script =
5007 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
5008 5 : .ToLocalChecked();
5009 10 : CHECK(script->Run(context.local()).IsEmpty());
5010 5 : CHECK(message_received);
5011 : // clear out the message listener
5012 5 : isolate->RemoveMessageListeners(check_message_5a);
5013 :
5014 5 : message_received = false;
5015 5 : isolate->AddMessageListener(check_message_5b);
5016 : v8::ScriptOrigin origin2 =
5017 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5018 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
5019 5 : script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
5020 5 : .ToLocalChecked();
5021 10 : CHECK(script->Run(context.local()).IsEmpty());
5022 5 : CHECK(message_received);
5023 : // clear out the message listener
5024 10 : isolate->RemoveMessageListeners(check_message_5b);
5025 5 : }
5026 :
5027 :
5028 28343 : THREADED_TEST(GetSetProperty) {
5029 6 : LocalContext context;
5030 6 : v8::Isolate* isolate = context->GetIsolate();
5031 12 : v8::HandleScope scope(isolate);
5032 30 : CHECK(context->Global()
5033 : ->Set(context.local(), v8_str("foo"), v8_num(14))
5034 : .FromJust());
5035 30 : CHECK(context->Global()
5036 : ->Set(context.local(), v8_str("12"), v8_num(92))
5037 : .FromJust());
5038 30 : CHECK(context->Global()
5039 : ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
5040 : .FromJust());
5041 24 : CHECK(context->Global()
5042 : ->Set(context.local(), v8_num(13), v8_num(56))
5043 : .FromJust());
5044 : Local<Value> foo = CompileRun("this.foo");
5045 12 : CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
5046 : Local<Value> twelve = CompileRun("this[12]");
5047 12 : CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
5048 : Local<Value> sixteen = CompileRun("this[16]");
5049 12 : CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
5050 : Local<Value> thirteen = CompileRun("this[13]");
5051 12 : CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
5052 36 : CHECK_EQ(92, context->Global()
5053 : ->Get(context.local(), v8::Integer::New(isolate, 12))
5054 : .ToLocalChecked()
5055 : ->Int32Value(context.local())
5056 : .FromJust());
5057 36 : CHECK_EQ(92, context->Global()
5058 : ->Get(context.local(), v8_str("12"))
5059 : .ToLocalChecked()
5060 : ->Int32Value(context.local())
5061 : .FromJust());
5062 30 : CHECK_EQ(92, context->Global()
5063 : ->Get(context.local(), v8_num(12))
5064 : .ToLocalChecked()
5065 : ->Int32Value(context.local())
5066 : .FromJust());
5067 36 : CHECK_EQ(32, context->Global()
5068 : ->Get(context.local(), v8::Integer::New(isolate, 16))
5069 : .ToLocalChecked()
5070 : ->Int32Value(context.local())
5071 : .FromJust());
5072 36 : CHECK_EQ(32, context->Global()
5073 : ->Get(context.local(), v8_str("16"))
5074 : .ToLocalChecked()
5075 : ->Int32Value(context.local())
5076 : .FromJust());
5077 30 : CHECK_EQ(32, context->Global()
5078 : ->Get(context.local(), v8_num(16))
5079 : .ToLocalChecked()
5080 : ->Int32Value(context.local())
5081 : .FromJust());
5082 36 : CHECK_EQ(56, context->Global()
5083 : ->Get(context.local(), v8::Integer::New(isolate, 13))
5084 : .ToLocalChecked()
5085 : ->Int32Value(context.local())
5086 : .FromJust());
5087 36 : CHECK_EQ(56, context->Global()
5088 : ->Get(context.local(), v8_str("13"))
5089 : .ToLocalChecked()
5090 : ->Int32Value(context.local())
5091 : .FromJust());
5092 30 : CHECK_EQ(56, context->Global()
5093 : ->Get(context.local(), v8_num(13))
5094 : .ToLocalChecked()
5095 : ->Int32Value(context.local())
5096 6 : .FromJust());
5097 6 : }
5098 :
5099 :
5100 28343 : THREADED_TEST(PropertyAttributes) {
5101 6 : LocalContext context;
5102 12 : v8::HandleScope scope(context->GetIsolate());
5103 : // none
5104 6 : Local<String> prop = v8_str("none");
5105 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5106 24 : CHECK_EQ(v8::None, context->Global()
5107 : ->GetPropertyAttributes(context.local(), prop)
5108 : .FromJust());
5109 : // read-only
5110 6 : prop = v8_str("read_only");
5111 : context->Global()
5112 24 : ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5113 12 : .FromJust();
5114 36 : CHECK_EQ(7, context->Global()
5115 : ->Get(context.local(), prop)
5116 : .ToLocalChecked()
5117 : ->Int32Value(context.local())
5118 : .FromJust());
5119 24 : CHECK_EQ(v8::ReadOnly, context->Global()
5120 : ->GetPropertyAttributes(context.local(), prop)
5121 : .FromJust());
5122 : CompileRun("read_only = 9");
5123 36 : CHECK_EQ(7, context->Global()
5124 : ->Get(context.local(), prop)
5125 : .ToLocalChecked()
5126 : ->Int32Value(context.local())
5127 : .FromJust());
5128 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5129 36 : CHECK_EQ(7, context->Global()
5130 : ->Get(context.local(), prop)
5131 : .ToLocalChecked()
5132 : ->Int32Value(context.local())
5133 : .FromJust());
5134 : // dont-delete
5135 6 : prop = v8_str("dont_delete");
5136 : context->Global()
5137 24 : ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5138 12 : .FromJust();
5139 36 : CHECK_EQ(13, context->Global()
5140 : ->Get(context.local(), prop)
5141 : .ToLocalChecked()
5142 : ->Int32Value(context.local())
5143 : .FromJust());
5144 : CompileRun("delete dont_delete");
5145 36 : CHECK_EQ(13, context->Global()
5146 : ->Get(context.local(), prop)
5147 : .ToLocalChecked()
5148 : ->Int32Value(context.local())
5149 : .FromJust());
5150 24 : CHECK_EQ(v8::DontDelete, context->Global()
5151 : ->GetPropertyAttributes(context.local(), prop)
5152 : .FromJust());
5153 : // dont-enum
5154 6 : prop = v8_str("dont_enum");
5155 : context->Global()
5156 24 : ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5157 12 : .FromJust();
5158 24 : CHECK_EQ(v8::DontEnum, context->Global()
5159 : ->GetPropertyAttributes(context.local(), prop)
5160 : .FromJust());
5161 : // absent
5162 6 : prop = v8_str("absent");
5163 24 : CHECK_EQ(v8::None, context->Global()
5164 : ->GetPropertyAttributes(context.local(), prop)
5165 : .FromJust());
5166 6 : Local<Value> fake_prop = v8_num(1);
5167 24 : CHECK_EQ(v8::None, context->Global()
5168 : ->GetPropertyAttributes(context.local(), fake_prop)
5169 : .FromJust());
5170 : // exception
5171 12 : TryCatch try_catch(context->GetIsolate());
5172 : Local<Value> exception =
5173 6 : CompileRun("({ toString: function() { throw 'exception';} })");
5174 24 : CHECK(context->Global()
5175 : ->GetPropertyAttributes(context.local(), exception)
5176 : .IsNothing());
5177 6 : CHECK(try_catch.HasCaught());
5178 : String::Utf8Value exception_value(context->GetIsolate(),
5179 18 : try_catch.Exception());
5180 6 : CHECK_EQ(0, strcmp("exception", *exception_value));
5181 12 : try_catch.Reset();
5182 6 : }
5183 :
5184 :
5185 28343 : THREADED_TEST(Array) {
5186 6 : LocalContext context;
5187 12 : v8::HandleScope scope(context->GetIsolate());
5188 6 : Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5189 6 : CHECK_EQ(0u, array->Length());
5190 12 : CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5191 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5192 12 : CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5193 12 : CHECK(!array->Has(context.local(), 100).FromJust());
5194 12 : CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5195 6 : CHECK_EQ(3u, array->Length());
5196 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5197 12 : CHECK(!array->Has(context.local(), 1).FromJust());
5198 12 : CHECK(array->Has(context.local(), 2).FromJust());
5199 18 : CHECK_EQ(7, array->Get(context.local(), 2)
5200 : .ToLocalChecked()
5201 : ->Int32Value(context.local())
5202 : .FromJust());
5203 : Local<Value> obj = CompileRun("[1, 2, 3]");
5204 : Local<v8::Array> arr = obj.As<v8::Array>();
5205 6 : CHECK_EQ(3u, arr->Length());
5206 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5207 : .ToLocalChecked()
5208 : ->Int32Value(context.local())
5209 : .FromJust());
5210 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5211 : .ToLocalChecked()
5212 : ->Int32Value(context.local())
5213 : .FromJust());
5214 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5215 : .ToLocalChecked()
5216 : ->Int32Value(context.local())
5217 : .FromJust());
5218 6 : array = v8::Array::New(context->GetIsolate(), 27);
5219 6 : CHECK_EQ(27u, array->Length());
5220 6 : array = v8::Array::New(context->GetIsolate(), -27);
5221 6 : CHECK_EQ(0u, array->Length());
5222 :
5223 12 : std::vector<Local<Value>> vector = {v8_num(1), v8_num(2), v8_num(3)};
5224 12 : array = v8::Array::New(context->GetIsolate(), vector.data(), vector.size());
5225 12 : CHECK_EQ(vector.size(), array->Length());
5226 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5227 : .ToLocalChecked()
5228 : ->Int32Value(context.local())
5229 : .FromJust());
5230 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5231 : .ToLocalChecked()
5232 : ->Int32Value(context.local())
5233 : .FromJust());
5234 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5235 : .ToLocalChecked()
5236 : ->Int32Value(context.local())
5237 6 : .FromJust());
5238 6 : }
5239 :
5240 :
5241 180 : void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5242 30 : v8::EscapableHandleScope scope(args.GetIsolate());
5243 30 : ApiTestFuzzer::Fuzz();
5244 30 : Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5245 180 : for (int i = 0; i < args.Length(); i++) {
5246 180 : CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5247 : .FromJust());
5248 : }
5249 : args.GetReturnValue().Set(scope.Escape(result));
5250 30 : }
5251 :
5252 :
5253 28343 : THREADED_TEST(Vector) {
5254 6 : v8::Isolate* isolate = CcTest::isolate();
5255 6 : v8::HandleScope scope(isolate);
5256 6 : Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5257 18 : global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5258 12 : LocalContext context(nullptr, global);
5259 :
5260 : const char* fun = "f()";
5261 : Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5262 6 : CHECK_EQ(0u, a0->Length());
5263 :
5264 : const char* fun2 = "f(11)";
5265 : Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5266 6 : CHECK_EQ(1u, a1->Length());
5267 18 : CHECK_EQ(11, a1->Get(context.local(), 0)
5268 : .ToLocalChecked()
5269 : ->Int32Value(context.local())
5270 : .FromJust());
5271 :
5272 : const char* fun3 = "f(12, 13)";
5273 : Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5274 6 : CHECK_EQ(2u, a2->Length());
5275 18 : CHECK_EQ(12, a2->Get(context.local(), 0)
5276 : .ToLocalChecked()
5277 : ->Int32Value(context.local())
5278 : .FromJust());
5279 18 : CHECK_EQ(13, a2->Get(context.local(), 1)
5280 : .ToLocalChecked()
5281 : ->Int32Value(context.local())
5282 : .FromJust());
5283 :
5284 : const char* fun4 = "f(14, 15, 16)";
5285 : Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5286 6 : CHECK_EQ(3u, a3->Length());
5287 18 : CHECK_EQ(14, a3->Get(context.local(), 0)
5288 : .ToLocalChecked()
5289 : ->Int32Value(context.local())
5290 : .FromJust());
5291 18 : CHECK_EQ(15, a3->Get(context.local(), 1)
5292 : .ToLocalChecked()
5293 : ->Int32Value(context.local())
5294 : .FromJust());
5295 18 : CHECK_EQ(16, a3->Get(context.local(), 2)
5296 : .ToLocalChecked()
5297 : ->Int32Value(context.local())
5298 : .FromJust());
5299 :
5300 : const char* fun5 = "f(17, 18, 19, 20)";
5301 : Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5302 6 : CHECK_EQ(4u, a4->Length());
5303 18 : CHECK_EQ(17, a4->Get(context.local(), 0)
5304 : .ToLocalChecked()
5305 : ->Int32Value(context.local())
5306 : .FromJust());
5307 18 : CHECK_EQ(18, a4->Get(context.local(), 1)
5308 : .ToLocalChecked()
5309 : ->Int32Value(context.local())
5310 : .FromJust());
5311 18 : CHECK_EQ(19, a4->Get(context.local(), 2)
5312 : .ToLocalChecked()
5313 : ->Int32Value(context.local())
5314 : .FromJust());
5315 18 : CHECK_EQ(20, a4->Get(context.local(), 3)
5316 : .ToLocalChecked()
5317 : ->Int32Value(context.local())
5318 6 : .FromJust());
5319 6 : }
5320 :
5321 :
5322 28343 : THREADED_TEST(FunctionCall) {
5323 6 : LocalContext context;
5324 6 : v8::Isolate* isolate = context->GetIsolate();
5325 12 : v8::HandleScope scope(isolate);
5326 : CompileRun(
5327 : "function Foo() {"
5328 : " var result = [];"
5329 : " for (var i = 0; i < arguments.length; i++) {"
5330 : " result.push(arguments[i]);"
5331 : " }"
5332 : " return result;"
5333 : "}"
5334 : "function ReturnThisSloppy() {"
5335 : " return this;"
5336 : "}"
5337 : "function ReturnThisStrict() {"
5338 : " 'use strict';"
5339 : " return this;"
5340 : "}");
5341 : Local<Function> Foo = Local<Function>::Cast(
5342 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5343 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5344 : context->Global()
5345 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
5346 6 : .ToLocalChecked());
5347 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
5348 : context->Global()
5349 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
5350 6 : .ToLocalChecked());
5351 :
5352 : v8::Local<Value>* args0 = nullptr;
5353 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5354 12 : Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5355 6 : CHECK_EQ(0u, a0->Length());
5356 :
5357 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5358 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5359 12 : Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5360 6 : CHECK_EQ(1u, a1->Length());
5361 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5362 : .ToLocalChecked()
5363 : ->NumberValue(context.local())
5364 : .FromJust());
5365 :
5366 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5367 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5368 12 : Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5369 6 : CHECK_EQ(2u, a2->Length());
5370 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5371 : .ToLocalChecked()
5372 : ->NumberValue(context.local())
5373 : .FromJust());
5374 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5375 : .ToLocalChecked()
5376 : ->NumberValue(context.local())
5377 : .FromJust());
5378 :
5379 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5380 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5381 12 : Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5382 6 : CHECK_EQ(3u, a3->Length());
5383 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5384 : .ToLocalChecked()
5385 : ->NumberValue(context.local())
5386 : .FromJust());
5387 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5388 : .ToLocalChecked()
5389 : ->NumberValue(context.local())
5390 : .FromJust());
5391 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5392 : .ToLocalChecked()
5393 : ->NumberValue(context.local())
5394 : .FromJust());
5395 :
5396 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5397 6 : v8_num(10.11)};
5398 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5399 12 : Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5400 6 : CHECK_EQ(4u, a4->Length());
5401 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5402 : .ToLocalChecked()
5403 : ->NumberValue(context.local())
5404 : .FromJust());
5405 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5406 : .ToLocalChecked()
5407 : ->NumberValue(context.local())
5408 : .FromJust());
5409 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5410 : .ToLocalChecked()
5411 : ->NumberValue(context.local())
5412 : .FromJust());
5413 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5414 : .ToLocalChecked()
5415 : ->NumberValue(context.local())
5416 : .FromJust());
5417 :
5418 : Local<v8::Value> r1 =
5419 : ReturnThisSloppy
5420 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5421 6 : .ToLocalChecked();
5422 12 : CHECK(r1->StrictEquals(context->Global()));
5423 : Local<v8::Value> r2 =
5424 12 : ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, nullptr)
5425 6 : .ToLocalChecked();
5426 12 : CHECK(r2->StrictEquals(context->Global()));
5427 : Local<v8::Value> r3 =
5428 6 : ReturnThisSloppy->Call(context.local(), v8_num(42), 0, nullptr)
5429 6 : .ToLocalChecked();
5430 6 : CHECK(r3->IsNumberObject());
5431 6 : CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5432 : Local<v8::Value> r4 =
5433 18 : ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, nullptr)
5434 6 : .ToLocalChecked();
5435 6 : CHECK(r4->IsStringObject());
5436 18 : CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5437 : Local<v8::Value> r5 =
5438 12 : ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, nullptr)
5439 6 : .ToLocalChecked();
5440 6 : CHECK(r5->IsBooleanObject());
5441 6 : CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5442 :
5443 : Local<v8::Value> r6 =
5444 : ReturnThisStrict
5445 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5446 6 : .ToLocalChecked();
5447 6 : CHECK(r6->IsUndefined());
5448 : Local<v8::Value> r7 =
5449 12 : ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, nullptr)
5450 6 : .ToLocalChecked();
5451 6 : CHECK(r7->IsNull());
5452 : Local<v8::Value> r8 =
5453 6 : ReturnThisStrict->Call(context.local(), v8_num(42), 0, nullptr)
5454 6 : .ToLocalChecked();
5455 6 : CHECK(r8->StrictEquals(v8_num(42)));
5456 : Local<v8::Value> r9 =
5457 18 : ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, nullptr)
5458 6 : .ToLocalChecked();
5459 12 : CHECK(r9->StrictEquals(v8_str("hello")));
5460 : Local<v8::Value> r10 =
5461 12 : ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, nullptr)
5462 6 : .ToLocalChecked();
5463 12 : CHECK(r10->StrictEquals(v8::True(isolate)));
5464 6 : }
5465 :
5466 :
5467 28343 : THREADED_TEST(ConstructCall) {
5468 6 : LocalContext context;
5469 6 : v8::Isolate* isolate = context->GetIsolate();
5470 12 : v8::HandleScope scope(isolate);
5471 : CompileRun(
5472 : "function Foo() {"
5473 : " var result = [];"
5474 : " for (var i = 0; i < arguments.length; i++) {"
5475 : " result.push(arguments[i]);"
5476 : " }"
5477 : " return result;"
5478 : "}");
5479 : Local<Function> Foo = Local<Function>::Cast(
5480 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5481 :
5482 : v8::Local<Value>* args0 = nullptr;
5483 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5484 6 : Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5485 6 : CHECK_EQ(0u, a0->Length());
5486 :
5487 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5488 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5489 6 : Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5490 6 : CHECK_EQ(1u, a1->Length());
5491 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5492 : .ToLocalChecked()
5493 : ->NumberValue(context.local())
5494 : .FromJust());
5495 :
5496 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5497 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5498 6 : Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5499 6 : CHECK_EQ(2u, a2->Length());
5500 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5501 : .ToLocalChecked()
5502 : ->NumberValue(context.local())
5503 : .FromJust());
5504 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5505 : .ToLocalChecked()
5506 : ->NumberValue(context.local())
5507 : .FromJust());
5508 :
5509 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5510 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5511 6 : Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5512 6 : CHECK_EQ(3u, a3->Length());
5513 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5514 : .ToLocalChecked()
5515 : ->NumberValue(context.local())
5516 : .FromJust());
5517 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5518 : .ToLocalChecked()
5519 : ->NumberValue(context.local())
5520 : .FromJust());
5521 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5522 : .ToLocalChecked()
5523 : ->NumberValue(context.local())
5524 : .FromJust());
5525 :
5526 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5527 6 : v8_num(10.11)};
5528 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5529 6 : Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5530 6 : CHECK_EQ(4u, a4->Length());
5531 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5532 : .ToLocalChecked()
5533 : ->NumberValue(context.local())
5534 : .FromJust());
5535 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5536 : .ToLocalChecked()
5537 : ->NumberValue(context.local())
5538 : .FromJust());
5539 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5540 : .ToLocalChecked()
5541 : ->NumberValue(context.local())
5542 : .FromJust());
5543 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5544 : .ToLocalChecked()
5545 : ->NumberValue(context.local())
5546 6 : .FromJust());
5547 6 : }
5548 :
5549 :
5550 28343 : THREADED_TEST(ConversionNumber) {
5551 6 : LocalContext env;
5552 6 : v8::Isolate* isolate = env->GetIsolate();
5553 12 : v8::HandleScope scope(isolate);
5554 : // Very large number.
5555 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5556 : Local<Value> obj =
5557 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5558 12 : CHECK_EQ(5312874545152.0,
5559 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5560 12 : CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5561 12 : CHECK_EQ(0, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5562 : // Large number.
5563 : CompileRun("var obj = -1234567890123;");
5564 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5565 12 : CHECK_EQ(-1234567890123.0,
5566 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5567 12 : CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5568 18 : CHECK_EQ(2382691125, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5569 : // Small positive integer.
5570 : CompileRun("var obj = 42;");
5571 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5572 12 : CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5573 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5574 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5575 : // Negative integer.
5576 : CompileRun("var obj = -37;");
5577 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5578 12 : CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5579 12 : CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5580 18 : CHECK_EQ(4294967259, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5581 : // Positive non-int32 integer.
5582 : CompileRun("var obj = 0x81234567;");
5583 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5584 12 : CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5585 12 : CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5586 18 : CHECK_EQ(2166572391, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5587 : // Fraction.
5588 : CompileRun("var obj = 42.3;");
5589 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5590 12 : CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5591 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5592 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5593 : // Large negative fraction.
5594 : CompileRun("var obj = -5726623061.75;");
5595 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5596 12 : CHECK_EQ(-5726623061.75,
5597 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5598 12 : CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5599 24 : CHECK_EQ(2863311531, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5600 6 : }
5601 :
5602 :
5603 28343 : THREADED_TEST(isNumberType) {
5604 6 : LocalContext env;
5605 12 : v8::HandleScope scope(env->GetIsolate());
5606 : // Very large number.
5607 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5608 : Local<Value> obj =
5609 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5610 6 : CHECK(!obj->IsInt32());
5611 6 : CHECK(!obj->IsUint32());
5612 : // Large negative number.
5613 : CompileRun("var obj = -1234567890123;");
5614 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5615 6 : CHECK(!obj->IsInt32());
5616 6 : CHECK(!obj->IsUint32());
5617 : // Small positive integer.
5618 : CompileRun("var obj = 42;");
5619 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5620 6 : CHECK(obj->IsInt32());
5621 6 : CHECK(obj->IsUint32());
5622 : // Negative integer.
5623 : CompileRun("var obj = -37;");
5624 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5625 6 : CHECK(obj->IsInt32());
5626 6 : CHECK(!obj->IsUint32());
5627 : // Positive non-int32 integer.
5628 : CompileRun("var obj = 0x81234567;");
5629 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5630 6 : CHECK(!obj->IsInt32());
5631 6 : CHECK(obj->IsUint32());
5632 : // Fraction.
5633 : CompileRun("var obj = 42.3;");
5634 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5635 6 : CHECK(!obj->IsInt32());
5636 6 : CHECK(!obj->IsUint32());
5637 : // Large negative fraction.
5638 : CompileRun("var obj = -5726623061.75;");
5639 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5640 6 : CHECK(!obj->IsInt32());
5641 6 : CHECK(!obj->IsUint32());
5642 : // Positive zero
5643 : CompileRun("var obj = 0.0;");
5644 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5645 6 : CHECK(obj->IsInt32());
5646 6 : CHECK(obj->IsUint32());
5647 : // Negative zero
5648 : CompileRun("var obj = -0.0;");
5649 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5650 6 : CHECK(!obj->IsInt32());
5651 12 : CHECK(!obj->IsUint32());
5652 6 : }
5653 :
5654 28343 : THREADED_TEST(IntegerType) {
5655 6 : LocalContext env;
5656 12 : v8::HandleScope scope(env->GetIsolate());
5657 : Local<Value> result;
5658 :
5659 : // Small positive integer
5660 : result = CompileRun("42;");
5661 6 : CHECK(result->IsNumber());
5662 6 : CHECK_EQ(42, result.As<v8::Integer>()->Value());
5663 : // Small negative integer
5664 : result = CompileRun("-42;");
5665 6 : CHECK(result->IsNumber());
5666 6 : CHECK_EQ(-42, result.As<v8::Integer>()->Value());
5667 : // Positive non-int32 integer
5668 : result = CompileRun("1099511627776;");
5669 6 : CHECK(result->IsNumber());
5670 6 : CHECK_EQ(1099511627776, result.As<v8::Integer>()->Value());
5671 : // Negative non-int32 integer
5672 : result = CompileRun("-1099511627776;");
5673 6 : CHECK(result->IsNumber());
5674 6 : CHECK_EQ(-1099511627776, result.As<v8::Integer>()->Value());
5675 : // Positive non-integer
5676 : result = CompileRun("3.14;");
5677 6 : CHECK(result->IsNumber());
5678 6 : CHECK_EQ(3, result.As<v8::Integer>()->Value());
5679 : // Negative non-integer
5680 : result = CompileRun("-3.14;");
5681 6 : CHECK(result->IsNumber());
5682 12 : CHECK_EQ(-3, result.As<v8::Integer>()->Value());
5683 6 : }
5684 :
5685 54 : static void CheckUncle(v8::Isolate* isolate, v8::TryCatch* try_catch) {
5686 54 : CHECK(try_catch->HasCaught());
5687 54 : String::Utf8Value str_value(isolate, try_catch->Exception());
5688 54 : CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5689 54 : try_catch->Reset();
5690 54 : }
5691 :
5692 28343 : THREADED_TEST(ConversionException) {
5693 6 : LocalContext env;
5694 6 : v8::Isolate* isolate = env->GetIsolate();
5695 12 : v8::HandleScope scope(isolate);
5696 : CompileRun(
5697 : "function TestClass() { };"
5698 : "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5699 : "var obj = new TestClass();");
5700 : Local<Value> obj =
5701 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5702 :
5703 12 : v8::TryCatch try_catch(isolate);
5704 :
5705 12 : CHECK(obj->ToString(env.local()).IsEmpty());
5706 6 : CheckUncle(isolate, &try_catch);
5707 :
5708 12 : CHECK(obj->ToNumber(env.local()).IsEmpty());
5709 6 : CheckUncle(isolate, &try_catch);
5710 :
5711 12 : CHECK(obj->ToInteger(env.local()).IsEmpty());
5712 6 : CheckUncle(isolate, &try_catch);
5713 :
5714 12 : CHECK(obj->ToUint32(env.local()).IsEmpty());
5715 6 : CheckUncle(isolate, &try_catch);
5716 :
5717 12 : CHECK(obj->ToInt32(env.local()).IsEmpty());
5718 6 : CheckUncle(isolate, &try_catch);
5719 :
5720 18 : CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5721 6 : CHECK(try_catch.HasCaught());
5722 6 : try_catch.Reset();
5723 :
5724 12 : CHECK(obj->Int32Value(env.local()).IsNothing());
5725 6 : CheckUncle(isolate, &try_catch);
5726 :
5727 12 : CHECK(obj->Uint32Value(env.local()).IsNothing());
5728 6 : CheckUncle(isolate, &try_catch);
5729 :
5730 12 : CHECK(obj->NumberValue(env.local()).IsNothing());
5731 6 : CheckUncle(isolate, &try_catch);
5732 :
5733 12 : CHECK(obj->IntegerValue(env.local()).IsNothing());
5734 12 : CheckUncle(isolate, &try_catch);
5735 6 : }
5736 :
5737 :
5738 56 : void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5739 28 : ApiTestFuzzer::Fuzz();
5740 56 : args.GetIsolate()->ThrowException(v8_str("konto"));
5741 28 : }
5742 :
5743 :
5744 25 : void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5745 5 : if (args.Length() < 1) {
5746 : args.GetReturnValue().Set(false);
5747 5 : return;
5748 : }
5749 5 : v8::HandleScope scope(args.GetIsolate());
5750 10 : v8::TryCatch try_catch(args.GetIsolate());
5751 : Local<Value> result =
5752 : CompileRun(args[0]
5753 5 : ->ToString(args.GetIsolate()->GetCurrentContext())
5754 10 : .ToLocalChecked());
5755 10 : CHECK(!try_catch.HasCaught() || result.IsEmpty());
5756 10 : args.GetReturnValue().Set(try_catch.HasCaught());
5757 : }
5758 :
5759 :
5760 28343 : THREADED_TEST(APICatch) {
5761 6 : v8::Isolate* isolate = CcTest::isolate();
5762 6 : v8::HandleScope scope(isolate);
5763 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764 : templ->Set(v8_str("ThrowFromC"),
5765 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5766 12 : LocalContext context(nullptr, templ);
5767 : CompileRun(
5768 : "var thrown = false;"
5769 : "try {"
5770 : " ThrowFromC();"
5771 : "} catch (e) {"
5772 : " thrown = true;"
5773 : "}");
5774 : Local<Value> thrown = context->Global()
5775 24 : ->Get(context.local(), v8_str("thrown"))
5776 6 : .ToLocalChecked();
5777 12 : CHECK(thrown->BooleanValue(isolate));
5778 6 : }
5779 :
5780 :
5781 28343 : THREADED_TEST(APIThrowTryCatch) {
5782 6 : v8::Isolate* isolate = CcTest::isolate();
5783 6 : v8::HandleScope scope(isolate);
5784 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5785 : templ->Set(v8_str("ThrowFromC"),
5786 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5787 12 : LocalContext context(nullptr, templ);
5788 12 : v8::TryCatch try_catch(isolate);
5789 : CompileRun("ThrowFromC();");
5790 12 : CHECK(try_catch.HasCaught());
5791 6 : }
5792 :
5793 :
5794 : // Test that a try-finally block doesn't shadow a try-catch block
5795 : // when setting up an external handler.
5796 : //
5797 : // BUG(271): Some of the exception propagation does not work on the
5798 : // ARM simulator because the simulator separates the C++ stack and the
5799 : // JS stack. This test therefore fails on the simulator. The test is
5800 : // not threaded to allow the threading tests to run on the simulator.
5801 28342 : TEST(TryCatchInTryFinally) {
5802 5 : v8::Isolate* isolate = CcTest::isolate();
5803 5 : v8::HandleScope scope(isolate);
5804 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5805 15 : templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5806 10 : LocalContext context(nullptr, templ);
5807 : Local<Value> result = CompileRun(
5808 : "try {"
5809 : " try {"
5810 : " CCatcher('throw 7;');"
5811 : " } finally {"
5812 : " }"
5813 : "} catch (e) {"
5814 : "}");
5815 10 : CHECK(result->IsTrue());
5816 5 : }
5817 :
5818 :
5819 5 : static void check_custom_error_tostring(v8::Local<v8::Message> message,
5820 : v8::Local<v8::Value> data) {
5821 : const char* uncaught_error = "Uncaught MyError toString";
5822 25 : CHECK(message->Get()
5823 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5824 : v8_str(uncaught_error))
5825 : .FromJust());
5826 5 : }
5827 :
5828 :
5829 28342 : TEST(CustomErrorToString) {
5830 5 : LocalContext context;
5831 10 : v8::HandleScope scope(context->GetIsolate());
5832 5 : context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5833 : CompileRun(
5834 : "function MyError(name, message) { "
5835 : " this.name = name; "
5836 : " this.message = message; "
5837 : "} "
5838 : "MyError.prototype = Object.create(Error.prototype); "
5839 : "MyError.prototype.toString = function() { "
5840 : " return 'MyError toString'; "
5841 : "}; "
5842 : "throw new MyError('my name', 'my message'); ");
5843 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5844 5 : }
5845 :
5846 :
5847 15 : static void check_custom_error_message(v8::Local<v8::Message> message,
5848 : v8::Local<v8::Value> data) {
5849 : const char* uncaught_error = "Uncaught MyError: my message";
5850 45 : printf("%s\n", *v8::String::Utf8Value(CcTest::isolate(), message->Get()));
5851 60 : CHECK(message->Get()
5852 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5853 : v8_str(uncaught_error))
5854 : .FromJust());
5855 15 : }
5856 :
5857 :
5858 28342 : TEST(CustomErrorMessage) {
5859 5 : LocalContext context;
5860 10 : v8::HandleScope scope(context->GetIsolate());
5861 5 : context->GetIsolate()->AddMessageListener(check_custom_error_message);
5862 :
5863 : // Handlebars.
5864 : CompileRun(
5865 : "function MyError(msg) { "
5866 : " this.name = 'MyError'; "
5867 : " this.message = msg; "
5868 : "} "
5869 : "MyError.prototype = new Error(); "
5870 : "throw new MyError('my message'); ");
5871 :
5872 : // Closure.
5873 : CompileRun(
5874 : "function MyError(msg) { "
5875 : " this.name = 'MyError'; "
5876 : " this.message = msg; "
5877 : "} "
5878 : "inherits = function(childCtor, parentCtor) { "
5879 : " function tempCtor() {}; "
5880 : " tempCtor.prototype = parentCtor.prototype; "
5881 : " childCtor.superClass_ = parentCtor.prototype; "
5882 : " childCtor.prototype = new tempCtor(); "
5883 : " childCtor.prototype.constructor = childCtor; "
5884 : "}; "
5885 : "inherits(MyError, Error); "
5886 : "throw new MyError('my message'); ");
5887 :
5888 : // Object.create.
5889 : CompileRun(
5890 : "function MyError(msg) { "
5891 : " this.name = 'MyError'; "
5892 : " this.message = msg; "
5893 : "} "
5894 : "MyError.prototype = Object.create(Error.prototype); "
5895 : "throw new MyError('my message'); ");
5896 :
5897 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5898 5 : }
5899 :
5900 :
5901 10 : static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5902 : v8::Local<v8::Value> data) {
5903 10 : CHECK(data->IsExternal());
5904 10 : int* callcount = static_cast<int*>(data.As<v8::External>()->Value());
5905 10 : ++*callcount;
5906 :
5907 : const char* uncaught_error = "Uncaught exception";
5908 50 : CHECK(message->Get()
5909 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5910 : v8_str(uncaught_error))
5911 : .FromJust());
5912 : // Test that compiling code inside a message handler works.
5913 40 : CHECK(CompileRunChecked(CcTest::isolate(), "(function(a) { return a; })(42)")
5914 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5915 : v8::Integer::NewFromUnsigned(CcTest::isolate(), 42))
5916 : .FromJust());
5917 10 : }
5918 :
5919 :
5920 28342 : TEST(CustomErrorRethrowsOnToString) {
5921 5 : int callcount = 0;
5922 5 : LocalContext context;
5923 5 : v8::Isolate* isolate = context->GetIsolate();
5924 10 : v8::HandleScope scope(isolate);
5925 : context->GetIsolate()->AddMessageListener(
5926 10 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5927 :
5928 : CompileRun(
5929 : "var e = { toString: function() { throw e; } };"
5930 : "try { throw e; } finally {}");
5931 :
5932 5 : CHECK_EQ(callcount, 1);
5933 : context->GetIsolate()->RemoveMessageListeners(
5934 10 : check_custom_rethrowing_message);
5935 5 : }
5936 :
5937 28342 : TEST(CustomErrorRethrowsOnToStringInsideVerboseTryCatch) {
5938 5 : int callcount = 0;
5939 5 : LocalContext context;
5940 5 : v8::Isolate* isolate = context->GetIsolate();
5941 10 : v8::HandleScope scope(isolate);
5942 10 : v8::TryCatch try_catch(isolate);
5943 5 : try_catch.SetVerbose(true);
5944 : context->GetIsolate()->AddMessageListener(
5945 10 : check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5946 :
5947 : CompileRun(
5948 : "var e = { toString: function() { throw e; } };"
5949 : "try { throw e; } finally {}");
5950 :
5951 5 : CHECK_EQ(callcount, 1);
5952 : context->GetIsolate()->RemoveMessageListeners(
5953 10 : check_custom_rethrowing_message);
5954 5 : }
5955 :
5956 :
5957 15 : static void receive_message(v8::Local<v8::Message> message,
5958 : v8::Local<v8::Value> data) {
5959 15 : message->Get();
5960 15 : message_received = true;
5961 15 : }
5962 :
5963 :
5964 28342 : TEST(APIThrowMessage) {
5965 5 : message_received = false;
5966 5 : v8::Isolate* isolate = CcTest::isolate();
5967 5 : v8::HandleScope scope(isolate);
5968 5 : isolate->AddMessageListener(receive_message);
5969 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5970 : templ->Set(v8_str("ThrowFromC"),
5971 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5972 10 : LocalContext context(nullptr, templ);
5973 : CompileRun("ThrowFromC();");
5974 5 : CHECK(message_received);
5975 10 : isolate->RemoveMessageListeners(receive_message);
5976 5 : }
5977 :
5978 :
5979 28342 : TEST(APIThrowMessageAndVerboseTryCatch) {
5980 5 : message_received = false;
5981 5 : v8::Isolate* isolate = CcTest::isolate();
5982 5 : v8::HandleScope scope(isolate);
5983 5 : isolate->AddMessageListener(receive_message);
5984 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5985 : templ->Set(v8_str("ThrowFromC"),
5986 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5987 10 : LocalContext context(nullptr, templ);
5988 10 : v8::TryCatch try_catch(isolate);
5989 5 : try_catch.SetVerbose(true);
5990 : Local<Value> result = CompileRun("ThrowFromC();");
5991 5 : CHECK(try_catch.HasCaught());
5992 5 : CHECK(result.IsEmpty());
5993 5 : CHECK(message_received);
5994 10 : isolate->RemoveMessageListeners(receive_message);
5995 5 : }
5996 :
5997 :
5998 28342 : TEST(APIStackOverflowAndVerboseTryCatch) {
5999 5 : message_received = false;
6000 5 : LocalContext context;
6001 10 : v8::HandleScope scope(context->GetIsolate());
6002 5 : context->GetIsolate()->AddMessageListener(receive_message);
6003 10 : v8::TryCatch try_catch(context->GetIsolate());
6004 5 : try_catch.SetVerbose(true);
6005 : Local<Value> result = CompileRun("function foo() { foo(); } foo();");
6006 5 : CHECK(try_catch.HasCaught());
6007 5 : CHECK(result.IsEmpty());
6008 5 : CHECK(message_received);
6009 10 : context->GetIsolate()->RemoveMessageListeners(receive_message);
6010 5 : }
6011 :
6012 :
6013 28343 : THREADED_TEST(ExternalScriptException) {
6014 6 : v8::Isolate* isolate = CcTest::isolate();
6015 6 : v8::HandleScope scope(isolate);
6016 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6017 : templ->Set(v8_str("ThrowFromC"),
6018 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
6019 12 : LocalContext context(nullptr, templ);
6020 :
6021 12 : v8::TryCatch try_catch(isolate);
6022 : Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
6023 6 : CHECK(result.IsEmpty());
6024 6 : CHECK(try_catch.HasCaught());
6025 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6026 12 : CHECK_EQ(0, strcmp("konto", *exception_value));
6027 6 : }
6028 :
6029 :
6030 370 : void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
6031 85 : ApiTestFuzzer::Fuzz();
6032 85 : CHECK_EQ(4, args.Length());
6033 85 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6034 170 : int count = args[0]->Int32Value(context).FromJust();
6035 170 : int cInterval = args[2]->Int32Value(context).FromJust();
6036 85 : if (count == 0) {
6037 10 : args.GetIsolate()->ThrowException(v8_str("FromC"));
6038 5 : return;
6039 : } else {
6040 80 : Local<v8::Object> global = context->Global();
6041 : Local<Value> fun =
6042 240 : global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
6043 320 : v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
6044 80 : if (count % cInterval == 0) {
6045 30 : v8::TryCatch try_catch(args.GetIsolate());
6046 : Local<Value> result = fun.As<Function>()
6047 30 : ->Call(context, global, 4, argv)
6048 60 : .FromMaybe(Local<Value>());
6049 60 : int expected = args[3]->Int32Value(context).FromJust();
6050 30 : if (try_catch.HasCaught()) {
6051 15 : CHECK_EQ(expected, count);
6052 15 : CHECK(result.IsEmpty());
6053 15 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
6054 : } else {
6055 15 : CHECK_NE(expected, count);
6056 : }
6057 : args.GetReturnValue().Set(result);
6058 30 : return;
6059 : } else {
6060 : args.GetReturnValue().Set(fun.As<Function>()
6061 50 : ->Call(context, global, 4, argv)
6062 100 : .FromMaybe(v8::Local<v8::Value>()));
6063 50 : return;
6064 : }
6065 : }
6066 : }
6067 :
6068 :
6069 75 : void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
6070 25 : ApiTestFuzzer::Fuzz();
6071 25 : CHECK_EQ(3, args.Length());
6072 : v8::Isolate* isolate = args.GetIsolate();
6073 25 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
6074 25 : bool equality = args[0]->BooleanValue(isolate);
6075 50 : int count = args[1]->Int32Value(context).FromJust();
6076 50 : int expected = args[2]->Int32Value(context).FromJust();
6077 25 : if (equality) {
6078 15 : CHECK_EQ(count, expected);
6079 : } else {
6080 10 : CHECK_NE(count, expected);
6081 : }
6082 25 : }
6083 :
6084 :
6085 28343 : THREADED_TEST(EvalInTryFinally) {
6086 6 : LocalContext context;
6087 12 : v8::HandleScope scope(context->GetIsolate());
6088 12 : v8::TryCatch try_catch(context->GetIsolate());
6089 : CompileRun(
6090 : "(function() {"
6091 : " try {"
6092 : " eval('asldkf (*&^&*^');"
6093 : " } finally {"
6094 : " return;"
6095 : " }"
6096 : "})()");
6097 12 : CHECK(!try_catch.HasCaught());
6098 6 : }
6099 :
6100 :
6101 : // This test works by making a stack of alternating JavaScript and C
6102 : // activations. These activations set up exception handlers with regular
6103 : // intervals, one interval for C activations and another for JavaScript
6104 : // activations. When enough activations have been created an exception is
6105 : // thrown and we check that the right activation catches the exception and that
6106 : // no other activations do. The right activation is always the topmost one with
6107 : // a handler, regardless of whether it is in JavaScript or C.
6108 : //
6109 : // The notation used to describe a test case looks like this:
6110 : //
6111 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6112 : //
6113 : // Each entry is an activation, either JS or C. The index is the count at that
6114 : // level. Stars identify activations with exception handlers, the @ identifies
6115 : // the exception handler that should catch the exception.
6116 : //
6117 : // BUG(271): Some of the exception propagation does not work on the
6118 : // ARM simulator because the simulator separates the C++ stack and the
6119 : // JS stack. This test therefore fails on the simulator. The test is
6120 : // not threaded to allow the threading tests to run on the simulator.
6121 28342 : TEST(ExceptionOrder) {
6122 5 : v8::Isolate* isolate = CcTest::isolate();
6123 5 : v8::HandleScope scope(isolate);
6124 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6125 15 : templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
6126 : templ->Set(v8_str("CThrowCountDown"),
6127 15 : v8::FunctionTemplate::New(isolate, CThrowCountDown));
6128 10 : LocalContext context(nullptr, templ);
6129 : CompileRun(
6130 : "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
6131 : " if (count == 0) throw 'FromJS';"
6132 : " if (count % jsInterval == 0) {"
6133 : " try {"
6134 : " var value = CThrowCountDown(count - 1,"
6135 : " jsInterval,"
6136 : " cInterval,"
6137 : " expected);"
6138 : " check(false, count, expected);"
6139 : " return value;"
6140 : " } catch (e) {"
6141 : " check(true, count, expected);"
6142 : " }"
6143 : " } else {"
6144 : " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
6145 : " }"
6146 : "}");
6147 : Local<Function> fun = Local<Function>::Cast(
6148 : context->Global()
6149 20 : ->Get(context.local(), v8_str("JSThrowCountDown"))
6150 5 : .ToLocalChecked());
6151 :
6152 : const int argc = 4;
6153 : // count jsInterval cInterval expected
6154 :
6155 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
6156 5 : v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6157 10 : fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6158 :
6159 : // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6160 5 : v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6161 10 : fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6162 :
6163 : // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6164 5 : v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6165 10 : fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6166 :
6167 : // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6168 5 : v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6169 10 : fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6170 :
6171 : // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6172 5 : v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6173 10 : fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6174 :
6175 : // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6176 5 : v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6177 15 : fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6178 5 : }
6179 :
6180 :
6181 126 : void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6182 42 : ApiTestFuzzer::Fuzz();
6183 42 : CHECK_EQ(1, args.Length());
6184 42 : args.GetIsolate()->ThrowException(args[0]);
6185 42 : }
6186 :
6187 :
6188 28343 : THREADED_TEST(ThrowValues) {
6189 6 : v8::Isolate* isolate = CcTest::isolate();
6190 6 : v8::HandleScope scope(isolate);
6191 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6192 18 : templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6193 12 : LocalContext context(nullptr, templ);
6194 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6195 : CompileRun("function Run(obj) {"
6196 : " try {"
6197 : " Throw(obj);"
6198 : " } catch (e) {"
6199 : " return e;"
6200 : " }"
6201 : " return 'no exception';"
6202 : "}"
6203 : "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6204 6 : CHECK_EQ(5u, result->Length());
6205 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6206 : .ToLocalChecked()
6207 : ->IsString());
6208 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6209 : .ToLocalChecked()
6210 : ->IsNumber());
6211 24 : CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6212 : .ToLocalChecked()
6213 : ->Int32Value(context.local())
6214 : .FromJust());
6215 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6216 : .ToLocalChecked()
6217 : ->IsNumber());
6218 24 : CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6219 : .ToLocalChecked()
6220 : ->Int32Value(context.local())
6221 : .FromJust());
6222 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6223 : .ToLocalChecked()
6224 : ->IsNull());
6225 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6226 : .ToLocalChecked()
6227 6 : ->IsUndefined());
6228 6 : }
6229 :
6230 :
6231 28343 : THREADED_TEST(CatchZero) {
6232 6 : LocalContext context;
6233 12 : v8::HandleScope scope(context->GetIsolate());
6234 12 : v8::TryCatch try_catch(context->GetIsolate());
6235 6 : CHECK(!try_catch.HasCaught());
6236 : CompileRun("throw 10");
6237 6 : CHECK(try_catch.HasCaught());
6238 18 : CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6239 6 : try_catch.Reset();
6240 6 : CHECK(!try_catch.HasCaught());
6241 : CompileRun("throw 0");
6242 6 : CHECK(try_catch.HasCaught());
6243 24 : CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6244 6 : }
6245 :
6246 :
6247 28343 : THREADED_TEST(CatchExceptionFromWith) {
6248 6 : LocalContext context;
6249 12 : v8::HandleScope scope(context->GetIsolate());
6250 12 : v8::TryCatch try_catch(context->GetIsolate());
6251 6 : CHECK(!try_catch.HasCaught());
6252 : CompileRun("var o = {}; with (o) { throw 42; }");
6253 12 : CHECK(try_catch.HasCaught());
6254 6 : }
6255 :
6256 :
6257 28343 : THREADED_TEST(TryCatchAndFinallyHidingException) {
6258 6 : LocalContext context;
6259 12 : v8::HandleScope scope(context->GetIsolate());
6260 12 : v8::TryCatch try_catch(context->GetIsolate());
6261 6 : CHECK(!try_catch.HasCaught());
6262 : CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6263 : CompileRun("f({toString: function() { throw 42; }});");
6264 12 : CHECK(!try_catch.HasCaught());
6265 6 : }
6266 :
6267 :
6268 6 : void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6269 6 : v8::TryCatch try_catch(args.GetIsolate());
6270 6 : }
6271 :
6272 :
6273 28343 : THREADED_TEST(TryCatchAndFinally) {
6274 6 : LocalContext context;
6275 6 : v8::Isolate* isolate = context->GetIsolate();
6276 12 : v8::HandleScope scope(isolate);
6277 48 : CHECK(context->Global()
6278 : ->Set(context.local(), v8_str("native_with_try_catch"),
6279 : v8::FunctionTemplate::New(isolate, WithTryCatch)
6280 : ->GetFunction(context.local())
6281 : .ToLocalChecked())
6282 : .FromJust());
6283 12 : v8::TryCatch try_catch(isolate);
6284 6 : CHECK(!try_catch.HasCaught());
6285 : CompileRun(
6286 : "try {\n"
6287 : " throw new Error('a');\n"
6288 : "} finally {\n"
6289 : " native_with_try_catch();\n"
6290 : "}\n");
6291 12 : CHECK(try_catch.HasCaught());
6292 6 : }
6293 :
6294 :
6295 30 : static void TryCatchNested1Helper(int depth) {
6296 30 : if (depth > 0) {
6297 25 : v8::TryCatch try_catch(CcTest::isolate());
6298 25 : try_catch.SetVerbose(true);
6299 25 : TryCatchNested1Helper(depth - 1);
6300 25 : CHECK(try_catch.HasCaught());
6301 25 : try_catch.ReThrow();
6302 : } else {
6303 10 : CcTest::isolate()->ThrowException(v8_str("E1"));
6304 : }
6305 30 : }
6306 :
6307 :
6308 30 : static void TryCatchNested2Helper(int depth) {
6309 30 : if (depth > 0) {
6310 25 : v8::TryCatch try_catch(CcTest::isolate());
6311 25 : try_catch.SetVerbose(true);
6312 25 : TryCatchNested2Helper(depth - 1);
6313 25 : CHECK(try_catch.HasCaught());
6314 25 : try_catch.ReThrow();
6315 : } else {
6316 : CompileRun("throw 'E2';");
6317 : }
6318 30 : }
6319 :
6320 :
6321 28342 : TEST(TryCatchNested) {
6322 5 : v8::V8::Initialize();
6323 5 : LocalContext context;
6324 10 : v8::HandleScope scope(context->GetIsolate());
6325 :
6326 : {
6327 : // Test nested try-catch with a native throw in the end.
6328 5 : v8::TryCatch try_catch(context->GetIsolate());
6329 5 : TryCatchNested1Helper(5);
6330 5 : CHECK(try_catch.HasCaught());
6331 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6332 : try_catch.Exception()),
6333 5 : "E1"));
6334 : }
6335 :
6336 : {
6337 : // Test nested try-catch with a JavaScript throw in the end.
6338 5 : v8::TryCatch try_catch(context->GetIsolate());
6339 5 : TryCatchNested2Helper(5);
6340 5 : CHECK(try_catch.HasCaught());
6341 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6342 : try_catch.Exception()),
6343 5 : "E2"));
6344 5 : }
6345 5 : }
6346 :
6347 :
6348 10 : void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6349 10 : CHECK(try_catch->HasCaught());
6350 10 : Local<Message> message = try_catch->Message();
6351 10 : Local<Value> resource = message->GetScriptOrigin().ResourceName();
6352 10 : CHECK_EQ(
6353 : 0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), resource), "inner"));
6354 20 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), message->Get()),
6355 : "Uncaught Error: a"));
6356 20 : CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6357 : .FromJust());
6358 20 : CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6359 : .FromJust());
6360 10 : }
6361 :
6362 :
6363 5 : void TryCatchMixedNestingHelper(
6364 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6365 5 : ApiTestFuzzer::Fuzz();
6366 5 : v8::TryCatch try_catch(args.GetIsolate());
6367 5 : CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6368 5 : CHECK(try_catch.HasCaught());
6369 5 : TryCatchMixedNestingCheck(&try_catch);
6370 5 : try_catch.ReThrow();
6371 5 : }
6372 :
6373 :
6374 : // This test ensures that an outer TryCatch in the following situation:
6375 : // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6376 : // does not clobber the Message object generated for the inner TryCatch.
6377 : // This exercises the ability of TryCatch.ReThrow() to restore the
6378 : // inner pending Message before throwing the exception again.
6379 28342 : TEST(TryCatchMixedNesting) {
6380 5 : v8::Isolate* isolate = CcTest::isolate();
6381 5 : v8::HandleScope scope(isolate);
6382 5 : v8::V8::Initialize();
6383 10 : v8::TryCatch try_catch(isolate);
6384 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6385 : templ->Set(v8_str("TryCatchMixedNestingHelper"),
6386 15 : v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6387 10 : LocalContext context(nullptr, templ);
6388 5 : CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6389 10 : TryCatchMixedNestingCheck(&try_catch);
6390 5 : }
6391 :
6392 :
6393 15 : void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6394 5 : ApiTestFuzzer::Fuzz();
6395 5 : v8::TryCatch try_catch(args.GetIsolate());
6396 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6397 5 : CHECK(try_catch.HasCaught());
6398 5 : }
6399 :
6400 :
6401 28342 : TEST(TryCatchNative) {
6402 5 : v8::Isolate* isolate = CcTest::isolate();
6403 5 : v8::HandleScope scope(isolate);
6404 5 : v8::V8::Initialize();
6405 10 : v8::TryCatch try_catch(isolate);
6406 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6407 : templ->Set(v8_str("TryCatchNativeHelper"),
6408 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6409 10 : LocalContext context(nullptr, templ);
6410 : CompileRun("TryCatchNativeHelper();");
6411 10 : CHECK(!try_catch.HasCaught());
6412 5 : }
6413 :
6414 :
6415 5 : void TryCatchNativeResetHelper(
6416 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6417 5 : ApiTestFuzzer::Fuzz();
6418 5 : v8::TryCatch try_catch(args.GetIsolate());
6419 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6420 5 : CHECK(try_catch.HasCaught());
6421 5 : try_catch.Reset();
6422 5 : CHECK(!try_catch.HasCaught());
6423 5 : }
6424 :
6425 :
6426 28342 : TEST(TryCatchNativeReset) {
6427 5 : v8::Isolate* isolate = CcTest::isolate();
6428 5 : v8::HandleScope scope(isolate);
6429 5 : v8::V8::Initialize();
6430 10 : v8::TryCatch try_catch(isolate);
6431 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6432 : templ->Set(v8_str("TryCatchNativeResetHelper"),
6433 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6434 10 : LocalContext context(nullptr, templ);
6435 : CompileRun("TryCatchNativeResetHelper();");
6436 10 : CHECK(!try_catch.HasCaught());
6437 5 : }
6438 :
6439 :
6440 28343 : THREADED_TEST(Equality) {
6441 6 : LocalContext context;
6442 6 : v8::Isolate* isolate = context->GetIsolate();
6443 12 : v8::HandleScope scope(context->GetIsolate());
6444 : // Check that equality works at all before relying on CHECK_EQ
6445 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6446 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6447 :
6448 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6449 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6450 18 : CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6451 18 : CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6452 18 : CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6453 :
6454 : // Assume String is not internalized.
6455 18 : CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6456 18 : CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6457 12 : CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6458 12 : CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6459 12 : CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6460 12 : CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6461 6 : Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6462 6 : CHECK(!not_a_number->StrictEquals(not_a_number));
6463 6 : CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6464 6 : CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6465 :
6466 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
6467 : v8::Persistent<v8::Object> alias(isolate, obj);
6468 6 : CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6469 : alias.Reset();
6470 :
6471 18 : CHECK(v8_str("a")->SameValue(v8_str("a")));
6472 18 : CHECK(!v8_str("a")->SameValue(v8_str("b")));
6473 12 : CHECK(!v8_str("5")->SameValue(v8_num(5)));
6474 12 : CHECK(v8_num(1)->SameValue(v8_num(1)));
6475 12 : CHECK(!v8_num(1)->SameValue(v8_num(2)));
6476 12 : CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6477 6 : CHECK(not_a_number->SameValue(not_a_number));
6478 6 : CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6479 12 : CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6480 6 : }
6481 :
6482 28343 : THREADED_TEST(TypeOf) {
6483 6 : LocalContext context;
6484 6 : v8::Isolate* isolate = context->GetIsolate();
6485 12 : v8::HandleScope scope(context->GetIsolate());
6486 :
6487 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6488 12 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6489 :
6490 30 : CHECK(v8::Undefined(isolate)
6491 : ->TypeOf(isolate)
6492 : ->Equals(context.local(), v8_str("undefined"))
6493 : .FromJust());
6494 30 : CHECK(v8::Null(isolate)
6495 : ->TypeOf(isolate)
6496 : ->Equals(context.local(), v8_str("object"))
6497 : .FromJust());
6498 30 : CHECK(v8_str("str")
6499 : ->TypeOf(isolate)
6500 : ->Equals(context.local(), v8_str("string"))
6501 : .FromJust());
6502 30 : CHECK(v8_num(0.0)
6503 : ->TypeOf(isolate)
6504 : ->Equals(context.local(), v8_str("number"))
6505 : .FromJust());
6506 30 : CHECK(v8_num(1)
6507 : ->TypeOf(isolate)
6508 : ->Equals(context.local(), v8_str("number"))
6509 : .FromJust());
6510 30 : CHECK(v8::Object::New(isolate)
6511 : ->TypeOf(isolate)
6512 : ->Equals(context.local(), v8_str("object"))
6513 : .FromJust());
6514 30 : CHECK(v8::Boolean::New(isolate, true)
6515 : ->TypeOf(isolate)
6516 : ->Equals(context.local(), v8_str("boolean"))
6517 : .FromJust());
6518 24 : CHECK(fun->TypeOf(isolate)
6519 : ->Equals(context.local(), v8_str("function"))
6520 6 : .FromJust());
6521 6 : }
6522 :
6523 28343 : THREADED_TEST(InstanceOf) {
6524 6 : LocalContext env;
6525 12 : v8::HandleScope scope(env->GetIsolate());
6526 : CompileRun(
6527 : "var A = {};"
6528 : "var B = {};"
6529 : "var C = {};"
6530 : "B.__proto__ = A;"
6531 : "C.__proto__ = B;"
6532 : "function F() {}"
6533 : "F.prototype = A;"
6534 : "var G = { [Symbol.hasInstance] : null};"
6535 : "var H = { [Symbol.hasInstance] : () => { throw new Error(); } };"
6536 : "var J = { [Symbol.hasInstance] : () => true };"
6537 : "class K {}"
6538 : "var D = new K;"
6539 : "class L extends K {}"
6540 : "var E = new L");
6541 :
6542 6 : v8::Local<v8::Object> f = v8::Local<v8::Object>::Cast(CompileRun("F"));
6543 6 : v8::Local<v8::Object> g = v8::Local<v8::Object>::Cast(CompileRun("G"));
6544 6 : v8::Local<v8::Object> h = v8::Local<v8::Object>::Cast(CompileRun("H"));
6545 6 : v8::Local<v8::Object> j = v8::Local<v8::Object>::Cast(CompileRun("J"));
6546 6 : v8::Local<v8::Object> k = v8::Local<v8::Object>::Cast(CompileRun("K"));
6547 6 : v8::Local<v8::Object> l = v8::Local<v8::Object>::Cast(CompileRun("L"));
6548 : v8::Local<v8::Value> a = v8::Local<v8::Value>::Cast(CompileRun("A"));
6549 : v8::Local<v8::Value> b = v8::Local<v8::Value>::Cast(CompileRun("B"));
6550 : v8::Local<v8::Value> c = v8::Local<v8::Value>::Cast(CompileRun("C"));
6551 : v8::Local<v8::Value> d = v8::Local<v8::Value>::Cast(CompileRun("D"));
6552 : v8::Local<v8::Value> e = v8::Local<v8::Value>::Cast(CompileRun("E"));
6553 :
6554 12 : v8::TryCatch try_catch(env->GetIsolate());
6555 12 : CHECK(!a->InstanceOf(env.local(), f).ToChecked());
6556 12 : CHECK(b->InstanceOf(env.local(), f).ToChecked());
6557 12 : CHECK(c->InstanceOf(env.local(), f).ToChecked());
6558 12 : CHECK(!d->InstanceOf(env.local(), f).ToChecked());
6559 12 : CHECK(!e->InstanceOf(env.local(), f).ToChecked());
6560 6 : CHECK(!try_catch.HasCaught());
6561 :
6562 12 : CHECK(a->InstanceOf(env.local(), g).IsNothing());
6563 6 : CHECK(try_catch.HasCaught());
6564 6 : try_catch.Reset();
6565 :
6566 12 : CHECK(b->InstanceOf(env.local(), h).IsNothing());
6567 6 : CHECK(try_catch.HasCaught());
6568 6 : try_catch.Reset();
6569 :
6570 18 : CHECK(v8_num(1)->InstanceOf(env.local(), j).ToChecked());
6571 6 : CHECK(!try_catch.HasCaught());
6572 :
6573 12 : CHECK(d->InstanceOf(env.local(), k).ToChecked());
6574 12 : CHECK(e->InstanceOf(env.local(), k).ToChecked());
6575 12 : CHECK(!d->InstanceOf(env.local(), l).ToChecked());
6576 12 : CHECK(e->InstanceOf(env.local(), l).ToChecked());
6577 12 : CHECK(!try_catch.HasCaught());
6578 6 : }
6579 :
6580 28343 : THREADED_TEST(MultiRun) {
6581 6 : LocalContext context;
6582 12 : v8::HandleScope scope(context->GetIsolate());
6583 : Local<Script> script = v8_compile("x");
6584 66 : for (int i = 0; i < 10; i++) {
6585 60 : script->Run(context.local()).IsEmpty();
6586 6 : }
6587 6 : }
6588 :
6589 :
6590 204 : static void GetXValue(Local<Name> name,
6591 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6592 204 : ApiTestFuzzer::Fuzz();
6593 816 : CHECK(info.Data()
6594 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6595 : .FromJust());
6596 816 : CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6597 : .FromJust());
6598 : info.GetReturnValue().Set(name);
6599 204 : }
6600 :
6601 :
6602 28343 : THREADED_TEST(SimplePropertyRead) {
6603 6 : LocalContext context;
6604 6 : v8::Isolate* isolate = context->GetIsolate();
6605 12 : v8::HandleScope scope(isolate);
6606 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6607 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6608 36 : CHECK(context->Global()
6609 : ->Set(context.local(), v8_str("obj"),
6610 : templ->NewInstance(context.local()).ToLocalChecked())
6611 : .FromJust());
6612 : Local<Script> script = v8_compile("obj.x");
6613 66 : for (int i = 0; i < 10; i++) {
6614 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
6615 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6616 6 : }
6617 6 : }
6618 :
6619 :
6620 28343 : THREADED_TEST(DefinePropertyOnAPIAccessor) {
6621 6 : LocalContext context;
6622 6 : v8::Isolate* isolate = context->GetIsolate();
6623 12 : v8::HandleScope scope(isolate);
6624 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6625 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6626 36 : CHECK(context->Global()
6627 : ->Set(context.local(), v8_str("obj"),
6628 : templ->NewInstance(context.local()).ToLocalChecked())
6629 : .FromJust());
6630 :
6631 : // Uses getOwnPropertyDescriptor to check the configurable status
6632 : Local<Script> script_desc = v8_compile(
6633 : "var prop = Object.getOwnPropertyDescriptor( "
6634 : "obj, 'x');"
6635 : "prop.configurable;");
6636 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6637 6 : CHECK(result->BooleanValue(isolate));
6638 :
6639 : // Redefine get - but still configurable
6640 : Local<Script> script_define = v8_compile(
6641 : "var desc = { get: function(){return 42; },"
6642 : " configurable: true };"
6643 : "Object.defineProperty(obj, 'x', desc);"
6644 : "obj.x");
6645 6 : result = script_define->Run(context.local()).ToLocalChecked();
6646 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6647 :
6648 : // Check that the accessor is still configurable
6649 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6650 6 : CHECK(result->BooleanValue(isolate));
6651 :
6652 : // Redefine to a non-configurable
6653 : script_define = v8_compile(
6654 : "var desc = { get: function(){return 43; },"
6655 : " configurable: false };"
6656 : "Object.defineProperty(obj, 'x', desc);"
6657 : "obj.x");
6658 6 : result = script_define->Run(context.local()).ToLocalChecked();
6659 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6660 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6661 6 : CHECK(!result->BooleanValue(isolate));
6662 :
6663 : // Make sure that it is not possible to redefine again
6664 12 : v8::TryCatch try_catch(isolate);
6665 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6666 6 : CHECK(try_catch.HasCaught());
6667 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6668 6 : CHECK_EQ(0,
6669 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6670 6 : }
6671 :
6672 :
6673 28343 : THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6674 6 : v8::Isolate* isolate = CcTest::isolate();
6675 6 : v8::HandleScope scope(isolate);
6676 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6677 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6678 12 : LocalContext context;
6679 36 : CHECK(context->Global()
6680 : ->Set(context.local(), v8_str("obj"),
6681 : templ->NewInstance(context.local()).ToLocalChecked())
6682 : .FromJust());
6683 :
6684 : Local<Script> script_desc = v8_compile(
6685 : "var prop ="
6686 : "Object.getOwnPropertyDescriptor( "
6687 : "obj, 'x');"
6688 : "prop.configurable;");
6689 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6690 6 : CHECK(result->BooleanValue(isolate));
6691 :
6692 : Local<Script> script_define = v8_compile(
6693 : "var desc = {get: function(){return 42; },"
6694 : " configurable: true };"
6695 : "Object.defineProperty(obj, 'x', desc);"
6696 : "obj.x");
6697 6 : result = script_define->Run(context.local()).ToLocalChecked();
6698 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6699 :
6700 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6701 6 : CHECK(result->BooleanValue(isolate));
6702 :
6703 : script_define = v8_compile(
6704 : "var desc = {get: function(){return 43; },"
6705 : " configurable: false };"
6706 : "Object.defineProperty(obj, 'x', desc);"
6707 : "obj.x");
6708 6 : result = script_define->Run(context.local()).ToLocalChecked();
6709 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6710 :
6711 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6712 6 : CHECK(!result->BooleanValue(isolate));
6713 :
6714 12 : v8::TryCatch try_catch(isolate);
6715 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6716 6 : CHECK(try_catch.HasCaught());
6717 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6718 6 : CHECK_EQ(0,
6719 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6720 6 : }
6721 :
6722 :
6723 72 : static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6724 : char const* name) {
6725 : return v8::Local<v8::Object>::Cast(
6726 : (*context)
6727 : ->Global()
6728 288 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6729 144 : .ToLocalChecked());
6730 : }
6731 :
6732 :
6733 28343 : THREADED_TEST(DefineAPIAccessorOnObject) {
6734 6 : v8::Isolate* isolate = CcTest::isolate();
6735 6 : v8::HandleScope scope(isolate);
6736 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6737 12 : LocalContext context;
6738 :
6739 42 : CHECK(context->Global()
6740 : ->Set(context.local(), v8_str("obj1"),
6741 : templ->NewInstance(context.local()).ToLocalChecked())
6742 : .FromJust());
6743 : CompileRun("var obj2 = {};");
6744 :
6745 6 : CHECK(CompileRun("obj1.x")->IsUndefined());
6746 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6747 :
6748 30 : CHECK(GetGlobalProperty(&context, "obj1")
6749 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6750 : v8_str("donut"))
6751 : .FromJust());
6752 :
6753 6 : ExpectString("obj1.x", "x");
6754 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6755 :
6756 30 : CHECK(GetGlobalProperty(&context, "obj2")
6757 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6758 : v8_str("donut"))
6759 : .FromJust());
6760 :
6761 6 : ExpectString("obj1.x", "x");
6762 6 : ExpectString("obj2.x", "x");
6763 :
6764 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6765 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6766 :
6767 : CompileRun(
6768 : "Object.defineProperty(obj1, 'x',"
6769 : "{ get: function() { return 'y'; }, configurable: true })");
6770 :
6771 6 : ExpectString("obj1.x", "y");
6772 6 : ExpectString("obj2.x", "x");
6773 :
6774 : CompileRun(
6775 : "Object.defineProperty(obj2, 'x',"
6776 : "{ get: function() { return 'y'; }, configurable: true })");
6777 :
6778 6 : ExpectString("obj1.x", "y");
6779 6 : ExpectString("obj2.x", "y");
6780 :
6781 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6782 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6783 :
6784 30 : CHECK(GetGlobalProperty(&context, "obj1")
6785 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6786 : v8_str("donut"))
6787 : .FromJust());
6788 30 : CHECK(GetGlobalProperty(&context, "obj2")
6789 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6790 : v8_str("donut"))
6791 : .FromJust());
6792 :
6793 6 : ExpectString("obj1.x", "x");
6794 6 : ExpectString("obj2.x", "x");
6795 :
6796 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6797 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6798 :
6799 : // Define getters/setters, but now make them not configurable.
6800 : CompileRun(
6801 : "Object.defineProperty(obj1, 'x',"
6802 : "{ get: function() { return 'z'; }, configurable: false })");
6803 : CompileRun(
6804 : "Object.defineProperty(obj2, 'x',"
6805 : "{ get: function() { return 'z'; }, configurable: false })");
6806 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6807 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6808 :
6809 6 : ExpectString("obj1.x", "z");
6810 6 : ExpectString("obj2.x", "z");
6811 :
6812 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6813 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6814 : v8_str("donut"))
6815 : .FromJust());
6816 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6817 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6818 : v8_str("donut"))
6819 : .FromJust());
6820 :
6821 6 : ExpectString("obj1.x", "z");
6822 12 : ExpectString("obj2.x", "z");
6823 6 : }
6824 :
6825 :
6826 28343 : THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6827 6 : v8::Isolate* isolate = CcTest::isolate();
6828 6 : v8::HandleScope scope(isolate);
6829 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6830 12 : LocalContext context;
6831 :
6832 42 : CHECK(context->Global()
6833 : ->Set(context.local(), v8_str("obj1"),
6834 : templ->NewInstance(context.local()).ToLocalChecked())
6835 : .FromJust());
6836 : CompileRun("var obj2 = {};");
6837 :
6838 30 : CHECK(GetGlobalProperty(&context, "obj1")
6839 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6840 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6841 : .FromJust());
6842 30 : CHECK(GetGlobalProperty(&context, "obj2")
6843 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6844 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6845 : .FromJust());
6846 :
6847 6 : ExpectString("obj1.x", "x");
6848 6 : ExpectString("obj2.x", "x");
6849 :
6850 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6851 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6852 :
6853 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6854 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6855 : v8_str("donut"))
6856 : .FromJust());
6857 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6858 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6859 : v8_str("donut"))
6860 : .FromJust());
6861 :
6862 : {
6863 6 : v8::TryCatch try_catch(isolate);
6864 : CompileRun(
6865 : "Object.defineProperty(obj1, 'x',"
6866 : "{get: function() { return 'func'; }})");
6867 6 : CHECK(try_catch.HasCaught());
6868 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6869 6 : CHECK_EQ(
6870 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6871 : }
6872 : {
6873 6 : v8::TryCatch try_catch(isolate);
6874 : CompileRun(
6875 : "Object.defineProperty(obj2, 'x',"
6876 : "{get: function() { return 'func'; }})");
6877 6 : CHECK(try_catch.HasCaught());
6878 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6879 6 : CHECK_EQ(
6880 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6881 6 : }
6882 6 : }
6883 :
6884 :
6885 24 : static void Get239Value(Local<Name> name,
6886 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6887 24 : ApiTestFuzzer::Fuzz();
6888 96 : CHECK(info.Data()
6889 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6890 : .FromJust());
6891 96 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6892 : .FromJust());
6893 : info.GetReturnValue().Set(name);
6894 24 : }
6895 :
6896 :
6897 28343 : THREADED_TEST(ElementAPIAccessor) {
6898 6 : v8::Isolate* isolate = CcTest::isolate();
6899 6 : v8::HandleScope scope(isolate);
6900 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6901 12 : LocalContext context;
6902 :
6903 42 : CHECK(context->Global()
6904 : ->Set(context.local(), v8_str("obj1"),
6905 : templ->NewInstance(context.local()).ToLocalChecked())
6906 : .FromJust());
6907 : CompileRun("var obj2 = {};");
6908 :
6909 30 : CHECK(GetGlobalProperty(&context, "obj1")
6910 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6911 : v8_str("donut"))
6912 : .FromJust());
6913 30 : CHECK(GetGlobalProperty(&context, "obj2")
6914 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6915 : v8_str("donut"))
6916 : .FromJust());
6917 :
6918 6 : ExpectString("obj1[239]", "239");
6919 6 : ExpectString("obj2[239]", "239");
6920 6 : ExpectString("obj1['239']", "239");
6921 12 : ExpectString("obj2['239']", "239");
6922 6 : }
6923 :
6924 :
6925 28337 : v8::Persistent<Value> xValue;
6926 :
6927 :
6928 120 : static void SetXValue(Local<Name> name, Local<Value> value,
6929 : const v8::PropertyCallbackInfo<void>& info) {
6930 120 : Local<Context> context = info.GetIsolate()->GetCurrentContext();
6931 240 : CHECK(value->Equals(context, v8_num(4)).FromJust());
6932 360 : CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6933 360 : CHECK(name->Equals(context, v8_str("x")).FromJust());
6934 120 : CHECK(xValue.IsEmpty());
6935 : xValue.Reset(info.GetIsolate(), value);
6936 120 : }
6937 :
6938 :
6939 28343 : THREADED_TEST(SimplePropertyWrite) {
6940 6 : v8::Isolate* isolate = CcTest::isolate();
6941 6 : v8::HandleScope scope(isolate);
6942 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6943 18 : templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6944 12 : LocalContext context;
6945 36 : CHECK(context->Global()
6946 : ->Set(context.local(), v8_str("obj"),
6947 : templ->NewInstance(context.local()).ToLocalChecked())
6948 : .FromJust());
6949 : Local<Script> script = v8_compile("obj.x = 4");
6950 66 : for (int i = 0; i < 10; i++) {
6951 60 : CHECK(xValue.IsEmpty());
6952 60 : script->Run(context.local()).ToLocalChecked();
6953 240 : CHECK(v8_num(4)
6954 : ->Equals(context.local(),
6955 : Local<Value>::New(CcTest::isolate(), xValue))
6956 : .FromJust());
6957 : xValue.Reset();
6958 6 : }
6959 6 : }
6960 :
6961 :
6962 28343 : THREADED_TEST(SetterOnly) {
6963 6 : v8::Isolate* isolate = CcTest::isolate();
6964 6 : v8::HandleScope scope(isolate);
6965 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6966 18 : templ->SetAccessor(v8_str("x"), nullptr, SetXValue, v8_str("donut"));
6967 12 : LocalContext context;
6968 36 : 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; obj.x");
6973 66 : 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 6 : }
6982 6 : }
6983 :
6984 :
6985 28343 : THREADED_TEST(NoAccessors) {
6986 6 : v8::Isolate* isolate = CcTest::isolate();
6987 6 : v8::HandleScope scope(isolate);
6988 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6989 : templ->SetAccessor(v8_str("x"),
6990 : static_cast<v8::AccessorGetterCallback>(nullptr), nullptr,
6991 12 : v8_str("donut"));
6992 12 : LocalContext context;
6993 36 : CHECK(context->Global()
6994 : ->Set(context.local(), v8_str("obj"),
6995 : templ->NewInstance(context.local()).ToLocalChecked())
6996 : .FromJust());
6997 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
6998 66 : for (int i = 0; i < 10; i++) {
6999 60 : script->Run(context.local()).ToLocalChecked();
7000 6 : }
7001 6 : }
7002 :
7003 :
7004 28343 : THREADED_TEST(MultiContexts) {
7005 6 : v8::Isolate* isolate = CcTest::isolate();
7006 6 : v8::HandleScope scope(isolate);
7007 6 : v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7008 : templ->Set(v8_str("dummy"),
7009 18 : v8::FunctionTemplate::New(isolate, DummyCallHandler));
7010 :
7011 6 : Local<String> password = v8_str("Password");
7012 :
7013 : // Create an environment
7014 12 : LocalContext context0(nullptr, templ);
7015 6 : context0->SetSecurityToken(password);
7016 6 : v8::Local<v8::Object> global0 = context0->Global();
7017 18 : CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
7018 : .FromJust());
7019 24 : CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
7020 : .ToLocalChecked()
7021 : ->Int32Value(context0.local())
7022 : .FromJust());
7023 :
7024 : // Create an independent environment
7025 12 : LocalContext context1(nullptr, templ);
7026 6 : context1->SetSecurityToken(password);
7027 6 : v8::Local<v8::Object> global1 = context1->Global();
7028 18 : CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
7029 : .FromJust());
7030 12 : CHECK(!global0->Equals(context1.local(), global1).FromJust());
7031 24 : CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
7032 : .ToLocalChecked()
7033 : ->Int32Value(context0.local())
7034 : .FromJust());
7035 24 : CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
7036 : .ToLocalChecked()
7037 : ->Int32Value(context1.local())
7038 : .FromJust());
7039 :
7040 : // Now create a new context with the old global
7041 12 : LocalContext context2(nullptr, templ, global1);
7042 6 : context2->SetSecurityToken(password);
7043 6 : v8::Local<v8::Object> global2 = context2->Global();
7044 12 : CHECK(global1->Equals(context2.local(), global2).FromJust());
7045 24 : CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
7046 : .ToLocalChecked()
7047 : ->Int32Value(context1.local())
7048 : .FromJust());
7049 24 : CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
7050 : .ToLocalChecked()
7051 : ->Int32Value(context2.local())
7052 6 : .FromJust());
7053 6 : }
7054 :
7055 :
7056 28343 : THREADED_TEST(FunctionPrototypeAcrossContexts) {
7057 : // Make sure that functions created by cloning boilerplates cannot
7058 : // communicate through their __proto__ field.
7059 :
7060 6 : v8::HandleScope scope(CcTest::isolate());
7061 :
7062 12 : LocalContext env0;
7063 6 : v8::Local<v8::Object> global0 = env0->Global();
7064 18 : v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
7065 6 : .ToLocalChecked()
7066 : .As<v8::Object>();
7067 : v8::Local<v8::Object> tostring0 =
7068 18 : object0->Get(env0.local(), v8_str("toString"))
7069 6 : .ToLocalChecked()
7070 : .As<v8::Object>();
7071 : v8::Local<v8::Object> proto0 =
7072 18 : tostring0->Get(env0.local(), v8_str("__proto__"))
7073 6 : .ToLocalChecked()
7074 : .As<v8::Object>();
7075 18 : CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
7076 :
7077 12 : LocalContext env1;
7078 6 : v8::Local<v8::Object> global1 = env1->Global();
7079 18 : v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
7080 6 : .ToLocalChecked()
7081 : .As<v8::Object>();
7082 : v8::Local<v8::Object> tostring1 =
7083 18 : object1->Get(env1.local(), v8_str("toString"))
7084 6 : .ToLocalChecked()
7085 : .As<v8::Object>();
7086 : v8::Local<v8::Object> proto1 =
7087 18 : tostring1->Get(env1.local(), v8_str("__proto__"))
7088 6 : .ToLocalChecked()
7089 : .As<v8::Object>();
7090 24 : CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
7091 6 : }
7092 :
7093 :
7094 28343 : THREADED_TEST(Regress892105) {
7095 : // Make sure that object and array literals created by cloning
7096 : // boilerplates cannot communicate through their __proto__
7097 : // field. This is rather difficult to check, but we try to add stuff
7098 : // to Object.prototype and Array.prototype and create a new
7099 : // environment. This should succeed.
7100 :
7101 6 : v8::HandleScope scope(CcTest::isolate());
7102 :
7103 : Local<String> source = v8_str(
7104 : "Object.prototype.obj = 1234;"
7105 : "Array.prototype.arr = 4567;"
7106 6 : "8901");
7107 :
7108 12 : LocalContext env0;
7109 6 : Local<Script> script0 = v8_compile(source);
7110 24 : CHECK_EQ(8901.0, script0->Run(env0.local())
7111 : .ToLocalChecked()
7112 : ->NumberValue(env0.local())
7113 : .FromJust());
7114 :
7115 12 : LocalContext env1;
7116 6 : Local<Script> script1 = v8_compile(source);
7117 24 : CHECK_EQ(8901.0, script1->Run(env1.local())
7118 : .ToLocalChecked()
7119 : ->NumberValue(env1.local())
7120 6 : .FromJust());
7121 6 : }
7122 :
7123 60 : static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
7124 : args.GetReturnValue().Set(args.This());
7125 30 : }
7126 :
7127 28343 : THREADED_TEST(UndetectableObject) {
7128 6 : LocalContext env;
7129 12 : v8::HandleScope scope(env->GetIsolate());
7130 :
7131 : Local<v8::FunctionTemplate> desc =
7132 6 : v8::FunctionTemplate::New(env->GetIsolate());
7133 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7134 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7135 :
7136 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7137 6 : .ToLocalChecked()
7138 6 : ->NewInstance(env.local())
7139 : .ToLocalChecked();
7140 30 : CHECK(
7141 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7142 :
7143 6 : ExpectString("undetectable.toString()", "[object Object]");
7144 6 : ExpectString("typeof undetectable", "undefined");
7145 6 : ExpectString("typeof(undetectable)", "undefined");
7146 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
7147 6 : ExpectBoolean("typeof undetectable == 'object'", false);
7148 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7149 6 : ExpectBoolean("!undetectable", true);
7150 :
7151 6 : ExpectObject("true&&undetectable", obj);
7152 6 : ExpectBoolean("false&&undetectable", false);
7153 6 : ExpectBoolean("true||undetectable", true);
7154 6 : ExpectObject("false||undetectable", obj);
7155 :
7156 6 : ExpectObject("undetectable&&true", obj);
7157 6 : ExpectObject("undetectable&&false", obj);
7158 6 : ExpectBoolean("undetectable||true", true);
7159 6 : ExpectBoolean("undetectable||false", false);
7160 :
7161 6 : ExpectBoolean("undetectable==null", true);
7162 6 : ExpectBoolean("null==undetectable", true);
7163 6 : ExpectBoolean("undetectable==undefined", true);
7164 6 : ExpectBoolean("undefined==undetectable", true);
7165 6 : ExpectBoolean("undetectable==undetectable", true);
7166 :
7167 :
7168 6 : ExpectBoolean("undetectable===null", false);
7169 6 : ExpectBoolean("null===undetectable", false);
7170 6 : ExpectBoolean("undetectable===undefined", false);
7171 6 : ExpectBoolean("undefined===undetectable", false);
7172 12 : ExpectBoolean("undetectable===undetectable", true);
7173 6 : }
7174 :
7175 :
7176 28343 : THREADED_TEST(VoidLiteral) {
7177 6 : LocalContext env;
7178 6 : v8::Isolate* isolate = env->GetIsolate();
7179 12 : v8::HandleScope scope(isolate);
7180 :
7181 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7182 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7183 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7184 :
7185 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7186 6 : .ToLocalChecked()
7187 6 : ->NewInstance(env.local())
7188 : .ToLocalChecked();
7189 30 : CHECK(
7190 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7191 :
7192 6 : ExpectBoolean("undefined == void 0", true);
7193 6 : ExpectBoolean("undetectable == void 0", true);
7194 6 : ExpectBoolean("null == void 0", true);
7195 6 : ExpectBoolean("undefined === void 0", true);
7196 6 : ExpectBoolean("undetectable === void 0", false);
7197 6 : ExpectBoolean("null === void 0", false);
7198 :
7199 6 : ExpectBoolean("void 0 == undefined", true);
7200 6 : ExpectBoolean("void 0 == undetectable", true);
7201 6 : ExpectBoolean("void 0 == null", true);
7202 6 : ExpectBoolean("void 0 === undefined", true);
7203 6 : ExpectBoolean("void 0 === undetectable", false);
7204 6 : ExpectBoolean("void 0 === null", false);
7205 :
7206 : ExpectString(
7207 : "(function() {"
7208 : " try {"
7209 : " return x === void 0;"
7210 : " } catch(e) {"
7211 : " return e.toString();"
7212 : " }"
7213 : "})()",
7214 6 : "ReferenceError: x is not defined");
7215 : ExpectString(
7216 : "(function() {"
7217 : " try {"
7218 : " return void 0 === x;"
7219 : " } catch(e) {"
7220 : " return e.toString();"
7221 : " }"
7222 : "})()",
7223 12 : "ReferenceError: x is not defined");
7224 6 : }
7225 :
7226 :
7227 28343 : THREADED_TEST(ExtensibleOnUndetectable) {
7228 6 : LocalContext env;
7229 6 : v8::Isolate* isolate = env->GetIsolate();
7230 12 : v8::HandleScope scope(isolate);
7231 :
7232 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7233 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7234 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7235 :
7236 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7237 6 : .ToLocalChecked()
7238 6 : ->NewInstance(env.local())
7239 : .ToLocalChecked();
7240 30 : CHECK(
7241 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7242 :
7243 : Local<String> source = v8_str(
7244 : "undetectable.x = 42;"
7245 6 : "undetectable.x");
7246 :
7247 6 : Local<Script> script = v8_compile(source);
7248 :
7249 24 : CHECK(v8::Integer::New(isolate, 42)
7250 : ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7251 : .FromJust());
7252 :
7253 6 : ExpectBoolean("Object.isExtensible(undetectable)", true);
7254 :
7255 6 : source = v8_str("Object.preventExtensions(undetectable);");
7256 6 : script = v8_compile(source);
7257 6 : script->Run(env.local()).ToLocalChecked();
7258 6 : ExpectBoolean("Object.isExtensible(undetectable)", false);
7259 :
7260 6 : source = v8_str("undetectable.y = 2000;");
7261 6 : script = v8_compile(source);
7262 6 : script->Run(env.local()).ToLocalChecked();
7263 12 : ExpectBoolean("undetectable.y == undefined", true);
7264 6 : }
7265 :
7266 28343 : THREADED_TEST(ConstructCallWithUndetectable) {
7267 6 : LocalContext env;
7268 6 : v8::Isolate* isolate = env->GetIsolate();
7269 12 : v8::HandleScope scope(isolate);
7270 :
7271 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7272 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7273 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7274 :
7275 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7276 6 : .ToLocalChecked()
7277 6 : ->NewInstance(env.local())
7278 : .ToLocalChecked();
7279 30 : CHECK(
7280 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7281 :
7282 : // Undetectable object cannot be called as constructor.
7283 12 : v8::TryCatch try_catch(env->GetIsolate());
7284 6 : CHECK(CompileRun("new undetectable()").IsEmpty());
7285 6 : CHECK(try_catch.HasCaught());
7286 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
7287 6 : CHECK_EQ(0, strcmp("TypeError: undetectable is not a constructor",
7288 6 : *exception_value));
7289 6 : }
7290 :
7291 : static int increment_callback_counter = 0;
7292 :
7293 12 : static void IncrementCounterConstructCallback(
7294 36 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7295 12 : increment_callback_counter++;
7296 48 : CHECK(Local<Object>::Cast(args.NewTarget())
7297 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("counter"),
7298 : v8_num(increment_callback_counter))
7299 : .FromJust());
7300 : args.GetReturnValue().Set(args.NewTarget());
7301 12 : }
7302 :
7303 28343 : THREADED_TEST(SetCallAsFunctionHandlerConstructor) {
7304 6 : LocalContext env;
7305 6 : v8::Isolate* isolate = env->GetIsolate();
7306 12 : v8::HandleScope scope(isolate);
7307 :
7308 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7309 : desc->InstanceTemplate()->SetCallAsFunctionHandler(
7310 12 : IncrementCounterConstructCallback); // callable
7311 :
7312 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7313 6 : .ToLocalChecked()
7314 6 : ->NewInstance(env.local())
7315 : .ToLocalChecked();
7316 30 : CHECK(env->Global()->Set(env.local(), v8_str("Counter"), obj).FromJust());
7317 :
7318 6 : ExpectInt32("(new Counter()).counter", 1);
7319 6 : CHECK_EQ(1, increment_callback_counter);
7320 6 : ExpectInt32("(new Counter()).counter", 2);
7321 12 : CHECK_EQ(2, increment_callback_counter);
7322 6 : }
7323 : // The point of this test is type checking. We run it only so compilers
7324 : // don't complain about an unused function.
7325 28342 : TEST(PersistentHandles) {
7326 5 : LocalContext env;
7327 5 : v8::Isolate* isolate = CcTest::isolate();
7328 10 : v8::HandleScope scope(isolate);
7329 5 : Local<String> str = v8_str("foo");
7330 : v8::Persistent<String> p_str(isolate, str);
7331 : p_str.Reset();
7332 : Local<Script> scr = v8_compile("");
7333 : v8::Persistent<Script> p_scr(isolate, scr);
7334 : p_scr.Reset();
7335 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7336 : v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7337 5 : p_templ.Reset();
7338 5 : }
7339 :
7340 :
7341 6 : static void HandleLogDelegator(
7342 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7343 6 : ApiTestFuzzer::Fuzz();
7344 6 : }
7345 :
7346 :
7347 28343 : THREADED_TEST(GlobalObjectTemplate) {
7348 6 : v8::Isolate* isolate = CcTest::isolate();
7349 6 : v8::HandleScope handle_scope(isolate);
7350 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7351 : global_template->Set(v8_str("JSNI_Log"),
7352 18 : v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7353 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
7354 : Context::Scope context_scope(context);
7355 6 : CompileRun("JSNI_Log('LOG')");
7356 6 : }
7357 :
7358 :
7359 : static const char* kSimpleExtensionSource =
7360 : "function Foo() {"
7361 : " return 4;"
7362 : "}";
7363 :
7364 :
7365 28342 : TEST(SimpleExtensions) {
7366 5 : v8::HandleScope handle_scope(CcTest::isolate());
7367 5 : v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7368 5 : const char* extension_names[] = {"simpletest"};
7369 : v8::ExtensionConfiguration extensions(1, extension_names);
7370 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7371 : Context::Scope lock(context);
7372 : v8::Local<Value> result = CompileRun("Foo()");
7373 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7374 5 : .FromJust());
7375 5 : }
7376 :
7377 :
7378 : static const char* kStackTraceFromExtensionSource =
7379 : "function foo() {"
7380 : " throw new Error();"
7381 : "}"
7382 : "function bar() {"
7383 : " foo();"
7384 : "}";
7385 :
7386 :
7387 28342 : TEST(StackTraceInExtension) {
7388 5 : v8::HandleScope handle_scope(CcTest::isolate());
7389 : v8::RegisterExtension(
7390 5 : new Extension("stacktracetest", kStackTraceFromExtensionSource));
7391 5 : const char* extension_names[] = {"stacktracetest"};
7392 : v8::ExtensionConfiguration extensions(1, extension_names);
7393 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7394 : Context::Scope lock(context);
7395 : CompileRun(
7396 : "function user() { bar(); }"
7397 : "var error;"
7398 : "try{ user(); } catch (e) { error = e; }");
7399 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7400 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7401 10 : CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7402 5 : }
7403 :
7404 :
7405 28342 : TEST(NullExtensions) {
7406 5 : v8::HandleScope handle_scope(CcTest::isolate());
7407 5 : v8::RegisterExtension(new Extension("nulltest", nullptr));
7408 5 : const char* extension_names[] = {"nulltest"};
7409 : v8::ExtensionConfiguration extensions(1, extension_names);
7410 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7411 : Context::Scope lock(context);
7412 : v8::Local<Value> result = CompileRun("1+3");
7413 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7414 5 : .FromJust());
7415 5 : }
7416 :
7417 : static const char* kEmbeddedExtensionSource =
7418 : "function Ret54321(){return 54321;}~~@@$"
7419 : "$%% THIS IS A SERIES OF NON-nullptr-TERMINATED STRINGS.";
7420 : static const int kEmbeddedExtensionSourceValidLen = 34;
7421 :
7422 :
7423 28342 : TEST(ExtensionMissingSourceLength) {
7424 5 : v8::HandleScope handle_scope(CcTest::isolate());
7425 : v8::RegisterExtension(
7426 5 : new Extension("srclentest_fail", kEmbeddedExtensionSource));
7427 5 : const char* extension_names[] = {"srclentest_fail"};
7428 : v8::ExtensionConfiguration extensions(1, extension_names);
7429 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7430 5 : CHECK_NULL(*context);
7431 5 : }
7432 :
7433 :
7434 28342 : TEST(ExtensionWithSourceLength) {
7435 20 : for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7436 : source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7437 15 : v8::HandleScope handle_scope(CcTest::isolate());
7438 : i::ScopedVector<char> extension_name(32);
7439 15 : i::SNPrintF(extension_name, "ext #%d", source_len);
7440 : v8::RegisterExtension(new Extension(extension_name.start(),
7441 : kEmbeddedExtensionSource, 0, nullptr,
7442 15 : source_len));
7443 15 : const char* extension_names[1] = {extension_name.start()};
7444 : v8::ExtensionConfiguration extensions(1, extension_names);
7445 15 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7446 15 : if (source_len == kEmbeddedExtensionSourceValidLen) {
7447 : Context::Scope lock(context);
7448 5 : v8::Local<Value> result = CompileRun("Ret54321()");
7449 15 : CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7450 : ->Equals(context, result)
7451 : .FromJust());
7452 : } else {
7453 : // Anything but exactly the right length should fail to compile.
7454 10 : CHECK_NULL(*context);
7455 : }
7456 15 : }
7457 5 : }
7458 :
7459 :
7460 : static const char* kEvalExtensionSource1 =
7461 : "function UseEval1() {"
7462 : " var x = 42;"
7463 : " return eval('x');"
7464 : "}";
7465 :
7466 :
7467 : static const char* kEvalExtensionSource2 =
7468 : "(function() {"
7469 : " var x = 42;"
7470 : " function e() {"
7471 : " return eval('x');"
7472 : " }"
7473 : " this.UseEval2 = e;"
7474 : "})()";
7475 :
7476 :
7477 28342 : TEST(UseEvalFromExtension) {
7478 5 : v8::HandleScope handle_scope(CcTest::isolate());
7479 5 : v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7480 5 : v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7481 5 : const char* extension_names[] = {"evaltest1", "evaltest2"};
7482 : v8::ExtensionConfiguration extensions(2, extension_names);
7483 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7484 : Context::Scope lock(context);
7485 : v8::Local<Value> result = CompileRun("UseEval1()");
7486 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7487 : .FromJust());
7488 : result = CompileRun("UseEval2()");
7489 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7490 5 : .FromJust());
7491 5 : }
7492 :
7493 :
7494 : static const char* kWithExtensionSource1 =
7495 : "function UseWith1() {"
7496 : " var x = 42;"
7497 : " with({x:87}) { return x; }"
7498 : "}";
7499 :
7500 :
7501 : static const char* kWithExtensionSource2 =
7502 : "(function() {"
7503 : " var x = 42;"
7504 : " function e() {"
7505 : " with ({x:87}) { return x; }"
7506 : " }"
7507 : " this.UseWith2 = e;"
7508 : "})()";
7509 :
7510 :
7511 28342 : TEST(UseWithFromExtension) {
7512 5 : v8::HandleScope handle_scope(CcTest::isolate());
7513 5 : v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7514 5 : v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7515 5 : const char* extension_names[] = {"withtest1", "withtest2"};
7516 : v8::ExtensionConfiguration extensions(2, extension_names);
7517 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7518 : Context::Scope lock(context);
7519 : v8::Local<Value> result = CompileRun("UseWith1()");
7520 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7521 : .FromJust());
7522 : result = CompileRun("UseWith2()");
7523 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7524 5 : .FromJust());
7525 5 : }
7526 :
7527 :
7528 28342 : TEST(AutoExtensions) {
7529 5 : v8::HandleScope handle_scope(CcTest::isolate());
7530 5 : Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7531 : extension->set_auto_enable(true);
7532 5 : v8::RegisterExtension(extension);
7533 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
7534 : Context::Scope lock(context);
7535 : v8::Local<Value> result = CompileRun("Foo()");
7536 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7537 5 : .FromJust());
7538 5 : }
7539 :
7540 :
7541 : static const char* kSyntaxErrorInExtensionSource = "[";
7542 :
7543 :
7544 : // Test that a syntax error in an extension does not cause a fatal
7545 : // error but results in an empty context.
7546 28342 : TEST(SyntaxErrorExtensions) {
7547 5 : v8::HandleScope handle_scope(CcTest::isolate());
7548 : v8::RegisterExtension(
7549 5 : new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
7550 5 : const char* extension_names[] = {"syntaxerror"};
7551 : v8::ExtensionConfiguration extensions(1, extension_names);
7552 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7553 5 : CHECK(context.IsEmpty());
7554 5 : }
7555 :
7556 :
7557 : static const char* kExceptionInExtensionSource = "throw 42";
7558 :
7559 :
7560 : // Test that an exception when installing an extension does not cause
7561 : // a fatal error but results in an empty context.
7562 28342 : TEST(ExceptionExtensions) {
7563 5 : v8::HandleScope handle_scope(CcTest::isolate());
7564 : v8::RegisterExtension(
7565 5 : new Extension("exception", kExceptionInExtensionSource));
7566 5 : const char* extension_names[] = {"exception"};
7567 : v8::ExtensionConfiguration extensions(1, extension_names);
7568 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7569 5 : CHECK(context.IsEmpty());
7570 5 : }
7571 :
7572 : static const char* kNativeCallInExtensionSource =
7573 : "function call_runtime_last_index_of(x) {"
7574 : " return %StringLastIndexOf(x, 'bob');"
7575 : "}";
7576 :
7577 : static const char* kNativeCallTest =
7578 : "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7579 :
7580 : // Test that a native runtime calls are supported in extensions.
7581 28342 : TEST(NativeCallInExtensions) {
7582 5 : v8::HandleScope handle_scope(CcTest::isolate());
7583 : v8::RegisterExtension(
7584 5 : new Extension("nativecall", kNativeCallInExtensionSource));
7585 5 : const char* extension_names[] = {"nativecall"};
7586 : v8::ExtensionConfiguration extensions(1, extension_names);
7587 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7588 : Context::Scope lock(context);
7589 5 : v8::Local<Value> result = CompileRun(kNativeCallTest);
7590 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24))
7591 5 : .FromJust());
7592 5 : }
7593 :
7594 :
7595 0 : class NativeFunctionExtension : public Extension {
7596 : public:
7597 : NativeFunctionExtension(const char* name, const char* source,
7598 : v8::FunctionCallback fun = &Echo)
7599 15 : : Extension(name, source), function_(fun) {}
7600 :
7601 5 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7602 : v8::Isolate* isolate, v8::Local<v8::String> name) override {
7603 5 : return v8::FunctionTemplate::New(isolate, function_);
7604 : }
7605 :
7606 10 : static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7607 5 : if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7608 5 : }
7609 :
7610 : private:
7611 : v8::FunctionCallback function_;
7612 : };
7613 :
7614 :
7615 28342 : TEST(NativeFunctionDeclaration) {
7616 5 : v8::HandleScope handle_scope(CcTest::isolate());
7617 : const char* name = "nativedecl";
7618 : v8::RegisterExtension(
7619 10 : new NativeFunctionExtension(name, "native function foo();"));
7620 5 : const char* extension_names[] = {name};
7621 : v8::ExtensionConfiguration extensions(1, extension_names);
7622 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7623 : Context::Scope lock(context);
7624 : v8::Local<Value> result = CompileRun("foo(42);");
7625 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7626 5 : .FromJust());
7627 5 : }
7628 :
7629 :
7630 28342 : TEST(NativeFunctionDeclarationError) {
7631 5 : v8::HandleScope handle_scope(CcTest::isolate());
7632 : const char* name = "nativedeclerr";
7633 : // Syntax error in extension code.
7634 : v8::RegisterExtension(
7635 10 : new NativeFunctionExtension(name, "native\nfunction foo();"));
7636 5 : const char* extension_names[] = {name};
7637 : v8::ExtensionConfiguration extensions(1, extension_names);
7638 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7639 5 : CHECK(context.IsEmpty());
7640 5 : }
7641 :
7642 :
7643 28342 : TEST(NativeFunctionDeclarationErrorEscape) {
7644 5 : v8::HandleScope handle_scope(CcTest::isolate());
7645 : const char* name = "nativedeclerresc";
7646 : // Syntax error in extension code - escape code in "native" means that
7647 : // it's not treated as a keyword.
7648 : v8::RegisterExtension(
7649 10 : new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
7650 5 : const char* extension_names[] = {name};
7651 : v8::ExtensionConfiguration extensions(1, extension_names);
7652 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7653 5 : CHECK(context.IsEmpty());
7654 5 : }
7655 :
7656 :
7657 30 : static void CheckDependencies(const char* name, const char* expected) {
7658 30 : v8::HandleScope handle_scope(CcTest::isolate());
7659 : v8::ExtensionConfiguration config(1, &name);
7660 60 : LocalContext context(&config);
7661 210 : CHECK(
7662 : v8_str(expected)
7663 : ->Equals(context.local(), context->Global()
7664 : ->Get(context.local(), v8_str("loaded"))
7665 : .ToLocalChecked())
7666 30 : .FromJust());
7667 30 : }
7668 :
7669 :
7670 : /*
7671 : * Configuration:
7672 : *
7673 : * /-- B <--\
7674 : * A <- -- D <-- E
7675 : * \-- C <--/
7676 : */
7677 28343 : THREADED_TEST(ExtensionDependency) {
7678 : static const char* kEDeps[] = {"D"};
7679 6 : v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7680 : static const char* kDDeps[] = {"B", "C"};
7681 6 : v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7682 : static const char* kBCDeps[] = {"A"};
7683 6 : v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7684 6 : v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7685 6 : v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7686 6 : CheckDependencies("A", "undefinedA");
7687 6 : CheckDependencies("B", "undefinedAB");
7688 6 : CheckDependencies("C", "undefinedAC");
7689 6 : CheckDependencies("D", "undefinedABCD");
7690 6 : CheckDependencies("E", "undefinedABCDE");
7691 6 : v8::HandleScope handle_scope(CcTest::isolate());
7692 : static const char* exts[2] = {"C", "E"};
7693 : v8::ExtensionConfiguration config(2, exts);
7694 12 : LocalContext context(&config);
7695 42 : CHECK(
7696 : v8_str("undefinedACBDE")
7697 : ->Equals(context.local(), context->Global()
7698 : ->Get(context.local(), v8_str("loaded"))
7699 : .ToLocalChecked())
7700 6 : .FromJust());
7701 6 : }
7702 :
7703 :
7704 : static const char* kExtensionTestScript =
7705 : "native function A();"
7706 : "native function B();"
7707 : "native function C();"
7708 : "function Foo(i) {"
7709 : " if (i == 0) return A();"
7710 : " if (i == 1) return B();"
7711 : " if (i == 2) return C();"
7712 : "}";
7713 :
7714 :
7715 738 : static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7716 198 : ApiTestFuzzer::Fuzz();
7717 198 : if (args.IsConstructCall()) {
7718 720 : CHECK(args.This()
7719 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7720 : args.Data())
7721 : .FromJust());
7722 : args.GetReturnValue().SetNull();
7723 378 : return;
7724 : }
7725 : args.GetReturnValue().Set(args.Data());
7726 : }
7727 :
7728 :
7729 0 : class FunctionExtension : public Extension {
7730 : public:
7731 12 : FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7732 : v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7733 : v8::Isolate* isolate, v8::Local<String> name) override;
7734 : };
7735 :
7736 :
7737 : static int lookup_count = 0;
7738 33 : v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7739 : v8::Isolate* isolate, v8::Local<String> name) {
7740 33 : lookup_count++;
7741 66 : if (name->StrictEquals(v8_str("A"))) {
7742 : return v8::FunctionTemplate::New(isolate, CallFun,
7743 22 : v8::Integer::New(isolate, 8));
7744 44 : } else if (name->StrictEquals(v8_str("B"))) {
7745 : return v8::FunctionTemplate::New(isolate, CallFun,
7746 22 : v8::Integer::New(isolate, 7));
7747 22 : } else if (name->StrictEquals(v8_str("C"))) {
7748 : return v8::FunctionTemplate::New(isolate, CallFun,
7749 22 : v8::Integer::New(isolate, 6));
7750 : } else {
7751 0 : return v8::Local<v8::FunctionTemplate>();
7752 : }
7753 : }
7754 :
7755 :
7756 28343 : THREADED_TEST(FunctionLookup) {
7757 6 : v8::RegisterExtension(new FunctionExtension());
7758 6 : v8::HandleScope handle_scope(CcTest::isolate());
7759 : static const char* exts[1] = {"functiontest"};
7760 : v8::ExtensionConfiguration config(1, exts);
7761 12 : LocalContext context(&config);
7762 6 : CHECK_EQ(3, lookup_count);
7763 18 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7764 : ->Equals(context.local(), CompileRun("Foo(0)"))
7765 : .FromJust());
7766 18 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7767 : ->Equals(context.local(), CompileRun("Foo(1)"))
7768 : .FromJust());
7769 18 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7770 : ->Equals(context.local(), CompileRun("Foo(2)"))
7771 6 : .FromJust());
7772 6 : }
7773 :
7774 :
7775 28343 : THREADED_TEST(NativeFunctionConstructCall) {
7776 6 : v8::RegisterExtension(new FunctionExtension());
7777 6 : v8::HandleScope handle_scope(CcTest::isolate());
7778 : static const char* exts[1] = {"functiontest"};
7779 : v8::ExtensionConfiguration config(1, exts);
7780 12 : LocalContext context(&config);
7781 66 : for (int i = 0; i < 10; i++) {
7782 : // Run a few times to ensure that allocation of objects doesn't
7783 : // change behavior of a constructor function.
7784 180 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7785 : ->Equals(context.local(), CompileRun("(new A()).data"))
7786 : .FromJust());
7787 180 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7788 : ->Equals(context.local(), CompileRun("(new B()).data"))
7789 : .FromJust());
7790 180 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7791 : ->Equals(context.local(), CompileRun("(new C()).data"))
7792 : .FromJust());
7793 6 : }
7794 6 : }
7795 :
7796 :
7797 : static const char* last_location;
7798 : static const char* last_message;
7799 10 : void StoringErrorCallback(const char* location, const char* message) {
7800 10 : if (last_location == nullptr) {
7801 10 : last_location = location;
7802 10 : last_message = message;
7803 : }
7804 10 : }
7805 :
7806 :
7807 : // ErrorReporting creates a circular extensions configuration and
7808 : // tests that the fatal error handler gets called. This renders V8
7809 : // unusable and therefore this test cannot be run in parallel.
7810 28342 : TEST(ErrorReporting) {
7811 5 : CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7812 : static const char* aDeps[] = {"B"};
7813 5 : v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7814 : static const char* bDeps[] = {"A"};
7815 5 : v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7816 5 : last_location = nullptr;
7817 : v8::ExtensionConfiguration config(1, bDeps);
7818 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7819 5 : CHECK(context.IsEmpty());
7820 5 : CHECK(last_location);
7821 5 : }
7822 :
7823 : static size_t dcheck_count;
7824 0 : void DcheckErrorCallback(const char* file, int line, const char* message) {
7825 0 : last_message = message;
7826 0 : ++dcheck_count;
7827 0 : }
7828 :
7829 28342 : TEST(DcheckErrorHandler) {
7830 5 : V8::SetDcheckErrorHandler(DcheckErrorCallback);
7831 :
7832 5 : last_message = nullptr;
7833 5 : dcheck_count = 0;
7834 :
7835 : DCHECK(false && "w00t");
7836 : #ifdef DEBUG
7837 : CHECK_EQ(dcheck_count, 1);
7838 : CHECK(last_message);
7839 : CHECK(std::string(last_message).find("w00t") != std::string::npos);
7840 : #else
7841 : // The DCHECK should be a noop in non-DEBUG builds.
7842 5 : CHECK_EQ(dcheck_count, 0);
7843 : #endif
7844 5 : }
7845 :
7846 6 : static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7847 : v8::Local<Value> data) {
7848 6 : v8::Isolate* isolate = CcTest::isolate();
7849 6 : Local<Context> context = isolate->GetCurrentContext();
7850 12 : CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7851 18 : CHECK(v8::Undefined(isolate)
7852 : ->Equals(context, message->GetScriptOrigin().ResourceName())
7853 : .FromJust());
7854 12 : message->GetLineNumber(context).FromJust();
7855 6 : message->GetSourceLine(context).ToLocalChecked();
7856 6 : }
7857 :
7858 :
7859 28343 : THREADED_TEST(ErrorWithMissingScriptInfo) {
7860 6 : LocalContext context;
7861 12 : v8::HandleScope scope(context->GetIsolate());
7862 6 : context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7863 : CompileRun("throw Error()");
7864 : context->GetIsolate()->RemoveMessageListeners(
7865 12 : MissingScriptInfoMessageListener);
7866 6 : }
7867 :
7868 :
7869 : struct FlagAndPersistent {
7870 : bool flag;
7871 : v8::Global<v8::Object> handle;
7872 : };
7873 :
7874 80 : static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7875 40 : data.GetParameter()->flag = true;
7876 : data.GetParameter()->handle.Reset();
7877 40 : }
7878 :
7879 20 : static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7880 20 : i::FLAG_stress_incremental_marking = false;
7881 : // Parallel scavenge introduces too much fragmentation.
7882 20 : i::FLAG_parallel_scavenge = false;
7883 20 : v8::Isolate* iso = CcTest::isolate();
7884 20 : v8::HandleScope scope(iso);
7885 20 : v8::Local<Context> context = Context::New(iso);
7886 : Context::Scope context_scope(context);
7887 :
7888 : FlagAndPersistent object_a, object_b;
7889 :
7890 : size_t big_heap_size = 0;
7891 : size_t big_array_size = 0;
7892 :
7893 : {
7894 20 : v8::HandleScope handle_scope(iso);
7895 20 : Local<Object> a(v8::Object::New(iso));
7896 20 : Local<Object> b(v8::Object::New(iso));
7897 : object_a.handle.Reset(iso, a);
7898 : object_b.handle.Reset(iso, b);
7899 20 : if (interlinked) {
7900 30 : a->Set(context, v8_str("x"), b).FromJust();
7901 30 : b->Set(context, v8_str("x"), a).FromJust();
7902 : }
7903 20 : if (global_gc) {
7904 10 : CcTest::CollectAllGarbage();
7905 : } else {
7906 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7907 : }
7908 20 : v8::Local<Value> big_array = v8::Array::New(CcTest::isolate(), 5000);
7909 : // Verify that we created an array where the space was reserved up front.
7910 : big_array_size =
7911 : v8::internal::JSArray::cast(*v8::Utils::OpenHandle(*big_array))
7912 40 : ->elements()
7913 20 : ->Size();
7914 20 : CHECK_LE(20000, big_array_size);
7915 60 : a->Set(context, v8_str("y"), big_array).FromJust();
7916 20 : big_heap_size = CcTest::heap()->SizeOfObjects();
7917 : }
7918 :
7919 20 : object_a.flag = false;
7920 20 : object_b.flag = false;
7921 : object_a.handle.SetWeak(&object_a, &SetFlag,
7922 : v8::WeakCallbackType::kParameter);
7923 : object_b.handle.SetWeak(&object_b, &SetFlag,
7924 : v8::WeakCallbackType::kParameter);
7925 : #if __clang__
7926 : #pragma clang diagnostic push
7927 : #pragma clang diagnostic ignored "-Wdeprecated"
7928 : #endif
7929 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
7930 20 : CHECK(!object_b.handle.IsIndependent());
7931 : object_a.handle.MarkIndependent();
7932 : object_b.handle.MarkIndependent();
7933 20 : CHECK(object_b.handle.IsIndependent());
7934 : #if __clang__
7935 : #pragma clang diagnostic pop
7936 : #endif
7937 20 : if (global_gc) {
7938 10 : CcTest::CollectAllGarbage();
7939 : } else {
7940 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7941 : }
7942 : // A single GC should be enough to reclaim the memory, since we are using
7943 : // phantom handles.
7944 20 : CHECK_GT(big_heap_size - big_array_size, CcTest::heap()->SizeOfObjects());
7945 20 : CHECK(object_a.flag);
7946 40 : CHECK(object_b.flag);
7947 20 : }
7948 :
7949 28342 : TEST(IndependentWeakHandle) {
7950 5 : IndependentWeakHandle(false, false);
7951 5 : IndependentWeakHandle(false, true);
7952 5 : IndependentWeakHandle(true, false);
7953 5 : IndependentWeakHandle(true, true);
7954 5 : }
7955 :
7956 : class Trivial {
7957 : public:
7958 12 : explicit Trivial(int x) : x_(x) {}
7959 :
7960 36 : int x() { return x_; }
7961 12 : void set_x(int x) { x_ = x; }
7962 :
7963 : private:
7964 : int x_;
7965 : };
7966 :
7967 :
7968 : class Trivial2 {
7969 : public:
7970 12 : Trivial2(int x, int y) : y_(y), x_(x) {}
7971 :
7972 : int x() { return x_; }
7973 12 : void set_x(int x) { x_ = x; }
7974 :
7975 : int y() { return y_; }
7976 : void set_y(int y) { y_ = y; }
7977 :
7978 : private:
7979 : int y_;
7980 : int x_;
7981 : };
7982 :
7983 12 : void CheckInternalFields(
7984 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
7985 : v8::Persistent<v8::Object>* handle = data.GetParameter();
7986 : handle->Reset();
7987 : Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
7988 12 : Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
7989 12 : CHECK_EQ(42, t1->x());
7990 12 : CHECK_EQ(103, t2->x());
7991 : t1->set_x(1729);
7992 : t2->set_x(33550336);
7993 12 : }
7994 :
7995 12 : void InternalFieldCallback(bool global_gc) {
7996 12 : LocalContext env;
7997 12 : v8::Isolate* isolate = env->GetIsolate();
7998 24 : v8::HandleScope scope(isolate);
7999 :
8000 12 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
8001 12 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
8002 : Trivial* t1;
8003 24 : Trivial2* t2;
8004 12 : instance_templ->SetInternalFieldCount(2);
8005 : v8::Persistent<v8::Object> handle;
8006 : {
8007 12 : v8::HandleScope scope(isolate);
8008 12 : Local<v8::Object> obj = templ->GetFunction(env.local())
8009 12 : .ToLocalChecked()
8010 12 : ->NewInstance(env.local())
8011 : .ToLocalChecked();
8012 : handle.Reset(isolate, obj);
8013 12 : CHECK_EQ(2, obj->InternalFieldCount());
8014 12 : CHECK(obj->GetInternalField(0)->IsUndefined());
8015 12 : t1 = new Trivial(42);
8016 12 : t2 = new Trivial2(103, 9);
8017 :
8018 12 : obj->SetAlignedPointerInInternalField(0, t1);
8019 : t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
8020 12 : CHECK_EQ(42, t1->x());
8021 :
8022 12 : obj->SetAlignedPointerInInternalField(1, t2);
8023 : t2 =
8024 : reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
8025 12 : CHECK_EQ(103, t2->x());
8026 :
8027 : handle.SetWeak<v8::Persistent<v8::Object>>(
8028 12 : &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
8029 : }
8030 12 : if (global_gc) {
8031 6 : CcTest::CollectAllGarbage();
8032 : } else {
8033 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8034 : }
8035 :
8036 12 : CHECK_EQ(1729, t1->x());
8037 12 : CHECK_EQ(33550336, t2->x());
8038 :
8039 12 : delete t1;
8040 24 : delete t2;
8041 12 : }
8042 :
8043 28343 : THREADED_TEST(InternalFieldCallback) {
8044 6 : InternalFieldCallback(false);
8045 6 : InternalFieldCallback(true);
8046 6 : }
8047 :
8048 24 : static void ResetUseValueAndSetFlag(
8049 48 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8050 : // Blink will reset the handle, and then use the other handle, so they
8051 : // can't use the same backing slot.
8052 : data.GetParameter()->handle.Reset();
8053 24 : data.GetParameter()->flag = true;
8054 24 : }
8055 :
8056 12 : void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) {
8057 : using v8::Context;
8058 : using v8::Local;
8059 : using v8::Object;
8060 :
8061 12 : v8::Isolate* iso = CcTest::isolate();
8062 12 : v8::HandleScope scope(iso);
8063 12 : v8::Local<Context> context = Context::New(iso);
8064 : Context::Scope context_scope(context);
8065 :
8066 : FlagAndPersistent object_a, object_b;
8067 :
8068 : {
8069 12 : v8::HandleScope handle_scope(iso);
8070 12 : Local<Object> a(v8::Object::New(iso));
8071 12 : Local<Object> b(v8::Object::New(iso));
8072 : object_a.handle.Reset(iso, a);
8073 : object_b.handle.Reset(iso, b);
8074 12 : if (global_gc) {
8075 6 : CcTest::PreciseCollectAllGarbage();
8076 : } else {
8077 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8078 12 : }
8079 : }
8080 :
8081 12 : object_a.flag = false;
8082 12 : object_b.flag = false;
8083 : object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
8084 : v8::WeakCallbackType::kParameter);
8085 : object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
8086 : v8::WeakCallbackType::kParameter);
8087 12 : if (!global_gc) {
8088 : #if __clang__
8089 : #pragma clang diagnostic push
8090 : #pragma clang diagnostic ignored "-Wdeprecated"
8091 : #endif
8092 : // MarkIndependent is marked deprecated but we still rely on it temporarily.
8093 : object_a.handle.MarkIndependent();
8094 : object_b.handle.MarkIndependent();
8095 6 : CHECK(object_b.handle.IsIndependent());
8096 : #if __clang__
8097 : #pragma clang diagnostic pop
8098 : #endif
8099 : }
8100 12 : if (global_gc) {
8101 6 : CcTest::PreciseCollectAllGarbage();
8102 : } else {
8103 6 : CcTest::CollectGarbage(i::NEW_SPACE);
8104 : }
8105 12 : CHECK(object_a.flag);
8106 24 : CHECK(object_b.flag);
8107 12 : }
8108 :
8109 28343 : THREADED_HEAP_TEST(ResetWeakHandle) {
8110 6 : v8::internal::heap::HeapTester::ResetWeakHandle(false);
8111 6 : v8::internal::heap::HeapTester::ResetWeakHandle(true);
8112 6 : }
8113 :
8114 24 : static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
8115 :
8116 24 : static void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
8117 :
8118 12 : static void ForceScavenge2(
8119 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8120 12 : data.GetParameter()->flag = true;
8121 : InvokeScavenge();
8122 12 : }
8123 :
8124 12 : static void ForceScavenge1(
8125 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8126 : data.GetParameter()->handle.Reset();
8127 : data.SetSecondPassCallback(ForceScavenge2);
8128 12 : }
8129 :
8130 12 : static void ForceMarkSweep2(
8131 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8132 12 : data.GetParameter()->flag = true;
8133 : InvokeMarkSweep();
8134 12 : }
8135 :
8136 12 : static void ForceMarkSweep1(
8137 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8138 : data.GetParameter()->handle.Reset();
8139 : data.SetSecondPassCallback(ForceMarkSweep2);
8140 12 : }
8141 :
8142 28343 : THREADED_TEST(GCFromWeakCallbacks) {
8143 6 : v8::Isolate* isolate = CcTest::isolate();
8144 6 : v8::Locker locker(CcTest::isolate());
8145 12 : v8::HandleScope scope(isolate);
8146 6 : v8::Local<Context> context = Context::New(isolate);
8147 : Context::Scope context_scope(context);
8148 :
8149 : static const int kNumberOfGCTypes = 2;
8150 : typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
8151 : Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
8152 6 : &ForceMarkSweep1};
8153 :
8154 : typedef void (*GCInvoker)();
8155 6 : GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
8156 :
8157 18 : for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
8158 24 : for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
8159 : FlagAndPersistent object;
8160 : {
8161 24 : v8::HandleScope handle_scope(isolate);
8162 48 : object.handle.Reset(isolate, v8::Object::New(isolate));
8163 : }
8164 24 : object.flag = false;
8165 : object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
8166 24 : v8::WeakCallbackType::kParameter);
8167 : #if __clang__
8168 : #pragma clang diagnostic push
8169 : #pragma clang diagnostic ignored "-Wdeprecated"
8170 : #endif
8171 : // MarkIndependent is marked deprecated but we still rely on it
8172 : // temporarily.
8173 : object.handle.MarkIndependent();
8174 : #if __clang__
8175 : #pragma clang diagnostic pop
8176 : #endif
8177 24 : invoke_gc[outer_gc]();
8178 24 : EmptyMessageQueues(isolate);
8179 24 : CHECK(object.flag);
8180 : }
8181 6 : }
8182 6 : }
8183 :
8184 : v8::Local<Function> args_fun;
8185 :
8186 :
8187 6 : static void ArgumentsTestCallback(
8188 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
8189 6 : ApiTestFuzzer::Fuzz();
8190 : v8::Isolate* isolate = args.GetIsolate();
8191 6 : Local<Context> context = isolate->GetCurrentContext();
8192 6 : CHECK_EQ(3, args.Length());
8193 18 : CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
8194 18 : CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
8195 18 : CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
8196 12 : CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
8197 6 : v8::HandleScope scope(args.GetIsolate());
8198 6 : CcTest::CollectAllGarbage();
8199 6 : }
8200 :
8201 :
8202 28343 : THREADED_TEST(Arguments) {
8203 6 : v8::Isolate* isolate = CcTest::isolate();
8204 6 : v8::HandleScope scope(isolate);
8205 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8206 : global->Set(v8_str("f"),
8207 18 : v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8208 12 : LocalContext context(nullptr, global);
8209 : args_fun = context->Global()
8210 24 : ->Get(context.local(), v8_str("f"))
8211 6 : .ToLocalChecked()
8212 6 : .As<Function>();
8213 18 : v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
8214 6 : }
8215 :
8216 :
8217 : static int p_getter_count;
8218 : static int p_getter_count2;
8219 :
8220 :
8221 240 : static void PGetter(Local<Name> name,
8222 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8223 240 : ApiTestFuzzer::Fuzz();
8224 240 : p_getter_count++;
8225 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8226 240 : v8::Local<v8::Object> global = context->Global();
8227 960 : CHECK(
8228 : info.Holder()
8229 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8230 : .FromJust());
8231 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8232 240 : CHECK(info.This()
8233 : ->Equals(context,
8234 : global->Get(context, v8_str("o1")).ToLocalChecked())
8235 : .FromJust());
8236 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8237 240 : CHECK(info.This()
8238 : ->Equals(context,
8239 : global->Get(context, v8_str("o2")).ToLocalChecked())
8240 : .FromJust());
8241 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8242 240 : CHECK(info.This()
8243 : ->Equals(context,
8244 : global->Get(context, v8_str("o3")).ToLocalChecked())
8245 : .FromJust());
8246 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8247 240 : CHECK(info.This()
8248 : ->Equals(context,
8249 : global->Get(context, v8_str("o4")).ToLocalChecked())
8250 : .FromJust());
8251 : }
8252 240 : }
8253 :
8254 :
8255 12 : static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8256 12 : ApiTestFuzzer::Fuzz();
8257 12 : LocalContext context;
8258 84 : CHECK(context->Global()
8259 : ->Set(context.local(), v8_str("o1"),
8260 : obj->NewInstance(context.local()).ToLocalChecked())
8261 : .FromJust());
8262 : CompileRun(
8263 : "o1.__proto__ = { };"
8264 : "var o2 = { __proto__: o1 };"
8265 : "var o3 = { __proto__: o2 };"
8266 : "var o4 = { __proto__: o3 };"
8267 : "for (var i = 0; i < 10; i++) o4.p4;"
8268 : "for (var i = 0; i < 10; i++) o3.p3;"
8269 : "for (var i = 0; i < 10; i++) o2.p2;"
8270 12 : "for (var i = 0; i < 10; i++) o1.p1;");
8271 12 : }
8272 :
8273 :
8274 240 : static void PGetter2(Local<Name> name,
8275 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8276 240 : ApiTestFuzzer::Fuzz();
8277 240 : p_getter_count2++;
8278 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8279 240 : v8::Local<v8::Object> global = context->Global();
8280 960 : CHECK(
8281 : info.Holder()
8282 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8283 : .FromJust());
8284 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8285 240 : CHECK(info.This()
8286 : ->Equals(context,
8287 : global->Get(context, v8_str("o1")).ToLocalChecked())
8288 : .FromJust());
8289 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8290 240 : CHECK(info.This()
8291 : ->Equals(context,
8292 : global->Get(context, v8_str("o2")).ToLocalChecked())
8293 : .FromJust());
8294 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8295 240 : CHECK(info.This()
8296 : ->Equals(context,
8297 : global->Get(context, v8_str("o3")).ToLocalChecked())
8298 : .FromJust());
8299 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8300 240 : CHECK(info.This()
8301 : ->Equals(context,
8302 : global->Get(context, v8_str("o4")).ToLocalChecked())
8303 : .FromJust());
8304 : }
8305 240 : }
8306 :
8307 :
8308 28343 : THREADED_TEST(GetterHolders) {
8309 6 : v8::Isolate* isolate = CcTest::isolate();
8310 6 : v8::HandleScope scope(isolate);
8311 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8312 12 : obj->SetAccessor(v8_str("p1"), PGetter);
8313 12 : obj->SetAccessor(v8_str("p2"), PGetter);
8314 12 : obj->SetAccessor(v8_str("p3"), PGetter);
8315 12 : obj->SetAccessor(v8_str("p4"), PGetter);
8316 6 : p_getter_count = 0;
8317 6 : RunHolderTest(obj);
8318 6 : CHECK_EQ(40, p_getter_count);
8319 6 : }
8320 :
8321 :
8322 28343 : THREADED_TEST(PreInterceptorHolders) {
8323 6 : v8::Isolate* isolate = CcTest::isolate();
8324 6 : v8::HandleScope scope(isolate);
8325 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8326 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8327 6 : p_getter_count2 = 0;
8328 6 : RunHolderTest(obj);
8329 6 : CHECK_EQ(40, p_getter_count2);
8330 6 : }
8331 :
8332 :
8333 28343 : THREADED_TEST(ObjectInstantiation) {
8334 6 : v8::Isolate* isolate = CcTest::isolate();
8335 6 : v8::HandleScope scope(isolate);
8336 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8337 12 : templ->SetAccessor(v8_str("t"), PGetter2);
8338 12 : LocalContext context;
8339 36 : CHECK(context->Global()
8340 : ->Set(context.local(), v8_str("o"),
8341 : templ->NewInstance(context.local()).ToLocalChecked())
8342 : .FromJust());
8343 600 : for (int i = 0; i < 100; i++) {
8344 600 : v8::HandleScope inner_scope(CcTest::isolate());
8345 : v8::Local<v8::Object> obj =
8346 600 : templ->NewInstance(context.local()).ToLocalChecked();
8347 3600 : CHECK(!obj->Equals(context.local(), context->Global()
8348 : ->Get(context.local(), v8_str("o"))
8349 : .ToLocalChecked())
8350 : .FromJust());
8351 3000 : CHECK(
8352 : context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8353 600 : v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8354 1800 : CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8355 3000 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8356 606 : }
8357 6 : }
8358 :
8359 :
8360 : static int StrCmp16(uint16_t* a, uint16_t* b) {
8361 : while (true) {
8362 168 : if (*a == 0 && *b == 0) return 0;
8363 138 : if (*a != *b) return 0 + *a - *b;
8364 132 : a++;
8365 132 : b++;
8366 : }
8367 : }
8368 :
8369 :
8370 : static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8371 : while (true) {
8372 150 : if (n-- == 0) return 0;
8373 120 : if (*a == 0 && *b == 0) return 0;
8374 120 : if (*a != *b) return 0 + *a - *b;
8375 120 : a++;
8376 120 : b++;
8377 : }
8378 : }
8379 :
8380 552 : int GetUtf8Length(v8::Isolate* isolate, Local<String> str) {
8381 552 : int len = str->Utf8Length(isolate);
8382 552 : if (len < 0) {
8383 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8384 0 : i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8385 0 : i::String::Flatten(i_isolate, istr);
8386 0 : len = str->Utf8Length(isolate);
8387 : }
8388 552 : return len;
8389 : }
8390 :
8391 :
8392 28343 : THREADED_TEST(StringWrite) {
8393 6 : LocalContext context;
8394 6 : v8::Isolate* isolate = context->GetIsolate();
8395 12 : v8::HandleScope scope(isolate);
8396 6 : v8::Local<String> str = v8_str("abcde");
8397 : // abc<Icelandic eth><Unicode snowman>.
8398 6 : v8::Local<String> str2 = v8_str("abc\xC3\xB0\xE2\x98\x83");
8399 : v8::Local<String> str3 =
8400 : v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8401 6 : v8::NewStringType::kNormal, 7)
8402 6 : .ToLocalChecked();
8403 : // "ab" + lead surrogate + "wx" + trail surrogate + "yz"
8404 6 : uint16_t orphans[8] = {0x61, 0x62, 0xD800, 0x77, 0x78, 0xDC00, 0x79, 0x7A};
8405 : v8::Local<String> orphans_str =
8406 : v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8407 6 : v8::NewStringType::kNormal, 8)
8408 6 : .ToLocalChecked();
8409 : // single lead surrogate
8410 6 : uint16_t lead[1] = {0xD800};
8411 : v8::Local<String> lead_str =
8412 : v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8413 6 : v8::NewStringType::kNormal, 1)
8414 6 : .ToLocalChecked();
8415 : // single trail surrogate
8416 6 : uint16_t trail[1] = {0xDC00};
8417 : v8::Local<String> trail_str =
8418 : v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8419 6 : v8::NewStringType::kNormal, 1)
8420 6 : .ToLocalChecked();
8421 : // surrogate pair
8422 6 : uint16_t pair[2] = {0xD800, 0xDC00};
8423 : v8::Local<String> pair_str =
8424 : v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8425 6 : v8::NewStringType::kNormal, 2)
8426 6 : .ToLocalChecked();
8427 : const int kStride = 4; // Must match stride in for loops in JS below.
8428 : CompileRun(
8429 : "var left = '';"
8430 : "for (var i = 0; i < 0xD800; i += 4) {"
8431 : " left = left + String.fromCharCode(i);"
8432 : "}");
8433 : CompileRun(
8434 : "var right = '';"
8435 : "for (var i = 0; i < 0xD800; i += 4) {"
8436 : " right = String.fromCharCode(i) + right;"
8437 : "}");
8438 6 : v8::Local<v8::Object> global = context->Global();
8439 18 : Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8440 6 : .ToLocalChecked()
8441 : .As<String>();
8442 18 : Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8443 6 : .ToLocalChecked()
8444 : .As<String>();
8445 :
8446 6 : CHECK_EQ(5, str2->Length());
8447 6 : CHECK_EQ(0xD800 / kStride, left_tree->Length());
8448 6 : CHECK_EQ(0xD800 / kStride, right_tree->Length());
8449 :
8450 : char buf[100];
8451 : char utf8buf[0xD800 * 3];
8452 : uint16_t wbuf[100];
8453 : int len;
8454 : int charlen;
8455 :
8456 : memset(utf8buf, 0x1, 1000);
8457 : len = v8::String::Empty(isolate)->WriteUtf8(isolate, utf8buf, sizeof(utf8buf),
8458 6 : &charlen);
8459 6 : CHECK_EQ(1, len);
8460 6 : CHECK_EQ(0, charlen);
8461 6 : CHECK_EQ(0, strcmp(utf8buf, ""));
8462 :
8463 : memset(utf8buf, 0x1, 1000);
8464 6 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8465 6 : CHECK_EQ(9, len);
8466 6 : CHECK_EQ(5, charlen);
8467 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8468 :
8469 : memset(utf8buf, 0x1, 1000);
8470 6 : len = str2->WriteUtf8(isolate, utf8buf, 8, &charlen);
8471 6 : CHECK_EQ(8, len);
8472 6 : CHECK_EQ(5, charlen);
8473 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83\x01", 9));
8474 :
8475 : memset(utf8buf, 0x1, 1000);
8476 6 : len = str2->WriteUtf8(isolate, utf8buf, 7, &charlen);
8477 6 : CHECK_EQ(5, len);
8478 6 : CHECK_EQ(4, charlen);
8479 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8480 :
8481 : memset(utf8buf, 0x1, 1000);
8482 6 : len = str2->WriteUtf8(isolate, utf8buf, 6, &charlen);
8483 6 : CHECK_EQ(5, len);
8484 6 : CHECK_EQ(4, charlen);
8485 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8486 :
8487 : memset(utf8buf, 0x1, 1000);
8488 6 : len = str2->WriteUtf8(isolate, utf8buf, 5, &charlen);
8489 6 : CHECK_EQ(5, len);
8490 6 : CHECK_EQ(4, charlen);
8491 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8492 :
8493 : memset(utf8buf, 0x1, 1000);
8494 6 : len = str2->WriteUtf8(isolate, utf8buf, 4, &charlen);
8495 6 : CHECK_EQ(3, len);
8496 6 : CHECK_EQ(3, charlen);
8497 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8498 :
8499 : memset(utf8buf, 0x1, 1000);
8500 6 : len = str2->WriteUtf8(isolate, utf8buf, 3, &charlen);
8501 6 : CHECK_EQ(3, len);
8502 6 : CHECK_EQ(3, charlen);
8503 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8504 :
8505 : memset(utf8buf, 0x1, 1000);
8506 6 : len = str2->WriteUtf8(isolate, utf8buf, 2, &charlen);
8507 6 : CHECK_EQ(2, len);
8508 6 : CHECK_EQ(2, charlen);
8509 6 : CHECK_EQ(0, strncmp(utf8buf, "ab\x01", 3));
8510 :
8511 : // allow orphan surrogates by default
8512 : memset(utf8buf, 0x1, 1000);
8513 6 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8514 6 : CHECK_EQ(13, len);
8515 6 : CHECK_EQ(8, charlen);
8516 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xED\xA0\x80wx\xED\xB0\x80yz"));
8517 :
8518 : // replace orphan surrogates with Unicode replacement character
8519 : memset(utf8buf, 0x1, 1000);
8520 : len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8521 6 : String::REPLACE_INVALID_UTF8);
8522 6 : CHECK_EQ(13, len);
8523 6 : CHECK_EQ(8, charlen);
8524 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\xEF\xBF\xBDwx\xEF\xBF\xBDyz"));
8525 :
8526 : // replace single lead surrogate with Unicode replacement character
8527 : memset(utf8buf, 0x1, 1000);
8528 : len = lead_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8529 6 : String::REPLACE_INVALID_UTF8);
8530 6 : CHECK_EQ(4, len);
8531 6 : CHECK_EQ(1, charlen);
8532 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8533 :
8534 : // replace single trail surrogate with Unicode replacement character
8535 : memset(utf8buf, 0x1, 1000);
8536 : len = trail_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8537 6 : String::REPLACE_INVALID_UTF8);
8538 6 : CHECK_EQ(4, len);
8539 6 : CHECK_EQ(1, charlen);
8540 6 : CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8541 :
8542 : // do not replace / write anything if surrogate pair does not fit the buffer
8543 : // space
8544 : memset(utf8buf, 0x1, 1000);
8545 : len = pair_str->WriteUtf8(isolate, utf8buf, 3, &charlen,
8546 6 : String::REPLACE_INVALID_UTF8);
8547 6 : CHECK_EQ(0, len);
8548 6 : CHECK_EQ(0, charlen);
8549 :
8550 : memset(utf8buf, 0x1, sizeof(utf8buf));
8551 6 : len = GetUtf8Length(isolate, left_tree);
8552 : int utf8_expected =
8553 : (0x80 + (0x800 - 0x80) * 2 + (0xD800 - 0x800) * 3) / kStride;
8554 6 : CHECK_EQ(utf8_expected, len);
8555 6 : len = left_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8556 6 : CHECK_EQ(utf8_expected, len);
8557 6 : CHECK_EQ(0xD800 / kStride, charlen);
8558 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8559 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8560 12 : CHECK_EQ(0xC0 - kStride,
8561 : static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8562 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8563 :
8564 : memset(utf8buf, 0x1, sizeof(utf8buf));
8565 6 : len = GetUtf8Length(isolate, right_tree);
8566 6 : CHECK_EQ(utf8_expected, len);
8567 6 : len = right_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8568 6 : CHECK_EQ(utf8_expected, len);
8569 6 : CHECK_EQ(0xD800 / kStride, charlen);
8570 12 : CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[0]));
8571 12 : CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[1]));
8572 12 : CHECK_EQ(0xC0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8573 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8574 :
8575 : memset(buf, 0x1, sizeof(buf));
8576 : memset(wbuf, 0x1, sizeof(wbuf));
8577 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8578 6 : CHECK_EQ(5, len);
8579 6 : len = str->Write(isolate, wbuf);
8580 6 : CHECK_EQ(5, len);
8581 6 : CHECK_EQ(0, strcmp("abcde", buf));
8582 6 : uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8583 6 : CHECK_EQ(0, StrCmp16(answer1, wbuf));
8584 :
8585 : memset(buf, 0x1, sizeof(buf));
8586 : memset(wbuf, 0x1, sizeof(wbuf));
8587 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 4);
8588 6 : CHECK_EQ(4, len);
8589 6 : len = str->Write(isolate, wbuf, 0, 4);
8590 6 : CHECK_EQ(4, len);
8591 6 : CHECK_EQ(0, strncmp("abcd\x01", buf, 5));
8592 6 : uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8593 6 : CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8594 :
8595 : memset(buf, 0x1, sizeof(buf));
8596 : memset(wbuf, 0x1, sizeof(wbuf));
8597 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 5);
8598 6 : CHECK_EQ(5, len);
8599 6 : len = str->Write(isolate, wbuf, 0, 5);
8600 6 : CHECK_EQ(5, len);
8601 6 : CHECK_EQ(0, strncmp("abcde\x01", buf, 6));
8602 6 : uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8603 6 : CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8604 :
8605 : memset(buf, 0x1, sizeof(buf));
8606 : memset(wbuf, 0x1, sizeof(wbuf));
8607 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6);
8608 6 : CHECK_EQ(5, len);
8609 6 : len = str->Write(isolate, wbuf, 0, 6);
8610 6 : CHECK_EQ(5, len);
8611 6 : CHECK_EQ(0, strcmp("abcde", buf));
8612 6 : uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8613 6 : CHECK_EQ(0, StrCmp16(answer4, wbuf));
8614 :
8615 : memset(buf, 0x1, sizeof(buf));
8616 : memset(wbuf, 0x1, sizeof(wbuf));
8617 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, -1);
8618 6 : CHECK_EQ(1, len);
8619 6 : len = str->Write(isolate, wbuf, 4, -1);
8620 6 : CHECK_EQ(1, len);
8621 6 : CHECK_EQ(0, strcmp("e", buf));
8622 6 : uint16_t answer5[] = {'e', '\0'};
8623 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8624 :
8625 : memset(buf, 0x1, sizeof(buf));
8626 : memset(wbuf, 0x1, sizeof(wbuf));
8627 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 6);
8628 6 : CHECK_EQ(1, len);
8629 6 : len = str->Write(isolate, wbuf, 4, 6);
8630 6 : CHECK_EQ(1, len);
8631 6 : CHECK_EQ(0, strcmp("e", buf));
8632 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8633 :
8634 : memset(buf, 0x1, sizeof(buf));
8635 : memset(wbuf, 0x1, sizeof(wbuf));
8636 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 1);
8637 6 : CHECK_EQ(1, len);
8638 6 : len = str->Write(isolate, wbuf, 4, 1);
8639 6 : CHECK_EQ(1, len);
8640 6 : CHECK_EQ(0, strncmp("e\x01", buf, 2));
8641 6 : uint16_t answer6[] = {'e', 0x101};
8642 6 : CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8643 :
8644 : memset(buf, 0x1, sizeof(buf));
8645 : memset(wbuf, 0x1, sizeof(wbuf));
8646 6 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 3, 1);
8647 6 : CHECK_EQ(1, len);
8648 6 : len = str->Write(isolate, wbuf, 3, 1);
8649 6 : CHECK_EQ(1, len);
8650 6 : CHECK_EQ(0, strncmp("d\x01", buf, 2));
8651 6 : uint16_t answer7[] = {'d', 0x101};
8652 6 : CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8653 :
8654 : memset(wbuf, 0x1, sizeof(wbuf));
8655 6 : wbuf[5] = 'X';
8656 6 : len = str->Write(isolate, wbuf, 0, 6, String::NO_NULL_TERMINATION);
8657 6 : CHECK_EQ(5, len);
8658 12 : CHECK_EQ('X', wbuf[5]);
8659 6 : uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8660 6 : uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8661 6 : CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8662 6 : CHECK_NE(0, StrCmp16(answer8b, wbuf));
8663 6 : wbuf[5] = '\0';
8664 6 : CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8665 :
8666 : memset(buf, 0x1, sizeof(buf));
8667 6 : buf[5] = 'X';
8668 : len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6,
8669 6 : String::NO_NULL_TERMINATION);
8670 6 : CHECK_EQ(5, len);
8671 6 : CHECK_EQ('X', buf[5]);
8672 6 : CHECK_EQ(0, strncmp("abcde", buf, 5));
8673 6 : CHECK_NE(0, strcmp("abcde", buf));
8674 6 : buf[5] = '\0';
8675 6 : CHECK_EQ(0, strcmp("abcde", buf));
8676 :
8677 : memset(utf8buf, 0x1, sizeof(utf8buf));
8678 6 : utf8buf[8] = 'X';
8679 : len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8680 6 : String::NO_NULL_TERMINATION);
8681 6 : CHECK_EQ(8, len);
8682 6 : CHECK_EQ('X', utf8buf[8]);
8683 6 : CHECK_EQ(5, charlen);
8684 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83", 8));
8685 6 : CHECK_NE(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8686 6 : utf8buf[8] = '\0';
8687 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8688 :
8689 : memset(utf8buf, 0x1, sizeof(utf8buf));
8690 6 : utf8buf[5] = 'X';
8691 : len = str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8692 6 : String::NO_NULL_TERMINATION);
8693 6 : CHECK_EQ(5, len);
8694 6 : CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8695 6 : CHECK_EQ(5, charlen);
8696 6 : utf8buf[5] = '\0';
8697 6 : CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8698 :
8699 : memset(buf, 0x1, sizeof(buf));
8700 6 : len = str3->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8701 6 : CHECK_EQ(7, len);
8702 6 : CHECK_EQ(0, strcmp("abc", buf));
8703 6 : CHECK_EQ(0, buf[3]);
8704 6 : CHECK_EQ(0, strcmp("def", buf + 4));
8705 :
8706 6 : CHECK_EQ(0, str->WriteOneByte(isolate, nullptr, 0, 0,
8707 : String::NO_NULL_TERMINATION));
8708 6 : CHECK_EQ(0, str->WriteUtf8(isolate, nullptr, 0, nullptr,
8709 : String::NO_NULL_TERMINATION));
8710 12 : CHECK_EQ(0, str->Write(isolate, nullptr, 0, 0, String::NO_NULL_TERMINATION));
8711 6 : }
8712 :
8713 :
8714 12 : static void Utf16Helper(
8715 : LocalContext& context, // NOLINT
8716 : const char* name,
8717 : const char* lengths_name,
8718 : int len) {
8719 : Local<v8::Array> a = Local<v8::Array>::Cast(
8720 60 : context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8721 : Local<v8::Array> alens =
8722 : Local<v8::Array>::Cast(context->Global()
8723 48 : ->Get(context.local(), v8_str(lengths_name))
8724 12 : .ToLocalChecked());
8725 552 : for (int i = 0; i < len; i++) {
8726 : Local<v8::String> string =
8727 1080 : Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8728 : Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8729 540 : alens->Get(context.local(), i).ToLocalChecked());
8730 540 : int length = GetUtf8Length(context->GetIsolate(), string);
8731 540 : CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8732 : }
8733 12 : }
8734 :
8735 6 : void TestUtf8DecodingAgainstReference(
8736 : v8::Isolate* isolate, const char* cases[],
8737 474 : const std::vector<std::vector<uint16_t>>& unicode_expected) {
8738 132 : for (size_t test_ix = 0; test_ix < unicode_expected.size(); ++test_ix) {
8739 60 : v8::Local<String> str = v8_str(cases[test_ix]);
8740 180 : CHECK_EQ(unicode_expected[test_ix].size(), str->Length());
8741 :
8742 60 : std::unique_ptr<uint16_t[]> buffer(new uint16_t[str->Length()]);
8743 60 : str->Write(isolate, buffer.get(), 0, -1, String::NO_NULL_TERMINATION);
8744 :
8745 1044 : for (size_t i = 0; i < unicode_expected[test_ix].size(); ++i) {
8746 576 : CHECK_EQ(unicode_expected[test_ix][i], buffer[i]);
8747 : }
8748 : }
8749 6 : }
8750 :
8751 28343 : THREADED_TEST(OverlongSequencesAndSurrogates) {
8752 6 : LocalContext context;
8753 12 : v8::HandleScope scope(context->GetIsolate());
8754 :
8755 : const char* cases[] = {
8756 : // Overlong 2-byte sequence.
8757 : "X\xc0\xbfY\0",
8758 : // Another overlong 2-byte sequence.
8759 : "X\xc1\xbfY\0",
8760 : // Overlong 3-byte sequence.
8761 : "X\xe0\x9f\xbfY\0",
8762 : // Overlong 4-byte sequence.
8763 : "X\xf0\x89\xbf\xbfY\0",
8764 : // Invalid 3-byte sequence (reserved for surrogates).
8765 : "X\xed\xa0\x80Y\0",
8766 : // Invalid 4-bytes sequence (value out of range).
8767 : "X\xf4\x90\x80\x80Y\0",
8768 :
8769 : // Start of an overlong 3-byte sequence but not enough continuation bytes.
8770 : "X\xe0\x9fY\0",
8771 : // Start of an overlong 4-byte sequence but not enough continuation bytes.
8772 : "X\xf0\x89\xbfY\0",
8773 : // Start of an invalid 3-byte sequence (reserved for surrogates) but not
8774 : // enough continuation bytes.
8775 : "X\xed\xa0Y\0",
8776 : // Start of an invalid 4-bytes sequence (value out of range) but not
8777 : // enough continuation bytes.
8778 : "X\xf4\x90\x80Y\0",
8779 6 : };
8780 : const std::vector<std::vector<uint16_t>> unicode_expected = {
8781 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8782 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8783 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8784 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8785 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8786 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8787 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8788 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8789 : {0x58, 0xFFFD, 0xFFFD, 0x59},
8790 : {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8791 12 : };
8792 12 : CHECK_EQ(unicode_expected.size(), arraysize(cases));
8793 : TestUtf8DecodingAgainstReference(context->GetIsolate(), cases,
8794 12 : unicode_expected);
8795 6 : }
8796 :
8797 28343 : THREADED_TEST(Utf16) {
8798 6 : LocalContext context;
8799 12 : v8::HandleScope scope(context->GetIsolate());
8800 : CompileRun(
8801 : "var pad = '01234567890123456789';"
8802 : "var p = [];"
8803 : "var plens = [20, 3, 3];"
8804 : "p.push('01234567890123456789');"
8805 : "var lead = 0xD800;"
8806 : "var trail = 0xDC00;"
8807 : "p.push(String.fromCharCode(0xD800));"
8808 : "p.push(String.fromCharCode(0xDC00));"
8809 : "var a = [];"
8810 : "var b = [];"
8811 : "var c = [];"
8812 : "var alens = [];"
8813 : "for (var i = 0; i < 3; i++) {"
8814 : " p[1] = String.fromCharCode(lead++);"
8815 : " for (var j = 0; j < 3; j++) {"
8816 : " p[2] = String.fromCharCode(trail++);"
8817 : " a.push(p[i] + p[j]);"
8818 : " b.push(p[i] + p[j]);"
8819 : " c.push(p[i] + p[j]);"
8820 : " alens.push(plens[i] + plens[j]);"
8821 : " }"
8822 : "}"
8823 : "alens[5] -= 2;" // Here the surrogate pairs match up.
8824 : "var a2 = [];"
8825 : "var b2 = [];"
8826 : "var c2 = [];"
8827 : "var a2lens = [];"
8828 : "for (var m = 0; m < 9; m++) {"
8829 : " for (var n = 0; n < 9; n++) {"
8830 : " a2.push(a[m] + a[n]);"
8831 : " b2.push(b[m] + b[n]);"
8832 : " var newc = 'x' + c[m] + c[n] + 'y';"
8833 : " c2.push(newc.substring(1, newc.length - 1));"
8834 : " var utf = alens[m] + alens[n];" // And here.
8835 : // The 'n's that start with 0xDC..
8836 : // are 6-8 The 'm's that end with
8837 : // 0xD8.. are 1, 4 and 7
8838 : " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8839 : " a2lens.push(utf);"
8840 : " }"
8841 : "}");
8842 6 : Utf16Helper(context, "a", "alens", 9);
8843 12 : Utf16Helper(context, "a2", "a2lens", 81);
8844 6 : }
8845 :
8846 :
8847 42 : static bool SameSymbol(Local<String> s1, Local<String> s2) {
8848 : i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8849 : i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8850 42 : return *is1 == *is2;
8851 : }
8852 :
8853 :
8854 28343 : THREADED_TEST(Utf16Symbol) {
8855 6 : LocalContext context;
8856 12 : v8::HandleScope scope(context->GetIsolate());
8857 :
8858 : Local<String> symbol1 =
8859 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8860 6 : v8::NewStringType::kInternalized)
8861 12 : .ToLocalChecked();
8862 : Local<String> symbol2 =
8863 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8864 6 : v8::NewStringType::kInternalized)
8865 12 : .ToLocalChecked();
8866 6 : CHECK(SameSymbol(symbol1, symbol2));
8867 :
8868 : CompileRun(
8869 : "var sym0 = 'benedictus';"
8870 : "var sym0b = 'S\xC3\xB8ren';"
8871 : "var sym1 = '\xED\xA0\x81\xED\xB0\x87';"
8872 : "var sym2 = '\xF0\x90\x90\x88';"
8873 : "var sym3 = 'x\xED\xA0\x81\xED\xB0\x87';"
8874 : "var sym4 = 'x\xF0\x90\x90\x88';"
8875 : "if (sym1.length != 2) throw sym1;"
8876 : "if (sym1.charCodeAt(1) != 0xDC07) throw sym1.charCodeAt(1);"
8877 : "if (sym2.length != 2) throw sym2;"
8878 : "if (sym2.charCodeAt(1) != 0xDC08) throw sym2.charCodeAt(2);"
8879 : "if (sym3.length != 3) throw sym3;"
8880 : "if (sym3.charCodeAt(2) != 0xDC07) throw sym1.charCodeAt(2);"
8881 : "if (sym4.length != 3) throw sym4;"
8882 : "if (sym4.charCodeAt(2) != 0xDC08) throw sym2.charCodeAt(2);");
8883 : Local<String> sym0 =
8884 : v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8885 6 : v8::NewStringType::kInternalized)
8886 12 : .ToLocalChecked();
8887 : Local<String> sym0b =
8888 : v8::String::NewFromUtf8(context->GetIsolate(), "S\xC3\xB8ren",
8889 6 : v8::NewStringType::kInternalized)
8890 12 : .ToLocalChecked();
8891 : Local<String> sym1 =
8892 : v8::String::NewFromUtf8(context->GetIsolate(), "\xED\xA0\x81\xED\xB0\x87",
8893 6 : v8::NewStringType::kInternalized)
8894 12 : .ToLocalChecked();
8895 : Local<String> sym2 =
8896 : v8::String::NewFromUtf8(context->GetIsolate(), "\xF0\x90\x90\x88",
8897 6 : v8::NewStringType::kInternalized)
8898 12 : .ToLocalChecked();
8899 : Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8900 : "x\xED\xA0\x81\xED\xB0\x87",
8901 6 : v8::NewStringType::kInternalized)
8902 12 : .ToLocalChecked();
8903 : Local<String> sym4 =
8904 : v8::String::NewFromUtf8(context->GetIsolate(), "x\xF0\x90\x90\x88",
8905 6 : v8::NewStringType::kInternalized)
8906 12 : .ToLocalChecked();
8907 6 : v8::Local<v8::Object> global = context->Global();
8908 : Local<Value> s0 =
8909 18 : global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8910 : Local<Value> s0b =
8911 18 : global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8912 : Local<Value> s1 =
8913 18 : global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8914 : Local<Value> s2 =
8915 18 : global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8916 : Local<Value> s3 =
8917 18 : global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8918 : Local<Value> s4 =
8919 18 : global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8920 6 : CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8921 6 : CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8922 6 : CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8923 6 : CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8924 6 : CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8925 12 : CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8926 6 : }
8927 :
8928 :
8929 28343 : THREADED_TEST(Utf16MissingTrailing) {
8930 6 : LocalContext context;
8931 12 : v8::HandleScope scope(context->GetIsolate());
8932 :
8933 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8934 : int size = 1024 * 64;
8935 6 : uint8_t* buffer = new uint8_t[size];
8936 98310 : for (int i = 0; i < size; i += 4) {
8937 98304 : buffer[i] = 0xF0;
8938 98304 : buffer[i + 1] = 0x9D;
8939 98304 : buffer[i + 2] = 0x80;
8940 98304 : buffer[i + 3] = 0x9E;
8941 : }
8942 :
8943 : // Now invoke the decoder without last 3 bytes
8944 : v8::Local<v8::String> str =
8945 : v8::String::NewFromUtf8(
8946 : context->GetIsolate(), reinterpret_cast<char*>(buffer),
8947 6 : v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8948 : USE(str);
8949 12 : delete[] buffer;
8950 6 : }
8951 :
8952 :
8953 28343 : THREADED_TEST(Utf16Trailing3Byte) {
8954 6 : LocalContext context;
8955 6 : v8::Isolate* isolate = context->GetIsolate();
8956 12 : v8::HandleScope scope(isolate);
8957 :
8958 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8959 : int size = 1024 * 63;
8960 6 : uint8_t* buffer = new uint8_t[size];
8961 129030 : for (int i = 0; i < size; i += 3) {
8962 129024 : buffer[i] = 0xE2;
8963 129024 : buffer[i + 1] = 0x80;
8964 129024 : buffer[i + 2] = 0xA6;
8965 : }
8966 :
8967 : // Now invoke the decoder without last 3 bytes
8968 : v8::Local<v8::String> str =
8969 : v8::String::NewFromUtf8(isolate, reinterpret_cast<char*>(buffer),
8970 : v8::NewStringType::kNormal, size)
8971 6 : .ToLocalChecked();
8972 :
8973 12 : v8::String::Value value(isolate, str);
8974 6 : CHECK_EQ(value.length(), size / 3);
8975 12 : CHECK_EQ((*value)[value.length() - 1], 0x2026);
8976 :
8977 12 : delete[] buffer;
8978 6 : }
8979 :
8980 :
8981 28343 : THREADED_TEST(ToArrayIndex) {
8982 6 : LocalContext context;
8983 6 : v8::Isolate* isolate = context->GetIsolate();
8984 12 : v8::HandleScope scope(isolate);
8985 :
8986 6 : v8::Local<String> str = v8_str("42");
8987 6 : v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
8988 6 : CHECK(!index.IsEmpty());
8989 18 : CHECK_EQ(42.0,
8990 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8991 6 : str = v8_str("42asdf");
8992 6 : index = str->ToArrayIndex(context.local());
8993 6 : CHECK(index.IsEmpty());
8994 6 : str = v8_str("-42");
8995 6 : index = str->ToArrayIndex(context.local());
8996 6 : CHECK(index.IsEmpty());
8997 6 : str = v8_str("4294967294");
8998 6 : index = str->ToArrayIndex(context.local());
8999 6 : CHECK(!index.IsEmpty());
9000 18 : CHECK_EQ(4294967294.0,
9001 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9002 6 : v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
9003 6 : index = num->ToArrayIndex(context.local());
9004 6 : CHECK(!index.IsEmpty());
9005 18 : CHECK_EQ(1.0,
9006 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9007 6 : num = v8::Number::New(isolate, -1);
9008 6 : index = num->ToArrayIndex(context.local());
9009 6 : CHECK(index.IsEmpty());
9010 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
9011 12 : index = obj->ToArrayIndex(context.local());
9012 12 : CHECK(index.IsEmpty());
9013 6 : }
9014 :
9015 6 : static v8::MaybeLocal<Value> PrepareStackTrace42(v8::Local<Context> context,
9016 : v8::Local<Value> error,
9017 : v8::Local<Array> trace) {
9018 6 : return v8::Number::New(context->GetIsolate(), 42);
9019 : }
9020 :
9021 6 : static v8::MaybeLocal<Value> PrepareStackTraceThrow(v8::Local<Context> context,
9022 : v8::Local<Value> error,
9023 : v8::Local<Array> trace) {
9024 6 : v8::Isolate* isolate = context->GetIsolate();
9025 6 : v8::Local<String> message = v8_str("42");
9026 6 : isolate->ThrowException(v8::Exception::Error(message));
9027 6 : return v8::MaybeLocal<Value>();
9028 : }
9029 :
9030 28343 : THREADED_TEST(IsolatePrepareStackTrace) {
9031 6 : LocalContext context;
9032 6 : v8::Isolate* isolate = context->GetIsolate();
9033 12 : v8::HandleScope scope(isolate);
9034 :
9035 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTrace42);
9036 :
9037 : v8::Local<Value> v = CompileRun("new Error().stack");
9038 :
9039 6 : CHECK(v->IsNumber());
9040 18 : CHECK_EQ(v.As<v8::Number>()->Int32Value(context.local()).FromJust(), 42);
9041 6 : }
9042 :
9043 28343 : THREADED_TEST(IsolatePrepareStackTraceThrow) {
9044 6 : LocalContext context;
9045 6 : v8::Isolate* isolate = context->GetIsolate();
9046 12 : v8::HandleScope scope(isolate);
9047 :
9048 6 : isolate->SetPrepareStackTraceCallback(PrepareStackTraceThrow);
9049 :
9050 : v8::Local<Value> v = CompileRun("try { new Error().stack } catch (e) { e }");
9051 :
9052 6 : CHECK(v->IsNativeError());
9053 :
9054 12 : v8::Local<String> message = v8::Exception::CreateMessage(isolate, v)->Get();
9055 :
9056 18 : CHECK(message->StrictEquals(v8_str("Uncaught Error: 42")));
9057 6 : }
9058 :
9059 28343 : THREADED_TEST(ErrorConstruction) {
9060 6 : LocalContext context;
9061 12 : v8::HandleScope scope(context->GetIsolate());
9062 :
9063 6 : v8::Local<String> foo = v8_str("foo");
9064 6 : v8::Local<String> message = v8_str("message");
9065 6 : v8::Local<Value> range_error = v8::Exception::RangeError(foo);
9066 6 : CHECK(range_error->IsObject());
9067 24 : CHECK(range_error.As<v8::Object>()
9068 : ->Get(context.local(), message)
9069 : .ToLocalChecked()
9070 : ->Equals(context.local(), foo)
9071 : .FromJust());
9072 6 : v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
9073 6 : CHECK(reference_error->IsObject());
9074 24 : CHECK(reference_error.As<v8::Object>()
9075 : ->Get(context.local(), message)
9076 : .ToLocalChecked()
9077 : ->Equals(context.local(), foo)
9078 : .FromJust());
9079 6 : v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
9080 6 : CHECK(syntax_error->IsObject());
9081 24 : CHECK(syntax_error.As<v8::Object>()
9082 : ->Get(context.local(), message)
9083 : .ToLocalChecked()
9084 : ->Equals(context.local(), foo)
9085 : .FromJust());
9086 6 : v8::Local<Value> type_error = v8::Exception::TypeError(foo);
9087 6 : CHECK(type_error->IsObject());
9088 24 : CHECK(type_error.As<v8::Object>()
9089 : ->Get(context.local(), message)
9090 : .ToLocalChecked()
9091 : ->Equals(context.local(), foo)
9092 : .FromJust());
9093 6 : v8::Local<Value> error = v8::Exception::Error(foo);
9094 6 : CHECK(error->IsObject());
9095 24 : CHECK(error.As<v8::Object>()
9096 : ->Get(context.local(), message)
9097 : .ToLocalChecked()
9098 : ->Equals(context.local(), foo)
9099 6 : .FromJust());
9100 6 : }
9101 :
9102 :
9103 48 : static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
9104 12 : ApiTestFuzzer::Fuzz();
9105 12 : v8::Local<String> foo = v8_str("foo");
9106 12 : v8::Local<String> message = v8_str("message");
9107 12 : v8::Local<Value> error = v8::Exception::Error(foo);
9108 12 : CHECK(error->IsObject());
9109 12 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9110 36 : CHECK(error.As<v8::Object>()
9111 : ->Get(context, message)
9112 : .ToLocalChecked()
9113 : ->Equals(context, foo)
9114 : .FromJust());
9115 12 : info.GetIsolate()->ThrowException(error);
9116 : info.GetReturnValue().SetUndefined();
9117 12 : }
9118 :
9119 :
9120 28343 : THREADED_TEST(ExceptionCreateMessage) {
9121 6 : LocalContext context;
9122 12 : v8::HandleScope scope(context->GetIsolate());
9123 6 : v8::Local<String> foo_str = v8_str("foo");
9124 6 : v8::Local<String> message_str = v8_str("message");
9125 :
9126 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
9127 :
9128 : Local<v8::FunctionTemplate> fun =
9129 6 : v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
9130 6 : v8::Local<v8::Object> global = context->Global();
9131 36 : CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
9132 : fun->GetFunction(context.local()).ToLocalChecked())
9133 : .FromJust());
9134 :
9135 12 : TryCatch try_catch(context->GetIsolate());
9136 : CompileRun(
9137 : "function f1() {\n"
9138 : " throwV8Exception();\n"
9139 : "};\n"
9140 : "f1();");
9141 6 : CHECK(try_catch.HasCaught());
9142 :
9143 6 : v8::Local<v8::Value> error = try_catch.Exception();
9144 6 : CHECK(error->IsObject());
9145 24 : CHECK(error.As<v8::Object>()
9146 : ->Get(context.local(), message_str)
9147 : .ToLocalChecked()
9148 : ->Equals(context.local(), foo_str)
9149 : .FromJust());
9150 :
9151 : v8::Local<v8::Message> message =
9152 6 : v8::Exception::CreateMessage(context->GetIsolate(), error);
9153 6 : CHECK(!message.IsEmpty());
9154 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9155 12 : CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
9156 :
9157 6 : v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
9158 6 : CHECK(!stackTrace.IsEmpty());
9159 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9160 :
9161 6 : stackTrace = v8::Exception::GetStackTrace(error);
9162 6 : CHECK(!stackTrace.IsEmpty());
9163 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
9164 :
9165 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
9166 :
9167 : // Now check message location when SetCaptureStackTraceForUncaughtExceptions
9168 : // is false.
9169 6 : try_catch.Reset();
9170 :
9171 : CompileRun(
9172 : "function f2() {\n"
9173 : " return throwV8Exception();\n"
9174 : "};\n"
9175 : "f2();");
9176 6 : CHECK(try_catch.HasCaught());
9177 :
9178 6 : error = try_catch.Exception();
9179 6 : CHECK(error->IsObject());
9180 24 : CHECK(error.As<v8::Object>()
9181 : ->Get(context.local(), message_str)
9182 : .ToLocalChecked()
9183 : ->Equals(context.local(), foo_str)
9184 : .FromJust());
9185 :
9186 6 : message = 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(9, message->GetStartColumn(context.local()).FromJust());
9190 :
9191 : // Should be empty stack trace.
9192 6 : stackTrace = message->GetStackTrace();
9193 6 : CHECK(stackTrace.IsEmpty());
9194 18 : CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9195 6 : }
9196 :
9197 :
9198 28343 : THREADED_TEST(ExceptionCreateMessageLength) {
9199 6 : LocalContext context;
9200 12 : v8::HandleScope scope(context->GetIsolate());
9201 :
9202 : // Test that the message is not truncated.
9203 12 : TryCatch try_catch(context->GetIsolate());
9204 : CompileRun(
9205 : "var message = 'm';"
9206 : "while (message.length < 1000) message += message;"
9207 : "throw message;");
9208 6 : CHECK(try_catch.HasCaught());
9209 :
9210 24 : CHECK_LT(1000, try_catch.Message()->Get()->Length());
9211 6 : }
9212 :
9213 :
9214 0 : static void YGetter(Local<String> name,
9215 : const v8::PropertyCallbackInfo<v8::Value>& info) {
9216 0 : ApiTestFuzzer::Fuzz();
9217 0 : info.GetReturnValue().Set(v8_num(10));
9218 0 : }
9219 :
9220 :
9221 6 : static void YSetter(Local<String> name,
9222 : Local<Value> value,
9223 : const v8::PropertyCallbackInfo<void>& info) {
9224 : Local<Object> this_obj = Local<Object>::Cast(info.This());
9225 6 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9226 12 : if (this_obj->Has(context, name).FromJust())
9227 12 : this_obj->Delete(context, name).FromJust();
9228 12 : CHECK(this_obj->Set(context, name, value).FromJust());
9229 6 : }
9230 :
9231 :
9232 28343 : THREADED_TEST(DeleteAccessor) {
9233 6 : v8::Isolate* isolate = CcTest::isolate();
9234 6 : v8::HandleScope scope(isolate);
9235 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9236 6 : obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9237 12 : LocalContext context;
9238 : v8::Local<v8::Object> holder =
9239 6 : obj->NewInstance(context.local()).ToLocalChecked();
9240 30 : CHECK(context->Global()
9241 : ->Set(context.local(), v8_str("holder"), holder)
9242 : .FromJust());
9243 : v8::Local<Value> result =
9244 : CompileRun("holder.y = 11; holder.y = 12; holder.y");
9245 18 : CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
9246 6 : }
9247 :
9248 :
9249 : static int trouble_nesting = 0;
9250 45 : static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9251 15 : ApiTestFuzzer::Fuzz();
9252 15 : trouble_nesting++;
9253 :
9254 : // Call a JS function that throws an uncaught exception.
9255 15 : Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
9256 15 : Local<v8::Object> arg_this = context->Global();
9257 : Local<Value> trouble_callee =
9258 15 : (trouble_nesting == 3)
9259 30 : ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
9260 60 : : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
9261 15 : CHECK(trouble_callee->IsFunction());
9262 : args.GetReturnValue().Set(Function::Cast(*trouble_callee)
9263 15 : ->Call(context, arg_this, 0, nullptr)
9264 30 : .FromMaybe(v8::Local<v8::Value>()));
9265 15 : }
9266 :
9267 :
9268 : static int report_count = 0;
9269 5 : static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
9270 : v8::Local<Value>) {
9271 5 : report_count++;
9272 5 : }
9273 :
9274 :
9275 : // Counts uncaught exceptions, but other tests running in parallel
9276 : // also have uncaught exceptions.
9277 28342 : TEST(ApiUncaughtException) {
9278 5 : report_count = 0;
9279 5 : LocalContext env;
9280 5 : v8::Isolate* isolate = env->GetIsolate();
9281 10 : v8::HandleScope scope(isolate);
9282 5 : isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
9283 :
9284 : Local<v8::FunctionTemplate> fun =
9285 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9286 5 : v8::Local<v8::Object> global = env->Global();
9287 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9288 : fun->GetFunction(env.local()).ToLocalChecked())
9289 : .FromJust());
9290 :
9291 : CompileRun(
9292 : "function trouble_callee() {"
9293 : " var x = null;"
9294 : " return x.foo;"
9295 : "};"
9296 : "function trouble_caller() {"
9297 : " trouble();"
9298 : "};");
9299 : Local<Value> trouble =
9300 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9301 5 : CHECK(trouble->IsFunction());
9302 : Local<Value> trouble_callee =
9303 15 : global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9304 5 : CHECK(trouble_callee->IsFunction());
9305 : Local<Value> trouble_caller =
9306 15 : global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9307 5 : CHECK(trouble_caller->IsFunction());
9308 : Function::Cast(*trouble_caller)
9309 10 : ->Call(env.local(), global, 0, nullptr)
9310 5 : .FromMaybe(v8::Local<v8::Value>());
9311 5 : CHECK_EQ(1, report_count);
9312 10 : isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9313 5 : }
9314 :
9315 :
9316 : static const char* script_resource_name = "ExceptionInNativeScript.js";
9317 5 : static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9318 : v8::Local<Value>) {
9319 5 : v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9320 10 : CHECK(!name_val.IsEmpty() && name_val->IsString());
9321 : v8::String::Utf8Value name(v8::Isolate::GetCurrent(),
9322 5 : message->GetScriptOrigin().ResourceName());
9323 5 : CHECK_EQ(0, strcmp(script_resource_name, *name));
9324 : v8::Local<v8::Context> context =
9325 5 : v8::Isolate::GetCurrent()->GetCurrentContext();
9326 10 : CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9327 : v8::String::Utf8Value source_line(
9328 : v8::Isolate::GetCurrent(),
9329 15 : message->GetSourceLine(context).ToLocalChecked());
9330 10 : CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9331 5 : }
9332 :
9333 :
9334 28342 : TEST(ExceptionInNativeScript) {
9335 5 : LocalContext env;
9336 5 : v8::Isolate* isolate = env->GetIsolate();
9337 10 : v8::HandleScope scope(isolate);
9338 5 : isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9339 :
9340 : Local<v8::FunctionTemplate> fun =
9341 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9342 5 : v8::Local<v8::Object> global = env->Global();
9343 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9344 : fun->GetFunction(env.local()).ToLocalChecked())
9345 : .FromJust());
9346 :
9347 : CompileRunWithOrigin(
9348 : "function trouble() {\n"
9349 : " var o = {};\n"
9350 : " new o.foo();\n"
9351 : "};",
9352 5 : script_resource_name);
9353 : Local<Value> trouble =
9354 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9355 5 : CHECK(trouble->IsFunction());
9356 10 : CHECK(Function::Cast(*trouble)
9357 : ->Call(env.local(), global, 0, nullptr)
9358 : .IsEmpty());
9359 10 : isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9360 5 : }
9361 :
9362 :
9363 28342 : TEST(CompilationErrorUsingTryCatchHandler) {
9364 5 : LocalContext env;
9365 10 : v8::HandleScope scope(env->GetIsolate());
9366 10 : v8::TryCatch try_catch(env->GetIsolate());
9367 : v8_compile("This doesn't &*&@#$&*^ compile.");
9368 10 : CHECK(*try_catch.Exception());
9369 10 : CHECK(try_catch.HasCaught());
9370 5 : }
9371 :
9372 :
9373 28342 : TEST(TryCatchFinallyUsingTryCatchHandler) {
9374 5 : LocalContext env;
9375 10 : v8::HandleScope scope(env->GetIsolate());
9376 10 : v8::TryCatch try_catch(env->GetIsolate());
9377 : CompileRun("try { throw ''; } catch (e) {}");
9378 5 : CHECK(!try_catch.HasCaught());
9379 : CompileRun("try { throw ''; } finally {}");
9380 5 : CHECK(try_catch.HasCaught());
9381 5 : try_catch.Reset();
9382 : CompileRun(
9383 : "(function() {"
9384 : "try { throw ''; } finally { return; }"
9385 : "})()");
9386 5 : CHECK(!try_catch.HasCaught());
9387 : CompileRun(
9388 : "(function()"
9389 : " { try { throw ''; } finally { throw 0; }"
9390 : "})()");
9391 10 : CHECK(try_catch.HasCaught());
9392 5 : }
9393 :
9394 :
9395 20 : void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9396 10 : v8::HandleScope scope(args.GetIsolate());
9397 : CompileRun(args[0]
9398 10 : ->ToString(args.GetIsolate()->GetCurrentContext())
9399 20 : .ToLocalChecked());
9400 10 : }
9401 :
9402 :
9403 28342 : TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9404 5 : v8::Isolate* isolate = CcTest::isolate();
9405 5 : v8::HandleScope scope(isolate);
9406 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9407 : templ->Set(v8_str("CEvaluate"),
9408 15 : v8::FunctionTemplate::New(isolate, CEvaluate));
9409 10 : LocalContext context(nullptr, templ);
9410 10 : v8::TryCatch try_catch(isolate);
9411 : CompileRun("try {"
9412 : " CEvaluate('throw 1;');"
9413 : "} finally {"
9414 : "}");
9415 5 : CHECK(try_catch.HasCaught());
9416 10 : CHECK(!try_catch.Message().IsEmpty());
9417 10 : String::Utf8Value exception_value(isolate, try_catch.Exception());
9418 5 : CHECK_EQ(0, strcmp(*exception_value, "1"));
9419 5 : try_catch.Reset();
9420 : CompileRun("try {"
9421 : " CEvaluate('throw 1;');"
9422 : "} finally {"
9423 : " throw 2;"
9424 : "}");
9425 5 : CHECK(try_catch.HasCaught());
9426 10 : CHECK(!try_catch.Message().IsEmpty());
9427 10 : String::Utf8Value finally_exception_value(isolate, try_catch.Exception());
9428 10 : CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9429 5 : }
9430 :
9431 :
9432 : // For use within the TestSecurityHandler() test.
9433 : static bool g_security_callback_result = false;
9434 35 : static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9435 : Local<v8::Object> accessed_object,
9436 : Local<v8::Value> data) {
9437 : printf("a\n");
9438 35 : CHECK(!data.IsEmpty() && data->IsInt32());
9439 70 : CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9440 35 : return g_security_callback_result;
9441 : }
9442 :
9443 :
9444 : // SecurityHandler can't be run twice
9445 28342 : TEST(SecurityHandler) {
9446 5 : v8::Isolate* isolate = CcTest::isolate();
9447 5 : v8::HandleScope scope0(isolate);
9448 : v8::Local<v8::ObjectTemplate> global_template =
9449 5 : v8::ObjectTemplate::New(isolate);
9450 10 : global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9451 : // Create an environment
9452 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9453 5 : context0->Enter();
9454 :
9455 5 : v8::Local<v8::Object> global0 = context0->Global();
9456 : v8::Local<Script> script0 = v8_compile("foo = 111");
9457 5 : script0->Run(context0).ToLocalChecked();
9458 15 : CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9459 : v8::Local<Value> foo0 =
9460 15 : global0->Get(context0, v8_str("foo")).ToLocalChecked();
9461 10 : CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9462 15 : v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9463 10 : CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9464 :
9465 : // Create another environment, should fail security checks.
9466 10 : v8::HandleScope scope1(isolate);
9467 :
9468 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, global_template);
9469 5 : context1->Enter();
9470 :
9471 5 : v8::Local<v8::Object> global1 = context1->Global();
9472 15 : global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9473 : // This set will fail the security check.
9474 : v8::Local<Script> script1 =
9475 : v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9476 10 : CHECK(script1->Run(context1).IsEmpty());
9477 5 : g_security_callback_result = true;
9478 : // This read will pass the security check.
9479 : v8::Local<Value> foo1 =
9480 15 : global0->Get(context1, v8_str("foo")).ToLocalChecked();
9481 10 : CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9482 : // This read will pass the security check.
9483 15 : v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9484 10 : CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9485 :
9486 : // Create another environment, should pass security checks.
9487 : {
9488 5 : v8::HandleScope scope2(isolate);
9489 10 : LocalContext context2;
9490 5 : v8::Local<v8::Object> global2 = context2->Global();
9491 20 : CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9492 : .FromJust());
9493 : v8::Local<Script> script2 =
9494 : v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9495 5 : script2->Run(context2.local()).ToLocalChecked();
9496 : v8::Local<Value> foo2 =
9497 15 : global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9498 10 : CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9499 : v8::Local<Value> z2 =
9500 15 : global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9501 15 : CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9502 : }
9503 :
9504 5 : context1->Exit();
9505 10 : context0->Exit();
9506 5 : }
9507 :
9508 :
9509 28343 : THREADED_TEST(SecurityChecks) {
9510 6 : LocalContext env1;
9511 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9512 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9513 :
9514 6 : Local<Value> foo = v8_str("foo");
9515 6 : Local<Value> bar = v8_str("bar");
9516 :
9517 : // Set to the same domain.
9518 6 : env1->SetSecurityToken(foo);
9519 :
9520 : // Create a function in env1.
9521 : CompileRun("spy=function(){return spy;}");
9522 : Local<Value> spy =
9523 30 : env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9524 6 : CHECK(spy->IsFunction());
9525 :
9526 : // Create another function accessing global objects.
9527 : CompileRun("spy2=function(){return new this.Array();}");
9528 : Local<Value> spy2 =
9529 30 : env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9530 6 : CHECK(spy2->IsFunction());
9531 :
9532 : // Switch to env2 in the same domain and invoke spy on env2.
9533 : {
9534 6 : env2->SetSecurityToken(foo);
9535 : // Enter env2
9536 : Context::Scope scope_env2(env2);
9537 : Local<Value> result = Function::Cast(*spy)
9538 12 : ->Call(env2, env2->Global(), 0, nullptr)
9539 6 : .ToLocalChecked();
9540 6 : CHECK(result->IsFunction());
9541 : }
9542 :
9543 : {
9544 6 : env2->SetSecurityToken(bar);
9545 : Context::Scope scope_env2(env2);
9546 :
9547 : // Call cross_domain_call, it should throw an exception
9548 12 : v8::TryCatch try_catch(env1->GetIsolate());
9549 18 : CHECK(Function::Cast(*spy2)
9550 : ->Call(env2, env2->Global(), 0, nullptr)
9551 : .IsEmpty());
9552 6 : CHECK(try_catch.HasCaught());
9553 6 : }
9554 6 : }
9555 :
9556 :
9557 : // Regression test case for issue 1183439.
9558 28343 : THREADED_TEST(SecurityChecksForPrototypeChain) {
9559 6 : LocalContext current;
9560 12 : v8::HandleScope scope(current->GetIsolate());
9561 6 : v8::Local<Context> other = Context::New(current->GetIsolate());
9562 :
9563 : // Change context to be able to get to the Object function in the
9564 : // other context without hitting the security checks.
9565 : v8::Local<Value> other_object;
9566 : { Context::Scope scope(other);
9567 : other_object =
9568 24 : other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9569 18 : CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9570 : }
9571 :
9572 36 : CHECK(current->Global()
9573 : ->Set(current.local(), v8_str("other"), other->Global())
9574 : .FromJust());
9575 30 : CHECK(v8_compile("other")
9576 : ->Run(current.local())
9577 : .ToLocalChecked()
9578 : ->Equals(current.local(), other->Global())
9579 : .FromJust());
9580 :
9581 : // Make sure the security check fails here and we get an undefined
9582 : // result instead of getting the Object function. Repeat in a loop
9583 : // to make sure to exercise the IC code.
9584 : v8::Local<Script> access_other0 = v8_compile("other.Object");
9585 : v8::Local<Script> access_other1 = v8_compile("other[42]");
9586 36 : for (int i = 0; i < 5; i++) {
9587 60 : CHECK(access_other0->Run(current.local()).IsEmpty());
9588 60 : CHECK(access_other1->Run(current.local()).IsEmpty());
9589 : }
9590 :
9591 : // Create an object that has 'other' in its prototype chain and make
9592 : // sure we cannot access the Object function indirectly through
9593 : // that. Repeat in a loop to make sure to exercise the IC code.
9594 : v8_compile(
9595 : "function F() { };"
9596 : "F.prototype = other;"
9597 : "var f = new F();")
9598 6 : ->Run(current.local())
9599 6 : .ToLocalChecked();
9600 : v8::Local<Script> access_f0 = v8_compile("f.Object");
9601 : v8::Local<Script> access_f1 = v8_compile("f[42]");
9602 36 : for (int j = 0; j < 5; j++) {
9603 60 : CHECK(access_f0->Run(current.local()).IsEmpty());
9604 60 : CHECK(access_f1->Run(current.local()).IsEmpty());
9605 : }
9606 :
9607 : // Now it gets hairy: Set the prototype for the other global object
9608 : // to be the current global object. The prototype chain for 'f' now
9609 : // goes through 'other' but ends up in the current global object.
9610 : { Context::Scope scope(other);
9611 30 : CHECK(other->Global()
9612 : ->Set(other, v8_str("__proto__"), current->Global())
9613 : .FromJust());
9614 : }
9615 : // Set a named and an index property on the current global
9616 : // object. To force the lookup to go through the other global object,
9617 : // the properties must not exist in the other global object.
9618 30 : CHECK(current->Global()
9619 : ->Set(current.local(), v8_str("foo"), v8_num(100))
9620 : .FromJust());
9621 24 : CHECK(current->Global()
9622 : ->Set(current.local(), v8_num(99), v8_num(101))
9623 : .FromJust());
9624 : // Try to read the properties from f and make sure that the access
9625 : // gets stopped by the security checks on the other global object.
9626 : Local<Script> access_f2 = v8_compile("f.foo");
9627 : Local<Script> access_f3 = v8_compile("f[99]");
9628 36 : for (int k = 0; k < 5; k++) {
9629 60 : CHECK(access_f2->Run(current.local()).IsEmpty());
9630 60 : CHECK(access_f3->Run(current.local()).IsEmpty());
9631 6 : }
9632 6 : }
9633 :
9634 :
9635 : static bool security_check_with_gc_called;
9636 :
9637 10 : static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9638 : Local<v8::Object> accessed_object,
9639 : Local<v8::Value> data) {
9640 10 : CcTest::CollectAllGarbage();
9641 10 : security_check_with_gc_called = true;
9642 10 : return true;
9643 : }
9644 :
9645 :
9646 28342 : TEST(SecurityTestGCAllowed) {
9647 5 : v8::Isolate* isolate = CcTest::isolate();
9648 5 : v8::HandleScope handle_scope(isolate);
9649 : v8::Local<v8::ObjectTemplate> object_template =
9650 5 : v8::ObjectTemplate::New(isolate);
9651 5 : object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9652 :
9653 5 : v8::Local<Context> context = Context::New(isolate);
9654 : v8::Context::Scope context_scope(context);
9655 :
9656 25 : CHECK(context->Global()
9657 : ->Set(context, v8_str("obj"),
9658 : object_template->NewInstance(context).ToLocalChecked())
9659 : .FromJust());
9660 :
9661 5 : security_check_with_gc_called = false;
9662 : CompileRun("obj[0] = new String(1002);");
9663 5 : CHECK(security_check_with_gc_called);
9664 :
9665 5 : security_check_with_gc_called = false;
9666 20 : CHECK(CompileRun("obj[0]")
9667 : ->ToString(context)
9668 : .ToLocalChecked()
9669 : ->Equals(context, v8_str("1002"))
9670 : .FromJust());
9671 10 : CHECK(security_check_with_gc_called);
9672 5 : }
9673 :
9674 :
9675 28343 : THREADED_TEST(CrossDomainDelete) {
9676 6 : LocalContext env1;
9677 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9678 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9679 :
9680 6 : Local<Value> foo = v8_str("foo");
9681 6 : Local<Value> bar = v8_str("bar");
9682 :
9683 : // Set to the same domain.
9684 6 : env1->SetSecurityToken(foo);
9685 6 : env2->SetSecurityToken(foo);
9686 :
9687 30 : CHECK(
9688 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9689 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9690 :
9691 : // Change env2 to a different domain and delete env1.prop.
9692 6 : env2->SetSecurityToken(bar);
9693 : {
9694 : Context::Scope scope_env2(env2);
9695 : Local<Value> result =
9696 : CompileRun("delete env1.prop");
9697 6 : CHECK(result.IsEmpty());
9698 : }
9699 :
9700 : // Check that env1.prop still exists.
9701 : Local<Value> v =
9702 30 : env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9703 6 : CHECK(v->IsNumber());
9704 18 : CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9705 6 : }
9706 :
9707 :
9708 28343 : THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9709 6 : LocalContext env1;
9710 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9711 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9712 :
9713 6 : Local<Value> foo = v8_str("foo");
9714 6 : Local<Value> bar = v8_str("bar");
9715 :
9716 : // Set to the same domain.
9717 6 : env1->SetSecurityToken(foo);
9718 6 : env2->SetSecurityToken(foo);
9719 :
9720 30 : CHECK(
9721 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9722 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9723 :
9724 : // env1.prop is enumerable in env2.
9725 6 : Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9726 : {
9727 : Context::Scope scope_env2(env2);
9728 6 : Local<Value> result = CompileRun(test);
9729 6 : CHECK(result->IsTrue());
9730 : }
9731 :
9732 : // Change env2 to a different domain and test again.
9733 6 : env2->SetSecurityToken(bar);
9734 : {
9735 : Context::Scope scope_env2(env2);
9736 6 : Local<Value> result = CompileRun(test);
9737 6 : CHECK(result.IsEmpty());
9738 6 : }
9739 6 : }
9740 :
9741 :
9742 28343 : THREADED_TEST(CrossDomainFor) {
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 30 : 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 : // Change env2 to a different domain and set env1's global object
9759 : // as the __proto__ of an object in env2 and enumerate properties
9760 : // in for-in. It shouldn't enumerate properties on env1's global
9761 : // object. It shouldn't throw either, just silently ignore them.
9762 6 : env2->SetSecurityToken(bar);
9763 : {
9764 : Context::Scope scope_env2(env2);
9765 : Local<Value> result = CompileRun(
9766 : "(function() {"
9767 : " try {"
9768 : " for (var p in env1) {"
9769 : " if (p == 'prop') return false;"
9770 : " }"
9771 : " return true;"
9772 : " } catch (e) {"
9773 : " return false;"
9774 : " }"
9775 : "})()");
9776 6 : CHECK(result->IsTrue());
9777 6 : }
9778 6 : }
9779 :
9780 :
9781 28343 : THREADED_TEST(CrossDomainForInOnPrototype) {
9782 6 : LocalContext env1;
9783 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9784 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9785 :
9786 6 : Local<Value> foo = v8_str("foo");
9787 6 : Local<Value> bar = v8_str("bar");
9788 :
9789 : // Set to the same domain.
9790 6 : env1->SetSecurityToken(foo);
9791 6 : env2->SetSecurityToken(foo);
9792 :
9793 30 : CHECK(
9794 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9795 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9796 :
9797 : // Change env2 to a different domain and set env1's global object
9798 : // as the __proto__ of an object in env2 and enumerate properties
9799 : // in for-in. It shouldn't enumerate properties on env1's global
9800 : // object.
9801 6 : env2->SetSecurityToken(bar);
9802 : {
9803 : Context::Scope scope_env2(env2);
9804 : Local<Value> result = CompileRun(
9805 : "(function() {"
9806 : " var obj = { '__proto__': env1 };"
9807 : " try {"
9808 : " for (var p in obj) {"
9809 : " if (p == 'prop') return false;"
9810 : " }"
9811 : " return true;"
9812 : " } catch (e) {"
9813 : " return false;"
9814 : " }"
9815 : "})()");
9816 6 : CHECK(result->IsTrue());
9817 6 : }
9818 6 : }
9819 :
9820 :
9821 28342 : TEST(ContextDetachGlobal) {
9822 5 : LocalContext env1;
9823 10 : v8::HandleScope handle_scope(env1->GetIsolate());
9824 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9825 :
9826 :
9827 5 : Local<Value> foo = v8_str("foo");
9828 :
9829 : // Set to the same domain.
9830 5 : env1->SetSecurityToken(foo);
9831 5 : env2->SetSecurityToken(foo);
9832 :
9833 : // Enter env2
9834 5 : env2->Enter();
9835 :
9836 : // Create a function in env2 and add a reference to it in env1.
9837 5 : Local<v8::Object> global2 = env2->Global();
9838 20 : CHECK(global2->Set(env2, v8_str("prop"),
9839 : v8::Integer::New(env2->GetIsolate(), 1))
9840 : .FromJust());
9841 : CompileRun("function getProp() {return prop;}");
9842 :
9843 35 : CHECK(env1->Global()
9844 : ->Set(env1.local(), v8_str("getProp"),
9845 : global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9846 : .FromJust());
9847 :
9848 : // Detach env2's global, and reuse the global object of env2
9849 5 : env2->Exit();
9850 5 : env2->DetachGlobal();
9851 :
9852 : v8::Local<Context> env3 = Context::New(
9853 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9854 10 : env3->SetSecurityToken(v8_str("bar"));
9855 :
9856 5 : env3->Enter();
9857 5 : Local<v8::Object> global3 = env3->Global();
9858 10 : CHECK(global2->Equals(env3, global3).FromJust());
9859 15 : CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9860 15 : CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9861 20 : CHECK(global3->Set(env3, v8_str("prop"),
9862 : v8::Integer::New(env3->GetIsolate(), -1))
9863 : .FromJust());
9864 20 : CHECK(global3->Set(env3, v8_str("prop2"),
9865 : v8::Integer::New(env3->GetIsolate(), 2))
9866 : .FromJust());
9867 5 : env3->Exit();
9868 :
9869 : // Call getProp in env1, and it should return the value 1
9870 : {
9871 5 : Local<v8::Object> global1 = env1->Global();
9872 : Local<Value> get_prop =
9873 20 : global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9874 5 : CHECK(get_prop->IsFunction());
9875 5 : v8::TryCatch try_catch(env1->GetIsolate());
9876 : Local<Value> r = Function::Cast(*get_prop)
9877 10 : ->Call(env1.local(), global1, 0, nullptr)
9878 5 : .ToLocalChecked();
9879 5 : CHECK(!try_catch.HasCaught());
9880 10 : CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9881 : }
9882 :
9883 : // Check that env3 is not accessible from env1
9884 : {
9885 10 : v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9886 5 : CHECK(r.IsEmpty());
9887 5 : }
9888 5 : }
9889 :
9890 :
9891 28342 : TEST(DetachGlobal) {
9892 5 : LocalContext env1;
9893 10 : v8::HandleScope scope(env1->GetIsolate());
9894 :
9895 : // Create second environment.
9896 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9897 :
9898 5 : Local<Value> foo = v8_str("foo");
9899 :
9900 : // Set same security token for env1 and env2.
9901 5 : env1->SetSecurityToken(foo);
9902 5 : env2->SetSecurityToken(foo);
9903 :
9904 : // Create a property on the global object in env2.
9905 : {
9906 : v8::Context::Scope scope(env2);
9907 25 : CHECK(env2->Global()
9908 : ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9909 : .FromJust());
9910 : }
9911 :
9912 : // Create a reference to env2 global from env1 global.
9913 30 : CHECK(env1->Global()
9914 : ->Set(env1.local(), v8_str("other"), env2->Global())
9915 : .FromJust());
9916 :
9917 : // Check that we have access to other.p in env2 from env1.
9918 : Local<Value> result = CompileRun("other.p");
9919 5 : CHECK(result->IsInt32());
9920 10 : CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9921 :
9922 : // Hold on to global from env2 and detach global from env2.
9923 5 : Local<v8::Object> global2 = env2->Global();
9924 5 : env2->DetachGlobal();
9925 :
9926 : // Check that the global has been detached. No other.p property can
9927 : // be found.
9928 : result = CompileRun("other.p");
9929 5 : CHECK(result.IsEmpty());
9930 :
9931 : // Reuse global2 for env3.
9932 : v8::Local<Context> env3 = Context::New(
9933 5 : env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9934 15 : CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9935 :
9936 : // Start by using the same security token for env3 as for env1 and env2.
9937 5 : env3->SetSecurityToken(foo);
9938 :
9939 : // Create a property on the global object in env3.
9940 : {
9941 : v8::Context::Scope scope(env3);
9942 25 : CHECK(env3->Global()
9943 : ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9944 : .FromJust());
9945 : }
9946 :
9947 : // Check that other.p is now the property in env3 and that we have access.
9948 : result = CompileRun("other.p");
9949 5 : CHECK(result->IsInt32());
9950 15 : CHECK_EQ(24, result->Int32Value(env3).FromJust());
9951 5 : }
9952 :
9953 :
9954 130 : void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9955 65 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9956 : info.GetReturnValue().Set(
9957 260 : context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9958 65 : }
9959 :
9960 :
9961 28342 : TEST(DetachedAccesses) {
9962 5 : LocalContext env1;
9963 10 : v8::HandleScope scope(env1->GetIsolate());
9964 :
9965 : // Create second environment.
9966 : Local<ObjectTemplate> inner_global_template =
9967 10 : FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9968 : inner_global_template ->SetAccessorProperty(
9969 10 : v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9970 : v8::Local<Context> env2 =
9971 5 : Context::New(env1->GetIsolate(), nullptr, inner_global_template);
9972 :
9973 5 : Local<Value> foo = v8_str("foo");
9974 :
9975 : // Set same security token for env1 and env2.
9976 5 : env1->SetSecurityToken(foo);
9977 5 : env2->SetSecurityToken(foo);
9978 :
9979 30 : CHECK(env1->Global()
9980 : ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
9981 : .FromJust());
9982 :
9983 : {
9984 : v8::Context::Scope scope(env2);
9985 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
9986 : CompileRun(
9987 : "function bound_x() { return x; }"
9988 : "function get_x() { return this.x; }"
9989 : "function get_x_w() { return (function() {return this.x;})(); }");
9990 25 : CHECK(env1->Global()
9991 : ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
9992 : .FromJust());
9993 25 : CHECK(env1->Global()
9994 : ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
9995 : .FromJust());
9996 25 : CHECK(env1->Global()
9997 : ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
9998 : .FromJust());
9999 : env1->Global()
10000 : ->Set(env1.local(), v8_str("this_x"),
10001 20 : CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
10002 10 : .FromJust();
10003 : }
10004 :
10005 5 : Local<Object> env2_global = env2->Global();
10006 5 : env2->DetachGlobal();
10007 :
10008 : Local<Value> result;
10009 : result = CompileRun("bound_x()");
10010 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10011 : result = CompileRun("get_x()");
10012 5 : CHECK(result.IsEmpty());
10013 : result = CompileRun("get_x_w()");
10014 5 : CHECK(result.IsEmpty());
10015 : result = CompileRun("this_x()");
10016 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10017 :
10018 : // Reattach env2's proxy
10019 : env2 = Context::New(env1->GetIsolate(), nullptr,
10020 5 : v8::Local<v8::ObjectTemplate>(), env2_global);
10021 5 : env2->SetSecurityToken(foo);
10022 : {
10023 : v8::Context::Scope scope(env2);
10024 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
10025 25 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
10026 : result = CompileRun(
10027 : "results = [];"
10028 : "for (var i = 0; i < 4; i++ ) {"
10029 : " results.push(env1.bound_x());"
10030 : " results.push(env1.get_x());"
10031 : " results.push(env1.get_x_w());"
10032 : " results.push(env1.this_x());"
10033 : "}"
10034 : "results");
10035 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10036 5 : CHECK_EQ(16u, results->Length());
10037 20 : for (int i = 0; i < 16; i += 4) {
10038 80 : CHECK(v8_str("env2_x")
10039 : ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
10040 : .FromJust());
10041 80 : CHECK(v8_str("env1_x")
10042 : ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
10043 : .FromJust());
10044 80 : CHECK(v8_str("env3_x")
10045 : ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
10046 : .FromJust());
10047 80 : CHECK(v8_str("env2_x")
10048 : ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
10049 : .FromJust());
10050 : }
10051 : }
10052 :
10053 : result = CompileRun(
10054 : "results = [];"
10055 : "for (var i = 0; i < 4; i++ ) {"
10056 : " results.push(bound_x());"
10057 : " results.push(get_x());"
10058 : " results.push(get_x_w());"
10059 : " results.push(this_x());"
10060 : "}"
10061 : "results");
10062 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
10063 5 : CHECK_EQ(16u, results->Length());
10064 20 : for (int i = 0; i < 16; i += 4) {
10065 80 : CHECK(v8_str("env2_x")
10066 : ->Equals(env1.local(),
10067 : results->Get(env1.local(), i + 0).ToLocalChecked())
10068 : .FromJust());
10069 80 : CHECK(v8_str("env3_x")
10070 : ->Equals(env1.local(),
10071 : results->Get(env1.local(), i + 1).ToLocalChecked())
10072 : .FromJust());
10073 80 : CHECK(v8_str("env3_x")
10074 : ->Equals(env1.local(),
10075 : results->Get(env1.local(), i + 2).ToLocalChecked())
10076 : .FromJust());
10077 80 : CHECK(v8_str("env2_x")
10078 : ->Equals(env1.local(),
10079 : results->Get(env1.local(), i + 3).ToLocalChecked())
10080 : .FromJust());
10081 : }
10082 :
10083 : result = CompileRun(
10084 : "results = [];"
10085 : "for (var i = 0; i < 4; i++ ) {"
10086 : " results.push(this.bound_x());"
10087 : " results.push(this.get_x());"
10088 : " results.push(this.get_x_w());"
10089 : " results.push(this.this_x());"
10090 : "}"
10091 : "results");
10092 : results = Local<v8::Array>::Cast(result);
10093 5 : CHECK_EQ(16u, results->Length());
10094 20 : for (int i = 0; i < 16; i += 4) {
10095 80 : CHECK(v8_str("env2_x")
10096 : ->Equals(env1.local(),
10097 : results->Get(env1.local(), i + 0).ToLocalChecked())
10098 : .FromJust());
10099 80 : CHECK(v8_str("env1_x")
10100 : ->Equals(env1.local(),
10101 : results->Get(env1.local(), i + 1).ToLocalChecked())
10102 : .FromJust());
10103 80 : CHECK(v8_str("env3_x")
10104 : ->Equals(env1.local(),
10105 : results->Get(env1.local(), i + 2).ToLocalChecked())
10106 : .FromJust());
10107 80 : CHECK(v8_str("env2_x")
10108 : ->Equals(env1.local(),
10109 : results->Get(env1.local(), i + 3).ToLocalChecked())
10110 : .FromJust());
10111 5 : }
10112 5 : }
10113 :
10114 :
10115 : static bool allowed_access = false;
10116 370 : static bool AccessBlocker(Local<v8::Context> accessing_context,
10117 : Local<v8::Object> accessed_object,
10118 : Local<v8::Value> data) {
10119 370 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
10120 1110 : return context->Global()->Equals(context, accessed_object).FromJust() ||
10121 370 : allowed_access;
10122 : }
10123 :
10124 :
10125 : static int g_echo_value = -1;
10126 :
10127 :
10128 15 : static void EchoGetter(
10129 : Local<String> name,
10130 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10131 15 : info.GetReturnValue().Set(v8_num(g_echo_value));
10132 15 : }
10133 :
10134 :
10135 10 : static void EchoSetter(Local<String> name, Local<Value> value,
10136 : const v8::PropertyCallbackInfo<void>& args) {
10137 10 : if (value->IsNumber())
10138 : g_echo_value =
10139 20 : value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
10140 10 : }
10141 :
10142 :
10143 0 : static void UnreachableGetter(
10144 : Local<String> name,
10145 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10146 0 : UNREACHABLE(); // This function should not be called..
10147 : }
10148 :
10149 :
10150 0 : static void UnreachableSetter(Local<String>,
10151 : Local<Value>,
10152 : const v8::PropertyCallbackInfo<void>&) {
10153 0 : UNREACHABLE(); // This function should not be called.
10154 : }
10155 :
10156 :
10157 0 : static void UnreachableFunction(
10158 : const v8::FunctionCallbackInfo<v8::Value>& info) {
10159 0 : UNREACHABLE(); // This function should not be called..
10160 : }
10161 :
10162 :
10163 28342 : TEST(AccessControl) {
10164 5 : v8::Isolate* isolate = CcTest::isolate();
10165 5 : v8::HandleScope handle_scope(isolate);
10166 : v8::Local<v8::ObjectTemplate> global_template =
10167 5 : v8::ObjectTemplate::New(isolate);
10168 :
10169 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10170 :
10171 : // Add an accessor accessible by cross-domain JS code.
10172 : global_template->SetAccessor(
10173 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10174 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10175 :
10176 :
10177 : // Add an accessor that is not accessible by cross-domain JS code.
10178 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10179 : UnreachableSetter, v8::Local<Value>(),
10180 5 : v8::DEFAULT);
10181 :
10182 : global_template->SetAccessorProperty(
10183 : v8_str("blocked_js_prop"),
10184 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10185 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
10186 : v8::None,
10187 15 : v8::DEFAULT);
10188 :
10189 : // Create an environment
10190 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10191 5 : context0->Enter();
10192 :
10193 5 : v8::Local<v8::Object> global0 = context0->Global();
10194 :
10195 : // Define a property with JS getter and setter.
10196 : CompileRun(
10197 : "function getter() { return 'getter'; };\n"
10198 : "function setter() { return 'setter'; }\n"
10199 : "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
10200 :
10201 : Local<Value> getter =
10202 15 : global0->Get(context0, v8_str("getter")).ToLocalChecked();
10203 : Local<Value> setter =
10204 15 : global0->Get(context0, v8_str("setter")).ToLocalChecked();
10205 :
10206 : // And define normal element.
10207 15 : CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
10208 :
10209 : // Define an element with JS getter and setter.
10210 : CompileRun(
10211 : "function el_getter() { return 'el_getter'; };\n"
10212 : "function el_setter() { return 'el_setter'; };\n"
10213 : "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
10214 :
10215 : Local<Value> el_getter =
10216 15 : global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
10217 : Local<Value> el_setter =
10218 15 : global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
10219 :
10220 10 : v8::HandleScope scope1(isolate);
10221 :
10222 5 : v8::Local<Context> context1 = Context::New(isolate);
10223 5 : context1->Enter();
10224 :
10225 5 : v8::Local<v8::Object> global1 = context1->Global();
10226 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10227 :
10228 : // Access blocked property.
10229 : CompileRun("other.blocked_prop = 1");
10230 :
10231 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10232 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10233 : .IsEmpty());
10234 5 : CHECK(
10235 : CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
10236 :
10237 : // Access blocked element.
10238 5 : CHECK(CompileRun("other[239] = 1").IsEmpty());
10239 :
10240 5 : CHECK(CompileRun("other[239]").IsEmpty());
10241 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10242 5 : CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10243 :
10244 5 : allowed_access = true;
10245 : // Now we can enumerate the property.
10246 : ExpectTrue("propertyIsEnumerable.call(other, '239')");
10247 5 : allowed_access = false;
10248 :
10249 : // Access a property with JS accessor.
10250 5 : CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10251 :
10252 5 : CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10253 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10254 : .IsEmpty());
10255 :
10256 5 : allowed_access = true;
10257 :
10258 5 : ExpectString("other.js_accessor_p", "getter");
10259 : ExpectObject(
10260 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10261 : ExpectObject(
10262 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10263 : ExpectUndefined(
10264 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10265 :
10266 5 : allowed_access = false;
10267 :
10268 : // Access an element with JS accessor.
10269 5 : CHECK(CompileRun("other[42] = 2").IsEmpty());
10270 :
10271 5 : CHECK(CompileRun("other[42]").IsEmpty());
10272 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10273 :
10274 5 : allowed_access = true;
10275 :
10276 5 : ExpectString("other[42]", "el_getter");
10277 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10278 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10279 5 : ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10280 :
10281 5 : allowed_access = false;
10282 :
10283 : v8::Local<Value> value;
10284 :
10285 : // Access accessible property
10286 : value = CompileRun("other.accessible_prop = 3");
10287 5 : CHECK(value->IsNumber());
10288 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10289 5 : CHECK_EQ(3, g_echo_value);
10290 :
10291 : value = CompileRun("other.accessible_prop");
10292 5 : CHECK(value->IsNumber());
10293 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10294 :
10295 : value = CompileRun(
10296 : "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10297 5 : CHECK(value->IsNumber());
10298 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10299 :
10300 : value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10301 5 : CHECK(value->IsTrue());
10302 :
10303 : // Enumeration doesn't enumerate accessors from inaccessible objects in
10304 : // the prototype chain even if the accessors are in themselves accessible.
10305 : // Enumeration doesn't throw, it silently ignores what it can't access.
10306 : value = CompileRun(
10307 : "(function() {"
10308 : " var obj = { '__proto__': other };"
10309 : " try {"
10310 : " for (var p in obj) {"
10311 : " if (p == 'accessible_prop' ||"
10312 : " p == 'blocked_js_prop' ||"
10313 : " p == 'blocked_js_prop') {"
10314 : " return false;"
10315 : " }"
10316 : " }"
10317 : " return true;"
10318 : " } catch (e) {"
10319 : " return false;"
10320 : " }"
10321 : "})()");
10322 5 : CHECK(value->IsTrue());
10323 :
10324 : // Test that preventExtensions fails on a non-accessible object even if that
10325 : // object is already non-extensible.
10326 20 : CHECK(global1->Set(context1, v8_str("checked_object"),
10327 : global_template->NewInstance(context1).ToLocalChecked())
10328 : .FromJust());
10329 5 : allowed_access = true;
10330 : CompileRun("Object.preventExtensions(checked_object)");
10331 : ExpectFalse("Object.isExtensible(checked_object)");
10332 5 : allowed_access = false;
10333 5 : CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10334 :
10335 5 : context1->Exit();
10336 10 : context0->Exit();
10337 5 : }
10338 :
10339 :
10340 28342 : TEST(AccessControlES5) {
10341 5 : v8::Isolate* isolate = CcTest::isolate();
10342 5 : v8::HandleScope handle_scope(isolate);
10343 : v8::Local<v8::ObjectTemplate> global_template =
10344 5 : v8::ObjectTemplate::New(isolate);
10345 :
10346 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10347 :
10348 : // Add accessible accessor.
10349 : global_template->SetAccessor(
10350 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10351 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10352 :
10353 :
10354 : // Add an accessor that is not accessible by cross-domain JS code.
10355 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10356 : UnreachableSetter, v8::Local<Value>(),
10357 5 : v8::DEFAULT);
10358 :
10359 : // Create an environment
10360 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10361 5 : context0->Enter();
10362 :
10363 5 : v8::Local<v8::Object> global0 = context0->Global();
10364 :
10365 5 : v8::Local<Context> context1 = Context::New(isolate);
10366 5 : context1->Enter();
10367 5 : v8::Local<v8::Object> global1 = context1->Global();
10368 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10369 :
10370 : // Regression test for issue 1154.
10371 5 : CHECK(CompileRun("Object.keys(other).length == 1")->BooleanValue(isolate));
10372 5 : CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10373 : ->BooleanValue(isolate));
10374 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10375 :
10376 : // Regression test for issue 1027.
10377 : CompileRun("Object.defineProperty(\n"
10378 : " other, 'blocked_prop', {configurable: false})");
10379 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10380 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10381 : .IsEmpty());
10382 :
10383 : // Regression test for issue 1171.
10384 : ExpectTrue("Object.isExtensible(other)");
10385 : CompileRun("Object.preventExtensions(other)");
10386 : ExpectTrue("Object.isExtensible(other)");
10387 :
10388 : // Object.seal and Object.freeze.
10389 : CompileRun("Object.freeze(other)");
10390 : ExpectTrue("Object.isExtensible(other)");
10391 :
10392 : CompileRun("Object.seal(other)");
10393 : ExpectTrue("Object.isExtensible(other)");
10394 :
10395 : // Regression test for issue 1250.
10396 : // Make sure that we can set the accessible accessors value using normal
10397 : // assignment.
10398 : CompileRun("other.accessible_prop = 42");
10399 5 : CHECK_EQ(42, g_echo_value);
10400 :
10401 : // [[DefineOwnProperty]] always throws for access-checked objects.
10402 5 : CHECK(
10403 : CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10404 : .IsEmpty());
10405 5 : CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10406 5 : CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10407 5 : }
10408 :
10409 235 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10410 : Local<v8::Object> global,
10411 : Local<v8::Value> data) {
10412 235 : i::PrintF("Access blocked.\n");
10413 235 : return false;
10414 : }
10415 :
10416 5 : static bool AccessAlwaysAllowed(Local<v8::Context> accessing_context,
10417 : Local<v8::Object> global,
10418 : Local<v8::Value> data) {
10419 5 : i::PrintF("Access allowed.\n");
10420 5 : return true;
10421 : }
10422 :
10423 28343 : THREADED_TEST(AccessControlGetOwnPropertyNames) {
10424 6 : v8::Isolate* isolate = CcTest::isolate();
10425 6 : v8::HandleScope handle_scope(isolate);
10426 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10427 :
10428 18 : obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10429 6 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10430 :
10431 : // Add an accessor accessible by cross-domain JS code.
10432 : obj_template->SetAccessor(
10433 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10434 6 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10435 :
10436 : // Create an environment
10437 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
10438 6 : context0->Enter();
10439 :
10440 6 : v8::Local<v8::Object> global0 = context0->Global();
10441 :
10442 12 : v8::HandleScope scope1(CcTest::isolate());
10443 :
10444 6 : v8::Local<Context> context1 = Context::New(isolate);
10445 6 : context1->Enter();
10446 :
10447 6 : v8::Local<v8::Object> global1 = context1->Global();
10448 18 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10449 24 : CHECK(global1->Set(context1, v8_str("object"),
10450 : obj_template->NewInstance(context1).ToLocalChecked())
10451 : .FromJust());
10452 :
10453 : v8::Local<Value> value;
10454 :
10455 : // Attempt to get the property names of the other global object and
10456 : // of an object that requires access checks. Accessing the other
10457 : // global object should be blocked by access checks on the global
10458 : // proxy object. Accessing the object that requires access checks
10459 : // is blocked by the access checks on the object itself.
10460 : value = CompileRun(
10461 : "var names = Object.getOwnPropertyNames(other);"
10462 : "names.length == 1 && names[0] == 'accessible_prop';");
10463 6 : CHECK(value->BooleanValue(isolate));
10464 :
10465 : value = CompileRun(
10466 : "var names = Object.getOwnPropertyNames(object);"
10467 : "names.length == 1 && names[0] == 'accessible_prop';");
10468 6 : CHECK(value->BooleanValue(isolate));
10469 :
10470 6 : context1->Exit();
10471 12 : context0->Exit();
10472 6 : }
10473 :
10474 :
10475 28342 : TEST(Regress470113) {
10476 5 : v8::Isolate* isolate = CcTest::isolate();
10477 5 : v8::HandleScope handle_scope(isolate);
10478 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10479 5 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10480 10 : LocalContext env;
10481 30 : CHECK(env->Global()
10482 : ->Set(env.local(), v8_str("prohibited"),
10483 : obj_template->NewInstance(env.local()).ToLocalChecked())
10484 : .FromJust());
10485 :
10486 : {
10487 5 : v8::TryCatch try_catch(isolate);
10488 : CompileRun(
10489 : "'use strict';\n"
10490 : "class C extends Object {\n"
10491 : " m() { super.powned = 'Powned!'; }\n"
10492 : "}\n"
10493 : "let c = new C();\n"
10494 : "c.m.call(prohibited)");
10495 :
10496 5 : CHECK(try_catch.HasCaught());
10497 5 : }
10498 5 : }
10499 :
10500 :
10501 6 : static void ConstTenGetter(Local<String> name,
10502 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10503 6 : info.GetReturnValue().Set(v8_num(10));
10504 6 : }
10505 :
10506 :
10507 28343 : THREADED_TEST(CrossDomainAccessors) {
10508 6 : v8::Isolate* isolate = CcTest::isolate();
10509 6 : v8::HandleScope handle_scope(isolate);
10510 :
10511 : v8::Local<v8::FunctionTemplate> func_template =
10512 6 : v8::FunctionTemplate::New(isolate);
10513 :
10514 : v8::Local<v8::ObjectTemplate> global_template =
10515 6 : func_template->InstanceTemplate();
10516 :
10517 : v8::Local<v8::ObjectTemplate> proto_template =
10518 6 : func_template->PrototypeTemplate();
10519 :
10520 : // Add an accessor to proto that's accessible by cross-domain JS code.
10521 : proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, nullptr,
10522 12 : v8::Local<Value>(), v8::ALL_CAN_READ);
10523 :
10524 : // Add an accessor that is not accessible by cross-domain JS code.
10525 : global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter,
10526 12 : nullptr, v8::Local<Value>(), v8::DEFAULT);
10527 :
10528 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10529 6 : context0->Enter();
10530 :
10531 6 : Local<v8::Object> global = context0->Global();
10532 : // Add a normal property that shadows 'accessible'
10533 18 : CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10534 :
10535 : // Enter a new context.
10536 12 : v8::HandleScope scope1(CcTest::isolate());
10537 6 : v8::Local<Context> context1 = Context::New(isolate);
10538 6 : context1->Enter();
10539 :
10540 6 : v8::Local<v8::Object> global1 = context1->Global();
10541 18 : CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10542 :
10543 : // Should return 10, instead of 11
10544 : v8::Local<Value> value =
10545 6 : v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10546 6 : CHECK(value->IsNumber());
10547 12 : CHECK_EQ(10, value->Int32Value(context1).FromJust());
10548 :
10549 : v8::MaybeLocal<v8::Value> maybe_value =
10550 6 : v8_compile("other.unreachable")->Run(context1);
10551 6 : CHECK(maybe_value.IsEmpty());
10552 :
10553 6 : context1->Exit();
10554 12 : context0->Exit();
10555 6 : }
10556 :
10557 :
10558 : static int access_count = 0;
10559 :
10560 820 : static bool AccessCounter(Local<v8::Context> accessing_context,
10561 : Local<v8::Object> accessed_object,
10562 : Local<v8::Value> data) {
10563 820 : access_count++;
10564 820 : return true;
10565 : }
10566 :
10567 :
10568 : // This one is too easily disturbed by other tests.
10569 28342 : TEST(AccessControlIC) {
10570 5 : access_count = 0;
10571 :
10572 5 : v8::Isolate* isolate = CcTest::isolate();
10573 5 : v8::HandleScope handle_scope(isolate);
10574 :
10575 : // Create an environment.
10576 5 : v8::Local<Context> context0 = Context::New(isolate);
10577 5 : context0->Enter();
10578 :
10579 : // Create an object that requires access-check functions to be
10580 : // called for cross-domain access.
10581 : v8::Local<v8::ObjectTemplate> object_template =
10582 5 : v8::ObjectTemplate::New(isolate);
10583 5 : object_template->SetAccessCheckCallback(AccessCounter);
10584 : Local<v8::Object> object =
10585 5 : object_template->NewInstance(context0).ToLocalChecked();
10586 :
10587 10 : v8::HandleScope scope1(isolate);
10588 :
10589 : // Create another environment.
10590 5 : v8::Local<Context> context1 = Context::New(isolate);
10591 5 : context1->Enter();
10592 :
10593 : // Make easy access to the object from the other environment.
10594 5 : v8::Local<v8::Object> global1 = context1->Global();
10595 15 : CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10596 :
10597 : v8::Local<Value> value;
10598 :
10599 : // Check that the named access-control function is called every time.
10600 : CompileRun("function testProp(obj) {"
10601 : " for (var i = 0; i < 10; i++) obj.prop = 1;"
10602 : " for (var j = 0; j < 10; j++) obj.prop;"
10603 : " return obj.prop"
10604 : "}");
10605 : value = CompileRun("testProp(obj)");
10606 5 : CHECK(value->IsNumber());
10607 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10608 5 : CHECK_EQ(21, access_count);
10609 :
10610 : // Check that the named access-control function is called every time.
10611 : CompileRun("var p = 'prop';"
10612 : "function testKeyed(obj) {"
10613 : " for (var i = 0; i < 10; i++) obj[p] = 1;"
10614 : " for (var j = 0; j < 10; j++) obj[p];"
10615 : " return obj[p];"
10616 : "}");
10617 : // Use obj which requires access checks. No inline caching is used
10618 : // in that case.
10619 : value = CompileRun("testKeyed(obj)");
10620 5 : CHECK(value->IsNumber());
10621 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10622 5 : CHECK_EQ(42, access_count);
10623 : // Force the inline caches into generic state and try again.
10624 : CompileRun("testKeyed({ a: 0 })");
10625 : CompileRun("testKeyed({ b: 0 })");
10626 : value = CompileRun("testKeyed(obj)");
10627 5 : CHECK(value->IsNumber());
10628 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10629 5 : CHECK_EQ(63, access_count);
10630 :
10631 : // Check that the indexed access-control function is called every time.
10632 5 : access_count = 0;
10633 :
10634 : CompileRun("function testIndexed(obj) {"
10635 : " for (var i = 0; i < 10; i++) obj[0] = 1;"
10636 : " for (var j = 0; j < 10; j++) obj[0];"
10637 : " return obj[0]"
10638 : "}");
10639 : value = CompileRun("testIndexed(obj)");
10640 5 : CHECK(value->IsNumber());
10641 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10642 5 : CHECK_EQ(21, access_count);
10643 : // Force the inline caches into generic state.
10644 : CompileRun("testIndexed(new Array(1))");
10645 : // Test that the indexed access check is called.
10646 : value = CompileRun("testIndexed(obj)");
10647 5 : CHECK(value->IsNumber());
10648 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10649 5 : CHECK_EQ(42, access_count);
10650 :
10651 5 : access_count = 0;
10652 : // Check that the named access check is called when invoking
10653 : // functions on an object that requires access checks.
10654 : CompileRun("obj.f = function() {}");
10655 : CompileRun("function testCallNormal(obj) {"
10656 : " for (var i = 0; i < 10; i++) obj.f();"
10657 : "}");
10658 : CompileRun("testCallNormal(obj)");
10659 5 : printf("%i\n", access_count);
10660 5 : CHECK_EQ(11, access_count);
10661 :
10662 : // Force obj into slow case.
10663 : value = CompileRun("delete obj.prop");
10664 5 : CHECK(value->BooleanValue(isolate));
10665 : // Force inline caches into dictionary probing mode.
10666 : CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10667 : // Test that the named access check is called.
10668 : value = CompileRun("testProp(obj);");
10669 5 : CHECK(value->IsNumber());
10670 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10671 5 : CHECK_EQ(33, access_count);
10672 :
10673 : // Force the call inline cache into dictionary probing mode.
10674 : CompileRun("o.f = function() {}; testCallNormal(o)");
10675 : // Test that the named access check is still called for each
10676 : // invocation of the function.
10677 : value = CompileRun("testCallNormal(obj)");
10678 5 : CHECK_EQ(43, access_count);
10679 :
10680 5 : context1->Exit();
10681 10 : context0->Exit();
10682 5 : }
10683 :
10684 :
10685 28343 : THREADED_TEST(Version) { v8::V8::GetVersion(); }
10686 :
10687 :
10688 18 : static void InstanceFunctionCallback(
10689 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10690 18 : ApiTestFuzzer::Fuzz();
10691 18 : args.GetReturnValue().Set(v8_num(12));
10692 18 : }
10693 :
10694 :
10695 28343 : THREADED_TEST(InstanceProperties) {
10696 6 : LocalContext context;
10697 6 : v8::Isolate* isolate = context->GetIsolate();
10698 12 : v8::HandleScope handle_scope(isolate);
10699 :
10700 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10701 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10702 :
10703 18 : instance->Set(v8_str("x"), v8_num(42));
10704 : instance->Set(v8_str("f"),
10705 18 : v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10706 :
10707 6 : Local<Value> o = t->GetFunction(context.local())
10708 6 : .ToLocalChecked()
10709 6 : ->NewInstance(context.local())
10710 : .ToLocalChecked();
10711 :
10712 30 : CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10713 : Local<Value> value = CompileRun("i.x");
10714 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10715 :
10716 : value = CompileRun("i.f()");
10717 18 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10718 6 : }
10719 :
10720 :
10721 696 : static void GlobalObjectInstancePropertiesGet(
10722 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10723 696 : ApiTestFuzzer::Fuzz();
10724 696 : }
10725 :
10726 :
10727 28343 : THREADED_TEST(GlobalObjectInstanceProperties) {
10728 6 : v8::Isolate* isolate = CcTest::isolate();
10729 6 : v8::HandleScope handle_scope(isolate);
10730 :
10731 : Local<Value> global_object;
10732 :
10733 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10734 : t->InstanceTemplate()->SetHandler(
10735 12 : v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10736 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10737 18 : instance_template->Set(v8_str("x"), v8_num(42));
10738 : instance_template->Set(v8_str("f"),
10739 : v8::FunctionTemplate::New(isolate,
10740 18 : InstanceFunctionCallback));
10741 :
10742 : // The script to check how TurboFan compiles missing global function
10743 : // invocations. function g is not defined and should throw on call.
10744 : const char* script =
10745 : "function wrapper(call) {"
10746 : " var x = 0, y = 1;"
10747 : " for (var i = 0; i < 1000; i++) {"
10748 : " x += i * 100;"
10749 : " y += i * 100;"
10750 : " }"
10751 : " if (call) g();"
10752 : "}"
10753 : "for (var i = 0; i < 17; i++) wrapper(false);"
10754 : "var thrown = 0;"
10755 : "try { wrapper(true); } catch (e) { thrown = 1; };"
10756 : "thrown";
10757 :
10758 : {
10759 6 : LocalContext env(nullptr, instance_template);
10760 : // Hold on to the global object so it can be used again in another
10761 : // environment initialization.
10762 6 : global_object = env->Global();
10763 :
10764 : Local<Value> value = CompileRun("x");
10765 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10766 : value = CompileRun("f()");
10767 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10768 : value = CompileRun(script);
10769 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10770 : }
10771 :
10772 : {
10773 : // Create new environment reusing the global object.
10774 6 : LocalContext env(nullptr, instance_template, global_object);
10775 : Local<Value> value = CompileRun("x");
10776 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10777 : value = CompileRun("f()");
10778 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10779 : value = CompileRun(script);
10780 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10781 6 : }
10782 6 : }
10783 :
10784 28343 : THREADED_TEST(ObjectGetOwnPropertyNames) {
10785 6 : LocalContext context;
10786 6 : v8::Isolate* isolate = context->GetIsolate();
10787 12 : v8::HandleScope handle_scope(isolate);
10788 :
10789 : v8::Local<v8::Object> value = v8::Local<v8::Object>::Cast(
10790 6 : v8::StringObject::New(CcTest::isolate(), v8_str("test")));
10791 : v8::Local<v8::Array> properties;
10792 :
10793 12 : CHECK(value
10794 : ->GetOwnPropertyNames(context.local(),
10795 : static_cast<v8::PropertyFilter>(
10796 : v8::PropertyFilter::ALL_PROPERTIES |
10797 : v8::PropertyFilter::SKIP_SYMBOLS),
10798 : v8::KeyConversionMode::kKeepNumbers)
10799 : .ToLocal(&properties));
10800 6 : CHECK_EQ(5u, properties->Length());
10801 : v8::Local<v8::Value> property;
10802 18 : CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10803 : property->IsString());
10804 18 : CHECK(property.As<v8::String>()
10805 : ->Equals(context.local(), v8_str("length"))
10806 : .FromMaybe(false));
10807 24 : for (int i = 0; i < 4; ++i) {
10808 : v8::Local<v8::Value> property;
10809 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10810 : property->IsInt32());
10811 24 : CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10812 : }
10813 :
10814 12 : CHECK(value
10815 : ->GetOwnPropertyNames(context.local(),
10816 : v8::PropertyFilter::ONLY_ENUMERABLE,
10817 : v8::KeyConversionMode::kKeepNumbers)
10818 : .ToLocal(&properties));
10819 : v8::Local<v8::Array> number_properties;
10820 12 : CHECK(value
10821 : ->GetOwnPropertyNames(context.local(),
10822 : v8::PropertyFilter::ONLY_ENUMERABLE,
10823 : v8::KeyConversionMode::kConvertToString)
10824 : .ToLocal(&number_properties));
10825 6 : CHECK_EQ(4u, properties->Length());
10826 24 : for (int i = 0; i < 4; ++i) {
10827 : v8::Local<v8::Value> property_index;
10828 : v8::Local<v8::Value> property_name;
10829 :
10830 48 : CHECK(number_properties->Get(context.local(), i).ToLocal(&property_name));
10831 24 : CHECK(property_name->IsString());
10832 :
10833 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property_index));
10834 24 : CHECK(property_index->IsInt32());
10835 :
10836 24 : CHECK_EQ(property_index.As<v8::Int32>()->Value(), i);
10837 48 : CHECK_EQ(property_name->ToNumber(context.local())
10838 : .ToLocalChecked()
10839 : .As<v8::Int32>()
10840 : ->Value(),
10841 : i);
10842 : }
10843 :
10844 6 : value = value->GetPrototype().As<v8::Object>();
10845 12 : CHECK(value
10846 : ->GetOwnPropertyNames(context.local(),
10847 : static_cast<v8::PropertyFilter>(
10848 : v8::PropertyFilter::ALL_PROPERTIES |
10849 : v8::PropertyFilter::SKIP_SYMBOLS))
10850 : .ToLocal(&properties));
10851 : bool concat_found = false;
10852 : bool starts_with_found = false;
10853 288 : for (uint32_t i = 0; i < properties->Length(); ++i) {
10854 : v8::Local<v8::Value> property;
10855 576 : CHECK(properties->Get(context.local(), i).ToLocal(&property));
10856 288 : if (!property->IsString()) continue;
10857 288 : if (!concat_found)
10858 : concat_found = property.As<v8::String>()
10859 180 : ->Equals(context.local(), v8_str("concat"))
10860 120 : .FromMaybe(false);
10861 288 : if (!starts_with_found)
10862 : starts_with_found = property.As<v8::String>()
10863 648 : ->Equals(context.local(), v8_str("startsWith"))
10864 432 : .FromMaybe(false);
10865 : }
10866 12 : CHECK(concat_found && starts_with_found);
10867 6 : }
10868 :
10869 28343 : THREADED_TEST(CallKnownGlobalReceiver) {
10870 6 : v8::Isolate* isolate = CcTest::isolate();
10871 6 : v8::HandleScope handle_scope(isolate);
10872 :
10873 : Local<Value> global_object;
10874 :
10875 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10876 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10877 :
10878 : // The script to check that we leave global object not
10879 : // global object proxy on stack when we deoptimize from inside
10880 : // arguments evaluation.
10881 : // To provoke error we need to both force deoptimization
10882 : // from arguments evaluation and to force CallIC to take
10883 : // CallIC_Miss code path that can't cope with global proxy.
10884 : const char* script =
10885 : "function bar(x, y) { try { } finally { } }"
10886 : "function baz(x) { try { } finally { } }"
10887 : "function bom(x) { try { } finally { } }"
10888 : "function foo(x) { bar([x], bom(2)); }"
10889 : "for (var i = 0; i < 10000; i++) foo(1);"
10890 : "foo";
10891 :
10892 : Local<Value> foo;
10893 : {
10894 6 : LocalContext env(nullptr, instance_template);
10895 : // Hold on to the global object so it can be used again in another
10896 : // environment initialization.
10897 6 : global_object = env->Global();
10898 6 : foo = CompileRun(script);
10899 : }
10900 :
10901 : {
10902 : // Create new environment reusing the global object.
10903 6 : LocalContext env(nullptr, instance_template, global_object);
10904 30 : CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10905 6 : CompileRun("foo()");
10906 6 : }
10907 6 : }
10908 :
10909 :
10910 6 : static void ShadowFunctionCallback(
10911 6 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10912 6 : ApiTestFuzzer::Fuzz();
10913 6 : args.GetReturnValue().Set(v8_num(42));
10914 6 : }
10915 :
10916 :
10917 : static int shadow_y;
10918 : static int shadow_y_setter_call_count;
10919 : static int shadow_y_getter_call_count;
10920 :
10921 :
10922 6 : static void ShadowYSetter(Local<String>,
10923 : Local<Value>,
10924 : const v8::PropertyCallbackInfo<void>&) {
10925 6 : shadow_y_setter_call_count++;
10926 6 : shadow_y = 42;
10927 6 : }
10928 :
10929 :
10930 6 : static void ShadowYGetter(Local<String> name,
10931 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10932 6 : ApiTestFuzzer::Fuzz();
10933 6 : shadow_y_getter_call_count++;
10934 6 : info.GetReturnValue().Set(v8_num(shadow_y));
10935 6 : }
10936 :
10937 :
10938 0 : static void ShadowIndexedGet(uint32_t index,
10939 : const v8::PropertyCallbackInfo<v8::Value>&) {
10940 0 : }
10941 :
10942 :
10943 30 : static void ShadowNamedGet(Local<Name> key,
10944 30 : const v8::PropertyCallbackInfo<v8::Value>&) {}
10945 :
10946 :
10947 28343 : THREADED_TEST(ShadowObject) {
10948 6 : shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10949 6 : v8::Isolate* isolate = CcTest::isolate();
10950 6 : v8::HandleScope handle_scope(isolate);
10951 :
10952 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10953 12 : LocalContext context(nullptr, global_template);
10954 :
10955 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10956 : t->InstanceTemplate()->SetHandler(
10957 12 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10958 : t->InstanceTemplate()->SetHandler(
10959 12 : v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10960 6 : Local<ObjectTemplate> proto = t->PrototypeTemplate();
10961 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10962 :
10963 : proto->Set(v8_str("f"),
10964 : v8::FunctionTemplate::New(isolate,
10965 : ShadowFunctionCallback,
10966 18 : Local<Value>()));
10967 18 : proto->Set(v8_str("x"), v8_num(12));
10968 :
10969 12 : instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10970 :
10971 6 : Local<Value> o = t->GetFunction(context.local())
10972 6 : .ToLocalChecked()
10973 6 : ->NewInstance(context.local())
10974 : .ToLocalChecked();
10975 30 : CHECK(context->Global()
10976 : ->Set(context.local(), v8_str("__proto__"), o)
10977 : .FromJust());
10978 :
10979 : Local<Value> value =
10980 : CompileRun("this.propertyIsEnumerable(0)");
10981 6 : CHECK(value->IsBoolean());
10982 6 : CHECK(!value->BooleanValue(isolate));
10983 :
10984 : value = CompileRun("x");
10985 12 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10986 :
10987 : value = CompileRun("f()");
10988 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10989 :
10990 : CompileRun("y = 43");
10991 6 : CHECK_EQ(1, shadow_y_setter_call_count);
10992 : value = CompileRun("y");
10993 6 : CHECK_EQ(1, shadow_y_getter_call_count);
10994 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10995 6 : }
10996 :
10997 :
10998 28343 : THREADED_TEST(HiddenPrototype) {
10999 6 : LocalContext context;
11000 6 : v8::Isolate* isolate = context->GetIsolate();
11001 12 : v8::HandleScope handle_scope(isolate);
11002 :
11003 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11004 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11005 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11006 6 : t1->SetHiddenPrototype(true);
11007 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11008 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11009 6 : t2->SetHiddenPrototype(true);
11010 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11011 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11012 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11013 :
11014 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
11015 6 : .ToLocalChecked()
11016 6 : ->NewInstance(context.local())
11017 : .ToLocalChecked();
11018 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11019 6 : .ToLocalChecked()
11020 6 : ->NewInstance(context.local())
11021 : .ToLocalChecked();
11022 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11023 6 : .ToLocalChecked()
11024 6 : ->NewInstance(context.local())
11025 : .ToLocalChecked();
11026 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11027 6 : .ToLocalChecked()
11028 6 : ->NewInstance(context.local())
11029 : .ToLocalChecked();
11030 :
11031 : // Setting the prototype on an object skips hidden prototypes.
11032 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11033 : .ToLocalChecked()
11034 : ->Int32Value(context.local())
11035 : .FromJust());
11036 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o1).FromJust());
11037 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11038 : .ToLocalChecked()
11039 : ->Int32Value(context.local())
11040 : .FromJust());
11041 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11042 : .ToLocalChecked()
11043 : ->Int32Value(context.local())
11044 : .FromJust());
11045 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o2).FromJust());
11046 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11047 : .ToLocalChecked()
11048 : ->Int32Value(context.local())
11049 : .FromJust());
11050 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11051 : .ToLocalChecked()
11052 : ->Int32Value(context.local())
11053 : .FromJust());
11054 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11055 : .ToLocalChecked()
11056 : ->Int32Value(context.local())
11057 : .FromJust());
11058 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o3).FromJust());
11059 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11060 : .ToLocalChecked()
11061 : ->Int32Value(context.local())
11062 : .FromJust());
11063 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11064 : .ToLocalChecked()
11065 : ->Int32Value(context.local())
11066 : .FromJust());
11067 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11068 : .ToLocalChecked()
11069 : ->Int32Value(context.local())
11070 : .FromJust());
11071 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
11072 : .ToLocalChecked()
11073 : ->Int32Value(context.local())
11074 : .FromJust());
11075 :
11076 : // Getting the prototype of o0 should get the first visible one
11077 : // which is o3. Therefore, z should not be defined on the prototype
11078 : // object.
11079 : Local<Value> proto =
11080 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
11081 6 : CHECK(proto->IsObject());
11082 18 : CHECK(proto.As<v8::Object>()
11083 : ->Get(context.local(), v8_str("z"))
11084 : .ToLocalChecked()
11085 6 : ->IsUndefined());
11086 6 : }
11087 :
11088 :
11089 28343 : THREADED_TEST(HiddenPrototypeSet) {
11090 6 : LocalContext context;
11091 6 : v8::Isolate* isolate = context->GetIsolate();
11092 12 : v8::HandleScope handle_scope(isolate);
11093 :
11094 6 : Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
11095 6 : Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
11096 6 : ht->SetHiddenPrototype(true);
11097 6 : Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
11098 24 : ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11099 :
11100 6 : Local<v8::Object> o = ot->GetFunction(context.local())
11101 6 : .ToLocalChecked()
11102 6 : ->NewInstance(context.local())
11103 : .ToLocalChecked();
11104 6 : Local<v8::Object> h = ht->GetFunction(context.local())
11105 6 : .ToLocalChecked()
11106 6 : ->NewInstance(context.local())
11107 : .ToLocalChecked();
11108 6 : Local<v8::Object> p = pt->GetFunction(context.local())
11109 6 : .ToLocalChecked()
11110 6 : ->NewInstance(context.local())
11111 : .ToLocalChecked();
11112 18 : CHECK(o->Set(context.local(), v8_str("__proto__"), h).FromJust());
11113 18 : CHECK(h->Set(context.local(), v8_str("__proto__"), p).FromJust());
11114 :
11115 : // Setting a property that exists on the hidden prototype goes there.
11116 18 : CHECK(o->Set(context.local(), v8_str("x"), v8_num(7)).FromJust());
11117 24 : CHECK_EQ(7, o->Get(context.local(), v8_str("x"))
11118 : .ToLocalChecked()
11119 : ->Int32Value(context.local())
11120 : .FromJust());
11121 24 : CHECK_EQ(7, h->Get(context.local(), v8_str("x"))
11122 : .ToLocalChecked()
11123 : ->Int32Value(context.local())
11124 : .FromJust());
11125 18 : CHECK(p->Get(context.local(), v8_str("x")).ToLocalChecked()->IsUndefined());
11126 :
11127 : // Setting a new property should not be forwarded to the hidden prototype.
11128 18 : CHECK(o->Set(context.local(), v8_str("y"), v8_num(6)).FromJust());
11129 24 : CHECK_EQ(6, o->Get(context.local(), v8_str("y"))
11130 : .ToLocalChecked()
11131 : ->Int32Value(context.local())
11132 : .FromJust());
11133 18 : CHECK(h->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
11134 18 : CHECK(p->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
11135 :
11136 : // Setting a property that only exists on a prototype of the hidden prototype
11137 : // is treated normally again.
11138 18 : CHECK(p->Set(context.local(), v8_str("z"), v8_num(8)).FromJust());
11139 24 : CHECK_EQ(8, o->Get(context.local(), v8_str("z"))
11140 : .ToLocalChecked()
11141 : ->Int32Value(context.local())
11142 : .FromJust());
11143 24 : CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
11144 : .ToLocalChecked()
11145 : ->Int32Value(context.local())
11146 : .FromJust());
11147 24 : CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
11148 : .ToLocalChecked()
11149 : ->Int32Value(context.local())
11150 : .FromJust());
11151 18 : CHECK(o->Set(context.local(), v8_str("z"), v8_num(9)).FromJust());
11152 24 : CHECK_EQ(9, o->Get(context.local(), v8_str("z"))
11153 : .ToLocalChecked()
11154 : ->Int32Value(context.local())
11155 : .FromJust());
11156 24 : CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
11157 : .ToLocalChecked()
11158 : ->Int32Value(context.local())
11159 : .FromJust());
11160 24 : CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
11161 : .ToLocalChecked()
11162 : ->Int32Value(context.local())
11163 6 : .FromJust());
11164 6 : }
11165 :
11166 :
11167 : // Regression test for issue 2457.
11168 28343 : THREADED_TEST(HiddenPrototypeIdentityHash) {
11169 6 : LocalContext context;
11170 12 : v8::HandleScope handle_scope(context->GetIsolate());
11171 :
11172 6 : Local<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
11173 6 : t->SetHiddenPrototype(true);
11174 24 : t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
11175 6 : Local<Object> p = t->GetFunction(context.local())
11176 6 : .ToLocalChecked()
11177 6 : ->NewInstance(context.local())
11178 : .ToLocalChecked();
11179 6 : Local<Object> o = Object::New(context->GetIsolate());
11180 12 : CHECK(o->SetPrototype(context.local(), p).FromJust());
11181 :
11182 6 : int hash = o->GetIdentityHash();
11183 : USE(hash);
11184 18 : CHECK(o->Set(context.local(), v8_str("foo"), v8_num(42)).FromJust());
11185 12 : CHECK_EQ(hash, o->GetIdentityHash());
11186 6 : }
11187 :
11188 :
11189 28343 : THREADED_TEST(SetPrototype) {
11190 6 : LocalContext context;
11191 6 : v8::Isolate* isolate = context->GetIsolate();
11192 12 : v8::HandleScope handle_scope(isolate);
11193 :
11194 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11195 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11196 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11197 6 : t1->SetHiddenPrototype(true);
11198 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11199 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11200 6 : t2->SetHiddenPrototype(true);
11201 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11202 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11203 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11204 :
11205 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
11206 6 : .ToLocalChecked()
11207 6 : ->NewInstance(context.local())
11208 : .ToLocalChecked();
11209 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11210 6 : .ToLocalChecked()
11211 6 : ->NewInstance(context.local())
11212 : .ToLocalChecked();
11213 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11214 6 : .ToLocalChecked()
11215 6 : ->NewInstance(context.local())
11216 : .ToLocalChecked();
11217 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11218 6 : .ToLocalChecked()
11219 6 : ->NewInstance(context.local())
11220 : .ToLocalChecked();
11221 :
11222 : // Setting the prototype on an object does not skip hidden prototypes.
11223 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11224 : .ToLocalChecked()
11225 : ->Int32Value(context.local())
11226 : .FromJust());
11227 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11228 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11229 : .ToLocalChecked()
11230 : ->Int32Value(context.local())
11231 : .FromJust());
11232 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11233 : .ToLocalChecked()
11234 : ->Int32Value(context.local())
11235 : .FromJust());
11236 12 : CHECK(o1->SetPrototype(context.local(), o2).FromJust());
11237 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11238 : .ToLocalChecked()
11239 : ->Int32Value(context.local())
11240 : .FromJust());
11241 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11242 : .ToLocalChecked()
11243 : ->Int32Value(context.local())
11244 : .FromJust());
11245 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11246 : .ToLocalChecked()
11247 : ->Int32Value(context.local())
11248 : .FromJust());
11249 12 : CHECK(o2->SetPrototype(context.local(), o3).FromJust());
11250 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11251 : .ToLocalChecked()
11252 : ->Int32Value(context.local())
11253 : .FromJust());
11254 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11255 : .ToLocalChecked()
11256 : ->Int32Value(context.local())
11257 : .FromJust());
11258 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11259 : .ToLocalChecked()
11260 : ->Int32Value(context.local())
11261 : .FromJust());
11262 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
11263 : .ToLocalChecked()
11264 : ->Int32Value(context.local())
11265 : .FromJust());
11266 :
11267 : // Getting the prototype of o0 should get the first visible one
11268 : // which is o3. Therefore, z should not be defined on the prototype
11269 : // object.
11270 : Local<Value> proto =
11271 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
11272 6 : CHECK(proto->IsObject());
11273 12 : CHECK(proto.As<v8::Object>()->Equals(context.local(), o3).FromJust());
11274 :
11275 : // However, Object::GetPrototype ignores hidden prototype.
11276 6 : Local<Value> proto0 = o0->GetPrototype();
11277 6 : CHECK(proto0->IsObject());
11278 12 : CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11279 :
11280 6 : Local<Value> proto1 = o1->GetPrototype();
11281 6 : CHECK(proto1->IsObject());
11282 12 : CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
11283 :
11284 6 : Local<Value> proto2 = o2->GetPrototype();
11285 6 : CHECK(proto2->IsObject());
11286 18 : CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
11287 6 : }
11288 :
11289 :
11290 : // Getting property names of an object with a prototype chain that
11291 : // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11292 : // crash the runtime.
11293 28343 : THREADED_TEST(Regress91517) {
11294 6 : i::FLAG_allow_natives_syntax = true;
11295 6 : LocalContext context;
11296 6 : v8::Isolate* isolate = context->GetIsolate();
11297 12 : v8::HandleScope handle_scope(isolate);
11298 :
11299 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11300 6 : t1->SetHiddenPrototype(true);
11301 24 : t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11302 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11303 6 : t2->SetHiddenPrototype(true);
11304 24 : t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11305 12 : t2->InstanceTemplate()->Set(v8_str("objects"),
11306 24 : v8::ObjectTemplate::New(isolate));
11307 24 : t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11308 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11309 6 : t3->SetHiddenPrototype(true);
11310 24 : t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11311 6 : Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11312 24 : t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11313 :
11314 : // Force dictionary-based properties.
11315 : i::ScopedVector<char> name_buf(1024);
11316 6006 : for (int i = 1; i <= 1000; i++) {
11317 6000 : i::SNPrintF(name_buf, "sdf%d", i);
11318 24000 : t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11319 : }
11320 :
11321 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11322 6 : .ToLocalChecked()
11323 6 : ->NewInstance(context.local())
11324 : .ToLocalChecked();
11325 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11326 6 : .ToLocalChecked()
11327 6 : ->NewInstance(context.local())
11328 : .ToLocalChecked();
11329 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11330 6 : .ToLocalChecked()
11331 6 : ->NewInstance(context.local())
11332 : .ToLocalChecked();
11333 6 : Local<v8::Object> o4 = t4->GetFunction(context.local())
11334 6 : .ToLocalChecked()
11335 6 : ->NewInstance(context.local())
11336 : .ToLocalChecked();
11337 :
11338 : // Create prototype chain of hidden prototypes.
11339 12 : CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11340 12 : CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11341 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11342 :
11343 : // Call the runtime version of GetOwnPropertyNames() on the natively
11344 : // created object through JavaScript.
11345 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11346 : // PROPERTY_FILTER_NONE = 0
11347 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11348 :
11349 6 : ExpectInt32("names.length", 1006);
11350 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11351 : ExpectTrue("names.indexOf(\"boo\") >= 0");
11352 : ExpectTrue("names.indexOf(\"foo\") >= 0");
11353 : ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11354 : ExpectTrue("names.indexOf(\"objects\") >= 0");
11355 : ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11356 6 : ExpectFalse("names[1005] == undefined");
11357 6 : }
11358 :
11359 :
11360 : // Getting property names of an object with a hidden and inherited
11361 : // prototype should not duplicate the accessor properties inherited.
11362 28343 : THREADED_TEST(Regress269562) {
11363 6 : i::FLAG_allow_natives_syntax = true;
11364 6 : LocalContext context;
11365 12 : v8::HandleScope handle_scope(context->GetIsolate());
11366 :
11367 : Local<v8::FunctionTemplate> t1 =
11368 6 : v8::FunctionTemplate::New(context->GetIsolate());
11369 6 : t1->SetHiddenPrototype(true);
11370 :
11371 6 : Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11372 : i1->SetAccessor(v8_str("foo"),
11373 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11374 : i1->SetAccessor(v8_str("bar"),
11375 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11376 : i1->SetAccessor(v8_str("baz"),
11377 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11378 18 : i1->Set(v8_str("n1"), v8_num(1));
11379 18 : i1->Set(v8_str("n2"), v8_num(2));
11380 :
11381 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11382 6 : .ToLocalChecked()
11383 6 : ->NewInstance(context.local())
11384 : .ToLocalChecked();
11385 : Local<v8::FunctionTemplate> t2 =
11386 6 : v8::FunctionTemplate::New(context->GetIsolate());
11387 6 : t2->SetHiddenPrototype(true);
11388 :
11389 : // Inherit from t1 and mark prototype as hidden.
11390 6 : t2->Inherit(t1);
11391 24 : t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11392 :
11393 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11394 6 : .ToLocalChecked()
11395 6 : ->NewInstance(context.local())
11396 : .ToLocalChecked();
11397 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11398 :
11399 : v8::Local<v8::Symbol> sym =
11400 12 : v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11401 18 : CHECK(o1->Set(context.local(), sym, v8_num(3)).FromJust());
11402 : o1->SetPrivate(context.local(),
11403 : v8::Private::New(context->GetIsolate(), v8_str("h1")),
11404 24 : v8::Integer::New(context->GetIsolate(), 2013))
11405 12 : .FromJust();
11406 :
11407 : // Call the runtime version of GetOwnPropertyNames() on
11408 : // the natively created object through JavaScript.
11409 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o2).FromJust());
11410 30 : CHECK(context->Global()->Set(context.local(), v8_str("sym"), sym).FromJust());
11411 : // PROPERTY_FILTER_NONE = 0
11412 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11413 :
11414 6 : ExpectInt32("names.length", 7);
11415 : ExpectTrue("names.indexOf(\"foo\") >= 0");
11416 : ExpectTrue("names.indexOf(\"bar\") >= 0");
11417 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11418 : ExpectTrue("names.indexOf(\"n1\") >= 0");
11419 : ExpectTrue("names.indexOf(\"n2\") >= 0");
11420 : ExpectTrue("names.indexOf(sym) >= 0");
11421 6 : ExpectTrue("names.indexOf(\"mine\") >= 0");
11422 6 : }
11423 :
11424 :
11425 28343 : THREADED_TEST(FunctionReadOnlyPrototype) {
11426 6 : LocalContext context;
11427 6 : v8::Isolate* isolate = context->GetIsolate();
11428 12 : v8::HandleScope handle_scope(isolate);
11429 :
11430 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11431 24 : t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11432 6 : t1->ReadOnlyPrototype();
11433 36 : CHECK(context->Global()
11434 : ->Set(context.local(), v8_str("func1"),
11435 : t1->GetFunction(context.local()).ToLocalChecked())
11436 : .FromJust());
11437 : // Configured value of ReadOnly flag.
11438 6 : CHECK(
11439 : CompileRun(
11440 : "(function() {"
11441 : " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11442 : " return (descriptor['writable'] == false);"
11443 : "})()")
11444 : ->BooleanValue(isolate));
11445 18 : CHECK_EQ(
11446 : 42,
11447 : CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11448 18 : CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11449 : ->Int32Value(context.local())
11450 : .FromJust());
11451 :
11452 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11453 24 : t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11454 36 : CHECK(context->Global()
11455 : ->Set(context.local(), v8_str("func2"),
11456 : t2->GetFunction(context.local()).ToLocalChecked())
11457 : .FromJust());
11458 : // Default value of ReadOnly flag.
11459 6 : CHECK(
11460 : CompileRun(
11461 : "(function() {"
11462 : " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11463 : " return (descriptor['writable'] == true);"
11464 : "})()")
11465 : ->BooleanValue(isolate));
11466 18 : CHECK_EQ(
11467 : 42,
11468 6 : CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11469 6 : }
11470 :
11471 :
11472 28343 : THREADED_TEST(SetPrototypeThrows) {
11473 6 : LocalContext context;
11474 6 : v8::Isolate* isolate = context->GetIsolate();
11475 12 : v8::HandleScope handle_scope(isolate);
11476 :
11477 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11478 :
11479 6 : Local<v8::Object> o0 = t->GetFunction(context.local())
11480 6 : .ToLocalChecked()
11481 6 : ->NewInstance(context.local())
11482 : .ToLocalChecked();
11483 6 : Local<v8::Object> o1 = t->GetFunction(context.local())
11484 6 : .ToLocalChecked()
11485 6 : ->NewInstance(context.local())
11486 : .ToLocalChecked();
11487 :
11488 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11489 : // If setting the prototype leads to the cycle, SetPrototype should
11490 : // return false and keep VM in sane state.
11491 12 : v8::TryCatch try_catch(isolate);
11492 12 : CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11493 6 : CHECK(!try_catch.HasCaught());
11494 6 : CHECK(!CcTest::i_isolate()->has_pending_exception());
11495 :
11496 18 : CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11497 : ->Int32Value(context.local())
11498 6 : .FromJust());
11499 6 : }
11500 :
11501 :
11502 28343 : THREADED_TEST(FunctionRemovePrototype) {
11503 6 : LocalContext context;
11504 6 : v8::Isolate* isolate = context->GetIsolate();
11505 12 : v8::HandleScope handle_scope(isolate);
11506 :
11507 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11508 6 : t1->RemovePrototype();
11509 6 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11510 6 : CHECK(!fun->IsConstructor());
11511 30 : CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11512 6 : CHECK(!CompileRun("'prototype' in fun")->BooleanValue(isolate));
11513 :
11514 12 : v8::TryCatch try_catch(isolate);
11515 : CompileRun("new fun()");
11516 6 : CHECK(try_catch.HasCaught());
11517 :
11518 6 : try_catch.Reset();
11519 12 : CHECK(fun->NewInstance(context.local()).IsEmpty());
11520 12 : CHECK(try_catch.HasCaught());
11521 6 : }
11522 :
11523 :
11524 28343 : THREADED_TEST(GetterSetterExceptions) {
11525 6 : LocalContext context;
11526 6 : v8::Isolate* isolate = context->GetIsolate();
11527 12 : v8::HandleScope handle_scope(isolate);
11528 : CompileRun(
11529 : "function Foo() { };"
11530 : "function Throw() { throw 5; };"
11531 : "var x = { };"
11532 : "x.__defineSetter__('set', Throw);"
11533 : "x.__defineGetter__('get', Throw);");
11534 : Local<v8::Object> x = Local<v8::Object>::Cast(
11535 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11536 12 : v8::TryCatch try_catch(isolate);
11537 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11538 : .IsNothing());
11539 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11540 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11541 : .IsNothing());
11542 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11543 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11544 : .IsNothing());
11545 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11546 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11547 : .IsNothing());
11548 24 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11549 6 : }
11550 :
11551 :
11552 28343 : THREADED_TEST(Constructor) {
11553 6 : LocalContext context;
11554 6 : v8::Isolate* isolate = context->GetIsolate();
11555 12 : v8::HandleScope handle_scope(isolate);
11556 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11557 6 : templ->SetClassName(v8_str("Fun"));
11558 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11559 30 : CHECK(
11560 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11561 6 : Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11562 : i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11563 12 : CHECK(obj->IsJSObject());
11564 : Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11565 12 : CHECK(value->BooleanValue(isolate));
11566 6 : }
11567 :
11568 :
11569 28343 : THREADED_TEST(FunctionDescriptorException) {
11570 6 : LocalContext context;
11571 6 : v8::Isolate* isolate = context->GetIsolate();
11572 12 : v8::HandleScope handle_scope(isolate);
11573 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11574 6 : templ->SetClassName(v8_str("Fun"));
11575 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11576 30 : CHECK(
11577 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11578 : Local<Value> value = CompileRun(
11579 : "function test() {"
11580 : " try {"
11581 : " (new Fun()).blah()"
11582 : " } catch (e) {"
11583 : " var str = String(e);"
11584 : // " if (str.indexOf('TypeError') == -1) return 1;"
11585 : // " if (str.indexOf('[object Fun]') != -1) return 2;"
11586 : // " if (str.indexOf('#<Fun>') == -1) return 3;"
11587 : " return 0;"
11588 : " }"
11589 : " return 4;"
11590 : "}"
11591 : "test();");
11592 18 : CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11593 6 : }
11594 :
11595 :
11596 28343 : THREADED_TEST(EvalAliasedDynamic) {
11597 6 : LocalContext current;
11598 12 : v8::HandleScope scope(current->GetIsolate());
11599 :
11600 : // Tests where aliased eval can only be resolved dynamically.
11601 : Local<Script> script = v8_compile(
11602 : "function f(x) { "
11603 : " var foo = 2;"
11604 : " with (x) { return eval('foo'); }"
11605 : "}"
11606 : "foo = 0;"
11607 : "result1 = f(new Object());"
11608 : "result2 = f(this);"
11609 : "var x = new Object();"
11610 : "x.eval = function(x) { return 1; };"
11611 : "result3 = f(x);");
11612 6 : script->Run(current.local()).ToLocalChecked();
11613 36 : CHECK_EQ(2, current->Global()
11614 : ->Get(current.local(), v8_str("result1"))
11615 : .ToLocalChecked()
11616 : ->Int32Value(current.local())
11617 : .FromJust());
11618 36 : CHECK_EQ(0, current->Global()
11619 : ->Get(current.local(), v8_str("result2"))
11620 : .ToLocalChecked()
11621 : ->Int32Value(current.local())
11622 : .FromJust());
11623 36 : CHECK_EQ(1, current->Global()
11624 : ->Get(current.local(), v8_str("result3"))
11625 : .ToLocalChecked()
11626 : ->Int32Value(current.local())
11627 : .FromJust());
11628 :
11629 12 : v8::TryCatch try_catch(current->GetIsolate());
11630 : script = v8_compile(
11631 : "function f(x) { "
11632 : " var bar = 2;"
11633 : " with (x) { return eval('bar'); }"
11634 : "}"
11635 : "result4 = f(this)");
11636 6 : script->Run(current.local()).ToLocalChecked();
11637 6 : CHECK(!try_catch.HasCaught());
11638 36 : CHECK_EQ(2, current->Global()
11639 : ->Get(current.local(), v8_str("result4"))
11640 : .ToLocalChecked()
11641 : ->Int32Value(current.local())
11642 : .FromJust());
11643 :
11644 12 : try_catch.Reset();
11645 6 : }
11646 :
11647 :
11648 28343 : THREADED_TEST(CrossEval) {
11649 6 : v8::HandleScope scope(CcTest::isolate());
11650 12 : LocalContext other;
11651 12 : LocalContext current;
11652 :
11653 6 : Local<String> token = v8_str("<security token>");
11654 6 : other->SetSecurityToken(token);
11655 6 : current->SetSecurityToken(token);
11656 :
11657 : // Set up reference from current to other.
11658 36 : CHECK(current->Global()
11659 : ->Set(current.local(), v8_str("other"), other->Global())
11660 : .FromJust());
11661 :
11662 : // Check that new variables are introduced in other context.
11663 : Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11664 6 : script->Run(current.local()).ToLocalChecked();
11665 : Local<Value> foo =
11666 30 : other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11667 12 : CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11668 30 : CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11669 :
11670 : // Check that writing to non-existing properties introduces them in
11671 : // the other context.
11672 : script = v8_compile("other.eval('na = 1234')");
11673 6 : script->Run(current.local()).ToLocalChecked();
11674 36 : CHECK_EQ(1234, other->Global()
11675 : ->Get(current.local(), v8_str("na"))
11676 : .ToLocalChecked()
11677 : ->Int32Value(other.local())
11678 : .FromJust());
11679 30 : CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11680 :
11681 : // Check that global variables in current context are not visible in other
11682 : // context.
11683 12 : v8::TryCatch try_catch(CcTest::isolate());
11684 : script = v8_compile("var bar = 42; other.eval('bar');");
11685 12 : CHECK(script->Run(current.local()).IsEmpty());
11686 6 : CHECK(try_catch.HasCaught());
11687 6 : try_catch.Reset();
11688 :
11689 : // Check that local variables in current context are not visible in other
11690 : // context.
11691 : script = v8_compile(
11692 : "(function() { "
11693 : " var baz = 87;"
11694 : " return other.eval('baz');"
11695 : "})();");
11696 12 : CHECK(script->Run(current.local()).IsEmpty());
11697 6 : CHECK(try_catch.HasCaught());
11698 6 : try_catch.Reset();
11699 :
11700 : // Check that global variables in the other environment are visible
11701 : // when evaluting code.
11702 30 : CHECK(other->Global()
11703 : ->Set(other.local(), v8_str("bis"), v8_num(1234))
11704 : .FromJust());
11705 : script = v8_compile("other.eval('bis')");
11706 18 : CHECK_EQ(1234, script->Run(current.local())
11707 : .ToLocalChecked()
11708 : ->Int32Value(current.local())
11709 : .FromJust());
11710 6 : CHECK(!try_catch.HasCaught());
11711 :
11712 : // Check that the 'this' pointer points to the global object evaluating
11713 : // code.
11714 36 : CHECK(other->Global()
11715 : ->Set(current.local(), v8_str("t"), other->Global())
11716 : .FromJust());
11717 : script = v8_compile("other.eval('this == t')");
11718 6 : Local<Value> result = script->Run(current.local()).ToLocalChecked();
11719 6 : CHECK(result->IsTrue());
11720 6 : CHECK(!try_catch.HasCaught());
11721 :
11722 : // Check that variables introduced in with-statement are not visible in
11723 : // other context.
11724 : script = v8_compile("with({x:2}){other.eval('x')}");
11725 12 : CHECK(script->Run(current.local()).IsEmpty());
11726 6 : CHECK(try_catch.HasCaught());
11727 6 : try_catch.Reset();
11728 :
11729 : // Check that you cannot use 'eval.call' with another object than the
11730 : // current global object.
11731 : script = v8_compile("other.y = 1; eval.call(other, 'y')");
11732 12 : CHECK(script->Run(current.local()).IsEmpty());
11733 12 : CHECK(try_catch.HasCaught());
11734 6 : }
11735 :
11736 :
11737 : // Test that calling eval in a context which has been detached from
11738 : // its global proxy works.
11739 28343 : THREADED_TEST(EvalInDetachedGlobal) {
11740 6 : v8::Isolate* isolate = CcTest::isolate();
11741 6 : v8::HandleScope scope(isolate);
11742 :
11743 6 : v8::Local<Context> context0 = Context::New(isolate);
11744 6 : v8::Local<Context> context1 = Context::New(isolate);
11745 6 : Local<String> token = v8_str("<security token>");
11746 6 : context0->SetSecurityToken(token);
11747 6 : context1->SetSecurityToken(token);
11748 :
11749 : // Set up function in context0 that uses eval from context0.
11750 6 : context0->Enter();
11751 : v8::Local<v8::Value> fun = CompileRun(
11752 : "var x = 42;"
11753 : "(function() {"
11754 : " var e = eval;"
11755 : " return function(s) { return e(s); }"
11756 6 : "})()");
11757 6 : context0->Exit();
11758 :
11759 : // Put the function into context1 and call it before and after
11760 : // detaching the global. Before detaching, the call succeeds and
11761 : // after detaching undefined is returned.
11762 6 : context1->Enter();
11763 24 : CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11764 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11765 12 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11766 6 : context0->DetachGlobal();
11767 : x_value = CompileRun("fun('x')");
11768 6 : CHECK(x_value->IsUndefined());
11769 6 : context1->Exit();
11770 6 : }
11771 :
11772 :
11773 28343 : THREADED_TEST(CrossLazyLoad) {
11774 6 : v8::HandleScope scope(CcTest::isolate());
11775 12 : LocalContext other;
11776 12 : LocalContext current;
11777 :
11778 6 : Local<String> token = v8_str("<security token>");
11779 6 : other->SetSecurityToken(token);
11780 6 : current->SetSecurityToken(token);
11781 :
11782 : // Set up reference from current to other.
11783 36 : CHECK(current->Global()
11784 : ->Set(current.local(), v8_str("other"), other->Global())
11785 : .FromJust());
11786 :
11787 : // Trigger lazy loading in other context.
11788 : Local<Script> script = v8_compile("other.eval('new Date(42)')");
11789 6 : Local<Value> value = script->Run(current.local()).ToLocalChecked();
11790 18 : CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11791 6 : }
11792 :
11793 :
11794 102 : static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11795 48 : ApiTestFuzzer::Fuzz();
11796 48 : if (args.IsConstructCall()) {
11797 6 : if (args[0]->IsInt32()) {
11798 : args.GetReturnValue().Set(
11799 : v8_num(-args[0]
11800 6 : ->Int32Value(args.GetIsolate()->GetCurrentContext())
11801 18 : .FromJust()));
11802 54 : return;
11803 : }
11804 : }
11805 :
11806 : args.GetReturnValue().Set(args[0]);
11807 : }
11808 :
11809 :
11810 : // Test that a call handler can be set for objects which will allow
11811 : // non-function objects created through the API to be called as
11812 : // functions.
11813 28343 : THREADED_TEST(CallAsFunction) {
11814 6 : LocalContext context;
11815 6 : v8::Isolate* isolate = context->GetIsolate();
11816 12 : v8::HandleScope scope(isolate);
11817 :
11818 : {
11819 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11820 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11821 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11822 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11823 6 : .ToLocalChecked()
11824 6 : ->NewInstance(context.local())
11825 : .ToLocalChecked();
11826 30 : CHECK(context->Global()
11827 : ->Set(context.local(), v8_str("obj"), instance)
11828 : .FromJust());
11829 6 : v8::TryCatch try_catch(isolate);
11830 : Local<Value> value;
11831 6 : CHECK(!try_catch.HasCaught());
11832 :
11833 : value = CompileRun("obj(42)");
11834 6 : CHECK(!try_catch.HasCaught());
11835 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11836 :
11837 : value = CompileRun("(function(o){return o(49)})(obj)");
11838 6 : CHECK(!try_catch.HasCaught());
11839 12 : CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11840 :
11841 : // test special case of call as function
11842 : value = CompileRun("[obj]['0'](45)");
11843 6 : CHECK(!try_catch.HasCaught());
11844 12 : CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11845 :
11846 : value = CompileRun(
11847 : "obj.call = Function.prototype.call;"
11848 : "obj.call(null, 87)");
11849 6 : CHECK(!try_catch.HasCaught());
11850 12 : CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11851 :
11852 : // Regression tests for bug #1116356: Calling call through call/apply
11853 : // must work for non-function receivers.
11854 : const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11855 : value = CompileRun(apply_99);
11856 6 : CHECK(!try_catch.HasCaught());
11857 12 : CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11858 :
11859 : const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11860 : value = CompileRun(call_17);
11861 6 : CHECK(!try_catch.HasCaught());
11862 12 : CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11863 :
11864 : // Check that the call-as-function handler can be called through new.
11865 : value = CompileRun("new obj(43)");
11866 6 : CHECK(!try_catch.HasCaught());
11867 12 : CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11868 :
11869 : // Check that the call-as-function handler can be called through
11870 : // the API.
11871 6 : v8::Local<Value> args[] = {v8_num(28)};
11872 12 : value = instance->CallAsFunction(context.local(), instance, 1, args)
11873 6 : .ToLocalChecked();
11874 6 : CHECK(!try_catch.HasCaught());
11875 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11876 : }
11877 :
11878 : {
11879 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11880 6 : Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11881 : USE(instance_template);
11882 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11883 6 : .ToLocalChecked()
11884 6 : ->NewInstance(context.local())
11885 : .ToLocalChecked();
11886 30 : CHECK(context->Global()
11887 : ->Set(context.local(), v8_str("obj2"), instance)
11888 : .FromJust());
11889 6 : v8::TryCatch try_catch(isolate);
11890 : Local<Value> value;
11891 6 : CHECK(!try_catch.HasCaught());
11892 :
11893 : // Call an object without call-as-function handler through the JS
11894 : value = CompileRun("obj2(28)");
11895 6 : CHECK(value.IsEmpty());
11896 6 : CHECK(try_catch.HasCaught());
11897 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11898 : // TODO(verwaest): Better message
11899 6 : CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11900 6 : try_catch.Reset();
11901 :
11902 : // Call an object without call-as-function handler through the API
11903 6 : v8::Local<Value> args[] = {v8_num(28)};
11904 12 : CHECK(
11905 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11906 6 : CHECK(try_catch.HasCaught());
11907 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11908 6 : CHECK_EQ(0,
11909 : strcmp("TypeError: object is not a function", *exception_value2));
11910 12 : try_catch.Reset();
11911 : }
11912 :
11913 : {
11914 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11915 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11916 6 : instance_template->SetCallAsFunctionHandler(ThrowValue);
11917 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11918 6 : .ToLocalChecked()
11919 6 : ->NewInstance(context.local())
11920 : .ToLocalChecked();
11921 30 : CHECK(context->Global()
11922 : ->Set(context.local(), v8_str("obj3"), instance)
11923 : .FromJust());
11924 6 : v8::TryCatch try_catch(isolate);
11925 : Local<Value> value;
11926 6 : CHECK(!try_catch.HasCaught());
11927 :
11928 : // Catch the exception which is thrown by call-as-function handler
11929 : value = CompileRun("obj3(22)");
11930 6 : CHECK(try_catch.HasCaught());
11931 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11932 6 : CHECK_EQ(0, strcmp("22", *exception_value1));
11933 6 : try_catch.Reset();
11934 :
11935 6 : v8::Local<Value> args[] = {v8_num(23)};
11936 12 : CHECK(
11937 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11938 6 : CHECK(try_catch.HasCaught());
11939 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11940 6 : CHECK_EQ(0, strcmp("23", *exception_value2));
11941 12 : try_catch.Reset();
11942 : }
11943 :
11944 : {
11945 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11946 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11947 6 : instance_template->SetCallAsFunctionHandler(ReturnThis);
11948 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11949 6 : .ToLocalChecked()
11950 6 : ->NewInstance(context.local())
11951 : .ToLocalChecked();
11952 :
11953 : Local<v8::Value> a1 =
11954 : instance
11955 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11956 12 : nullptr)
11957 6 : .ToLocalChecked();
11958 6 : CHECK(a1->StrictEquals(instance));
11959 : Local<v8::Value> a2 =
11960 12 : instance->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11961 6 : .ToLocalChecked();
11962 6 : CHECK(a2->StrictEquals(instance));
11963 : Local<v8::Value> a3 =
11964 6 : instance->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11965 6 : .ToLocalChecked();
11966 6 : CHECK(a3->StrictEquals(instance));
11967 : Local<v8::Value> a4 =
11968 18 : instance->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11969 6 : .ToLocalChecked();
11970 6 : CHECK(a4->StrictEquals(instance));
11971 : Local<v8::Value> a5 =
11972 12 : instance->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11973 6 : .ToLocalChecked();
11974 6 : CHECK(a5->StrictEquals(instance));
11975 : }
11976 :
11977 : {
11978 : CompileRun(
11979 : "function ReturnThisSloppy() {"
11980 : " return this;"
11981 : "}"
11982 : "function ReturnThisStrict() {"
11983 : " 'use strict';"
11984 : " return this;"
11985 : "}");
11986 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11987 : context->Global()
11988 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
11989 6 : .ToLocalChecked());
11990 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
11991 : context->Global()
11992 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
11993 6 : .ToLocalChecked());
11994 :
11995 : Local<v8::Value> a1 =
11996 : ReturnThisSloppy
11997 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11998 12 : nullptr)
11999 6 : .ToLocalChecked();
12000 12 : CHECK(a1->StrictEquals(context->Global()));
12001 : Local<v8::Value> a2 =
12002 : ReturnThisSloppy
12003 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
12004 6 : .ToLocalChecked();
12005 12 : CHECK(a2->StrictEquals(context->Global()));
12006 : Local<v8::Value> a3 =
12007 : ReturnThisSloppy
12008 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
12009 6 : .ToLocalChecked();
12010 6 : CHECK(a3->IsNumberObject());
12011 6 : CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
12012 : Local<v8::Value> a4 =
12013 : ReturnThisSloppy
12014 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
12015 6 : .ToLocalChecked();
12016 6 : CHECK(a4->IsStringObject());
12017 18 : CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
12018 : Local<v8::Value> a5 =
12019 : ReturnThisSloppy
12020 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
12021 6 : .ToLocalChecked();
12022 6 : CHECK(a5->IsBooleanObject());
12023 6 : CHECK(a5.As<v8::BooleanObject>()->ValueOf());
12024 :
12025 : Local<v8::Value> a6 =
12026 : ReturnThisStrict
12027 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
12028 12 : nullptr)
12029 6 : .ToLocalChecked();
12030 6 : CHECK(a6->IsUndefined());
12031 : Local<v8::Value> a7 =
12032 : ReturnThisStrict
12033 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
12034 6 : .ToLocalChecked();
12035 6 : CHECK(a7->IsNull());
12036 : Local<v8::Value> a8 =
12037 : ReturnThisStrict
12038 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
12039 6 : .ToLocalChecked();
12040 6 : CHECK(a8->StrictEquals(v8_num(42)));
12041 : Local<v8::Value> a9 =
12042 : ReturnThisStrict
12043 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
12044 6 : .ToLocalChecked();
12045 12 : CHECK(a9->StrictEquals(v8_str("hello")));
12046 : Local<v8::Value> a10 =
12047 : ReturnThisStrict
12048 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
12049 6 : .ToLocalChecked();
12050 6 : CHECK(a10->StrictEquals(v8::True(isolate)));
12051 6 : }
12052 6 : }
12053 :
12054 :
12055 : // Check whether a non-function object is callable.
12056 28343 : THREADED_TEST(CallableObject) {
12057 6 : LocalContext context;
12058 6 : v8::Isolate* isolate = context->GetIsolate();
12059 12 : v8::HandleScope scope(isolate);
12060 :
12061 : {
12062 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
12063 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
12064 : Local<Object> instance =
12065 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
12066 6 : v8::TryCatch try_catch(isolate);
12067 :
12068 6 : CHECK(instance->IsCallable());
12069 6 : CHECK(!try_catch.HasCaught());
12070 : }
12071 :
12072 : {
12073 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
12074 : Local<Object> instance =
12075 12 : instance_template->NewInstance(context.local()).ToLocalChecked();
12076 6 : v8::TryCatch try_catch(isolate);
12077 :
12078 6 : CHECK(!instance->IsCallable());
12079 6 : CHECK(!try_catch.HasCaught());
12080 : }
12081 :
12082 : {
12083 : Local<FunctionTemplate> function_template =
12084 6 : FunctionTemplate::New(isolate, call_as_function);
12085 : Local<Function> function =
12086 12 : function_template->GetFunction(context.local()).ToLocalChecked();
12087 : Local<Object> instance = function;
12088 6 : v8::TryCatch try_catch(isolate);
12089 :
12090 6 : CHECK(instance->IsCallable());
12091 6 : CHECK(!try_catch.HasCaught());
12092 : }
12093 :
12094 : {
12095 6 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
12096 : Local<Function> function =
12097 12 : function_template->GetFunction(context.local()).ToLocalChecked();
12098 : Local<Object> instance = function;
12099 6 : v8::TryCatch try_catch(isolate);
12100 :
12101 6 : CHECK(instance->IsCallable());
12102 6 : CHECK(!try_catch.HasCaught());
12103 6 : }
12104 6 : }
12105 :
12106 :
12107 28343 : THREADED_TEST(Regress567998) {
12108 6 : LocalContext env;
12109 12 : v8::HandleScope scope(env->GetIsolate());
12110 :
12111 : Local<v8::FunctionTemplate> desc =
12112 6 : v8::FunctionTemplate::New(env->GetIsolate());
12113 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
12114 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
12115 :
12116 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
12117 6 : .ToLocalChecked()
12118 6 : ->NewInstance(env.local())
12119 : .ToLocalChecked();
12120 30 : CHECK(
12121 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
12122 :
12123 6 : ExpectString("undetectable.toString()", "[object Object]");
12124 6 : ExpectString("typeof undetectable", "undefined");
12125 6 : ExpectString("typeof(undetectable)", "undefined");
12126 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
12127 6 : ExpectBoolean("typeof undetectable == 'object'", false);
12128 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
12129 6 : ExpectBoolean("!undetectable", true);
12130 :
12131 6 : ExpectObject("true&&undetectable", obj);
12132 6 : ExpectBoolean("false&&undetectable", false);
12133 6 : ExpectBoolean("true||undetectable", true);
12134 6 : ExpectObject("false||undetectable", obj);
12135 :
12136 6 : ExpectObject("undetectable&&true", obj);
12137 6 : ExpectObject("undetectable&&false", obj);
12138 6 : ExpectBoolean("undetectable||true", true);
12139 6 : ExpectBoolean("undetectable||false", false);
12140 :
12141 6 : ExpectBoolean("undetectable==null", true);
12142 6 : ExpectBoolean("null==undetectable", true);
12143 6 : ExpectBoolean("undetectable==undefined", true);
12144 6 : ExpectBoolean("undefined==undetectable", true);
12145 6 : ExpectBoolean("undetectable==undetectable", true);
12146 :
12147 6 : ExpectBoolean("undetectable===null", false);
12148 6 : ExpectBoolean("null===undetectable", false);
12149 6 : ExpectBoolean("undetectable===undefined", false);
12150 6 : ExpectBoolean("undefined===undetectable", false);
12151 12 : ExpectBoolean("undetectable===undetectable", true);
12152 6 : }
12153 :
12154 :
12155 1206 : static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
12156 1206 : v8::HandleScope scope(isolate);
12157 1206 : if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
12158 600000 : for (int i = 0; i < iterations; i++) {
12159 600000 : Local<v8::Number> n(v8::Integer::New(isolate, 42));
12160 : }
12161 1200 : return Recurse(isolate, depth - 1, iterations);
12162 : }
12163 :
12164 :
12165 28343 : THREADED_TEST(HandleIteration) {
12166 : static const int kIterations = 500;
12167 : static const int kNesting = 200;
12168 6 : LocalContext context;
12169 6 : v8::Isolate* isolate = context->GetIsolate();
12170 12 : v8::HandleScope scope0(isolate);
12171 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12172 : {
12173 6 : v8::HandleScope scope1(isolate);
12174 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12175 3006 : for (int i = 0; i < kIterations; i++) {
12176 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12177 3000 : CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12178 : }
12179 :
12180 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12181 : {
12182 6 : v8::HandleScope scope2(CcTest::isolate());
12183 3006 : for (int j = 0; j < kIterations; j++) {
12184 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12185 3000 : CHECK_EQ(j + 1 + kIterations,
12186 : v8::HandleScope::NumberOfHandles(isolate));
12187 6 : }
12188 : }
12189 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12190 : }
12191 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12192 12 : CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12193 6 : }
12194 :
12195 :
12196 4994 : static void InterceptorCallICFastApi(
12197 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12198 4994 : ApiTestFuzzer::Fuzz();
12199 4994 : CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12200 : int* call_count =
12201 4994 : reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12202 4994 : ++(*call_count);
12203 4994 : if ((*call_count) % 20 == 0) {
12204 231 : CcTest::CollectAllGarbage();
12205 : }
12206 4994 : }
12207 :
12208 2200 : static void FastApiCallback_TrivialSignature(
12209 8800 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12210 2200 : ApiTestFuzzer::Fuzz();
12211 2200 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12212 2200 : v8::Isolate* isolate = CcTest::isolate();
12213 2200 : CHECK_EQ(isolate, args.GetIsolate());
12214 6600 : CHECK(args.This()
12215 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12216 : .FromJust());
12217 8800 : CHECK(args.Data()
12218 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12219 : .FromJust());
12220 : args.GetReturnValue().Set(
12221 8800 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12222 2200 : }
12223 :
12224 6127 : static void FastApiCallback_SimpleSignature(
12225 30635 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12226 6127 : ApiTestFuzzer::Fuzz();
12227 6127 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12228 6127 : v8::Isolate* isolate = CcTest::isolate();
12229 6127 : CHECK_EQ(isolate, args.GetIsolate());
12230 24508 : CHECK(args.This()
12231 : ->GetPrototype()
12232 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12233 : .FromJust());
12234 24508 : CHECK(args.Data()
12235 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12236 : .FromJust());
12237 : // Note, we're using HasRealNamedProperty instead of Has to avoid
12238 : // invoking the interceptor again.
12239 24508 : CHECK(args.Holder()
12240 : ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12241 : .FromJust());
12242 : args.GetReturnValue().Set(
12243 24508 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12244 6127 : }
12245 :
12246 :
12247 : // Helper to maximize the odds of object moving.
12248 291 : static void GenerateSomeGarbage() {
12249 : CompileRun(
12250 : "var garbage;"
12251 : "for (var i = 0; i < 1000; i++) {"
12252 : " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12253 : "}"
12254 : "garbage = undefined;");
12255 291 : }
12256 :
12257 :
12258 180 : void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12259 : static int count = 0;
12260 180 : if (count++ % 3 == 0) {
12261 60 : CcTest::CollectAllGarbage();
12262 : // This should move the stub
12263 60 : GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12264 : }
12265 180 : }
12266 :
12267 :
12268 28343 : THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12269 6 : LocalContext context;
12270 6 : v8::Isolate* isolate = context->GetIsolate();
12271 12 : v8::HandleScope scope(isolate);
12272 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12273 6 : v8::ObjectTemplate::New(isolate);
12274 : nativeobject_templ->Set(isolate, "callback",
12275 : v8::FunctionTemplate::New(isolate,
12276 12 : DirectApiCallback));
12277 : v8::Local<v8::Object> nativeobject_obj =
12278 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12279 30 : CHECK(context->Global()
12280 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12281 : .FromJust());
12282 : // call the api function multiple times to ensure direct call stub creation.
12283 : CompileRun(
12284 : "function f() {"
12285 : " for (var i = 1; i <= 30; i++) {"
12286 : " nativeobject.callback();"
12287 : " }"
12288 : "}"
12289 6 : "f();");
12290 6 : }
12291 :
12292 :
12293 30 : void ThrowingDirectApiCallback(
12294 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12295 60 : args.GetIsolate()->ThrowException(v8_str("g"));
12296 30 : }
12297 :
12298 :
12299 28343 : THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12300 6 : LocalContext context;
12301 6 : v8::Isolate* isolate = context->GetIsolate();
12302 12 : v8::HandleScope scope(isolate);
12303 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12304 6 : v8::ObjectTemplate::New(isolate);
12305 : nativeobject_templ->Set(isolate, "callback",
12306 : v8::FunctionTemplate::New(isolate,
12307 12 : ThrowingDirectApiCallback));
12308 : v8::Local<v8::Object> nativeobject_obj =
12309 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12310 30 : CHECK(context->Global()
12311 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12312 : .FromJust());
12313 : // call the api function multiple times to ensure direct call stub creation.
12314 : v8::Local<Value> result = CompileRun(
12315 : "var result = '';"
12316 : "function f() {"
12317 : " for (var i = 1; i <= 5; i++) {"
12318 : " try { nativeobject.callback(); } catch (e) { result += e; }"
12319 : " }"
12320 : "}"
12321 6 : "f(); result;");
12322 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12323 6 : }
12324 :
12325 :
12326 : static int p_getter_count_3;
12327 :
12328 :
12329 341 : static Local<Value> DoDirectGetter() {
12330 341 : if (++p_getter_count_3 % 3 == 0) {
12331 110 : CcTest::CollectAllGarbage();
12332 110 : GenerateSomeGarbage();
12333 : }
12334 341 : return v8_str("Direct Getter Result");
12335 : }
12336 :
12337 :
12338 341 : static void DirectGetterCallback(
12339 : Local<String> name,
12340 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12341 341 : CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12342 341 : info.GetReturnValue().Set(DoDirectGetter());
12343 341 : }
12344 :
12345 :
12346 : template<typename Accessor>
12347 11 : static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12348 11 : LocalContext context;
12349 11 : v8::Isolate* isolate = context->GetIsolate();
12350 22 : v8::HandleScope scope(isolate);
12351 11 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12352 11 : obj->SetAccessor(v8_str("p1"), accessor);
12353 66 : CHECK(context->Global()
12354 : ->Set(context.local(), v8_str("o1"),
12355 : obj->NewInstance(context.local()).ToLocalChecked())
12356 : .FromJust());
12357 11 : p_getter_count_3 = 0;
12358 : v8::Local<v8::Value> result = CompileRun(
12359 : "function f() {"
12360 : " for (var i = 0; i < 30; i++) o1.p1;"
12361 : " return o1.p1"
12362 : "}"
12363 11 : "f();");
12364 33 : CHECK(v8_str("Direct Getter Result")
12365 : ->Equals(context.local(), result)
12366 : .FromJust());
12367 22 : CHECK_EQ(31, p_getter_count_3);
12368 11 : }
12369 :
12370 :
12371 56690 : THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12372 11 : LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12373 11 : }
12374 :
12375 :
12376 30 : void ThrowingDirectGetterCallback(
12377 : Local<String> name,
12378 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12379 60 : info.GetIsolate()->ThrowException(v8_str("g"));
12380 30 : }
12381 :
12382 :
12383 28343 : THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12384 6 : LocalContext context;
12385 6 : v8::Isolate* isolate = context->GetIsolate();
12386 12 : v8::HandleScope scope(isolate);
12387 6 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12388 6 : obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12389 36 : CHECK(context->Global()
12390 : ->Set(context.local(), v8_str("o1"),
12391 : obj->NewInstance(context.local()).ToLocalChecked())
12392 : .FromJust());
12393 : v8::Local<Value> result = CompileRun(
12394 : "var result = '';"
12395 : "for (var i = 0; i < 5; i++) {"
12396 : " try { o1.p1; } catch (e) { result += e; }"
12397 : "}"
12398 6 : "result;");
12399 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12400 6 : }
12401 :
12402 :
12403 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12404 11 : int interceptor_call_count = 0;
12405 11 : v8::Isolate* isolate = CcTest::isolate();
12406 11 : v8::HandleScope scope(isolate);
12407 : v8::Local<v8::FunctionTemplate> fun_templ =
12408 11 : v8::FunctionTemplate::New(isolate);
12409 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12410 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12411 22 : v8::Local<v8::Signature>());
12412 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12413 22 : proto_templ->Set(v8_str("method"), method_templ);
12414 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12415 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12416 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12417 22 : v8::External::New(isolate, &interceptor_call_count)));
12418 22 : LocalContext context;
12419 : v8::Local<v8::Function> fun =
12420 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12421 11 : GenerateSomeGarbage();
12422 66 : CHECK(context->Global()
12423 : ->Set(context.local(), v8_str("o"),
12424 : fun->NewInstance(context.local()).ToLocalChecked())
12425 : .FromJust());
12426 : CompileRun(
12427 : "var result = 0;"
12428 : "for (var i = 0; i < 100; i++) {"
12429 : " result = o.method(41);"
12430 : "}");
12431 66 : CHECK_EQ(42, context->Global()
12432 : ->Get(context.local(), v8_str("result"))
12433 : .ToLocalChecked()
12434 : ->Int32Value(context.local())
12435 : .FromJust());
12436 22 : CHECK_EQ(100, interceptor_call_count);
12437 11 : }
12438 :
12439 :
12440 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12441 11 : int interceptor_call_count = 0;
12442 11 : v8::Isolate* isolate = CcTest::isolate();
12443 11 : v8::HandleScope scope(isolate);
12444 : v8::Local<v8::FunctionTemplate> fun_templ =
12445 11 : v8::FunctionTemplate::New(isolate);
12446 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12447 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12448 22 : v8::Signature::New(isolate, fun_templ));
12449 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12450 22 : proto_templ->Set(v8_str("method"), method_templ);
12451 11 : fun_templ->SetHiddenPrototype(true);
12452 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12453 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12454 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12455 22 : v8::External::New(isolate, &interceptor_call_count)));
12456 22 : LocalContext context;
12457 : v8::Local<v8::Function> fun =
12458 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12459 11 : GenerateSomeGarbage();
12460 66 : CHECK(context->Global()
12461 : ->Set(context.local(), v8_str("o"),
12462 : fun->NewInstance(context.local()).ToLocalChecked())
12463 : .FromJust());
12464 : CompileRun(
12465 : "o.foo = 17;"
12466 : "var receiver = {};"
12467 : "receiver.__proto__ = o;"
12468 : "var result = 0;"
12469 : "for (var i = 0; i < 100; i++) {"
12470 : " result = receiver.method(41);"
12471 : "}");
12472 66 : CHECK_EQ(42, context->Global()
12473 : ->Get(context.local(), v8_str("result"))
12474 : .ToLocalChecked()
12475 : ->Int32Value(context.local())
12476 : .FromJust());
12477 22 : CHECK_EQ(100, interceptor_call_count);
12478 11 : }
12479 :
12480 :
12481 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12482 11 : int interceptor_call_count = 0;
12483 11 : v8::Isolate* isolate = CcTest::isolate();
12484 11 : v8::HandleScope scope(isolate);
12485 : v8::Local<v8::FunctionTemplate> fun_templ =
12486 11 : v8::FunctionTemplate::New(isolate);
12487 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12488 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12489 22 : v8::Signature::New(isolate, fun_templ));
12490 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12491 22 : proto_templ->Set(v8_str("method"), method_templ);
12492 11 : fun_templ->SetHiddenPrototype(true);
12493 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12494 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12495 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12496 22 : v8::External::New(isolate, &interceptor_call_count)));
12497 22 : LocalContext context;
12498 : v8::Local<v8::Function> fun =
12499 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12500 11 : GenerateSomeGarbage();
12501 66 : CHECK(context->Global()
12502 : ->Set(context.local(), v8_str("o"),
12503 : fun->NewInstance(context.local()).ToLocalChecked())
12504 : .FromJust());
12505 : CompileRun(
12506 : "o.foo = 17;"
12507 : "var receiver = {};"
12508 : "receiver.__proto__ = o;"
12509 : "var result = 0;"
12510 : "var saved_result = 0;"
12511 : "for (var i = 0; i < 100; i++) {"
12512 : " result = receiver.method(41);"
12513 : " if (i == 50) {"
12514 : " saved_result = result;"
12515 : " receiver = {method: function(x) { return x - 1 }};"
12516 : " }"
12517 : "}");
12518 66 : CHECK_EQ(40, context->Global()
12519 : ->Get(context.local(), v8_str("result"))
12520 : .ToLocalChecked()
12521 : ->Int32Value(context.local())
12522 : .FromJust());
12523 66 : CHECK_EQ(42, context->Global()
12524 : ->Get(context.local(), v8_str("saved_result"))
12525 : .ToLocalChecked()
12526 : ->Int32Value(context.local())
12527 : .FromJust());
12528 22 : CHECK_GE(interceptor_call_count, 50);
12529 11 : }
12530 :
12531 :
12532 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12533 11 : int interceptor_call_count = 0;
12534 11 : v8::Isolate* isolate = CcTest::isolate();
12535 11 : v8::HandleScope scope(isolate);
12536 : v8::Local<v8::FunctionTemplate> fun_templ =
12537 11 : v8::FunctionTemplate::New(isolate);
12538 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12539 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12540 22 : v8::Signature::New(isolate, fun_templ));
12541 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12542 22 : proto_templ->Set(v8_str("method"), method_templ);
12543 11 : fun_templ->SetHiddenPrototype(true);
12544 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12545 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12546 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12547 22 : v8::External::New(isolate, &interceptor_call_count)));
12548 22 : LocalContext context;
12549 : v8::Local<v8::Function> fun =
12550 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12551 11 : GenerateSomeGarbage();
12552 66 : CHECK(context->Global()
12553 : ->Set(context.local(), v8_str("o"),
12554 : fun->NewInstance(context.local()).ToLocalChecked())
12555 : .FromJust());
12556 : CompileRun(
12557 : "o.foo = 17;"
12558 : "var receiver = {};"
12559 : "receiver.__proto__ = o;"
12560 : "var result = 0;"
12561 : "var saved_result = 0;"
12562 : "for (var i = 0; i < 100; i++) {"
12563 : " result = receiver.method(41);"
12564 : " if (i == 50) {"
12565 : " saved_result = result;"
12566 : " o.method = function(x) { return x - 1 };"
12567 : " }"
12568 : "}");
12569 66 : CHECK_EQ(40, context->Global()
12570 : ->Get(context.local(), v8_str("result"))
12571 : .ToLocalChecked()
12572 : ->Int32Value(context.local())
12573 : .FromJust());
12574 66 : CHECK_EQ(42, context->Global()
12575 : ->Get(context.local(), v8_str("saved_result"))
12576 : .ToLocalChecked()
12577 : ->Int32Value(context.local())
12578 : .FromJust());
12579 22 : CHECK_GE(interceptor_call_count, 50);
12580 11 : }
12581 :
12582 :
12583 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12584 11 : int interceptor_call_count = 0;
12585 11 : v8::Isolate* isolate = CcTest::isolate();
12586 11 : v8::HandleScope scope(isolate);
12587 : v8::Local<v8::FunctionTemplate> fun_templ =
12588 11 : v8::FunctionTemplate::New(isolate);
12589 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12590 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12591 22 : v8::Signature::New(isolate, fun_templ));
12592 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12593 22 : proto_templ->Set(v8_str("method"), method_templ);
12594 11 : fun_templ->SetHiddenPrototype(true);
12595 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12596 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12597 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12598 22 : v8::External::New(isolate, &interceptor_call_count)));
12599 22 : LocalContext context;
12600 : v8::Local<v8::Function> fun =
12601 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12602 11 : GenerateSomeGarbage();
12603 66 : CHECK(context->Global()
12604 : ->Set(context.local(), v8_str("o"),
12605 : fun->NewInstance(context.local()).ToLocalChecked())
12606 : .FromJust());
12607 22 : v8::TryCatch try_catch(isolate);
12608 : CompileRun(
12609 : "o.foo = 17;"
12610 : "var receiver = {};"
12611 : "receiver.__proto__ = o;"
12612 : "var result = 0;"
12613 : "var saved_result = 0;"
12614 : "for (var i = 0; i < 100; i++) {"
12615 : " result = receiver.method(41);"
12616 : " if (i == 50) {"
12617 : " saved_result = result;"
12618 : " receiver = 333;"
12619 : " }"
12620 : "}");
12621 11 : CHECK(try_catch.HasCaught());
12622 : // TODO(verwaest): Adjust message.
12623 55 : CHECK(
12624 : v8_str("TypeError: receiver.method is not a function")
12625 : ->Equals(
12626 : context.local(),
12627 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12628 : .FromJust());
12629 66 : CHECK_EQ(42, context->Global()
12630 : ->Get(context.local(), v8_str("saved_result"))
12631 : .ToLocalChecked()
12632 : ->Int32Value(context.local())
12633 : .FromJust());
12634 22 : CHECK_GE(interceptor_call_count, 50);
12635 11 : }
12636 :
12637 :
12638 56690 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12639 11 : int interceptor_call_count = 0;
12640 11 : v8::Isolate* isolate = CcTest::isolate();
12641 11 : v8::HandleScope scope(isolate);
12642 : v8::Local<v8::FunctionTemplate> fun_templ =
12643 11 : v8::FunctionTemplate::New(isolate);
12644 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12645 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12646 22 : v8::Signature::New(isolate, fun_templ));
12647 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12648 22 : proto_templ->Set(v8_str("method"), method_templ);
12649 11 : fun_templ->SetHiddenPrototype(true);
12650 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12651 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12652 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12653 22 : v8::External::New(isolate, &interceptor_call_count)));
12654 22 : LocalContext context;
12655 : v8::Local<v8::Function> fun =
12656 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12657 11 : GenerateSomeGarbage();
12658 66 : CHECK(context->Global()
12659 : ->Set(context.local(), v8_str("o"),
12660 : fun->NewInstance(context.local()).ToLocalChecked())
12661 : .FromJust());
12662 22 : v8::TryCatch try_catch(isolate);
12663 : CompileRun(
12664 : "o.foo = 17;"
12665 : "var receiver = {};"
12666 : "receiver.__proto__ = o;"
12667 : "var result = 0;"
12668 : "var saved_result = 0;"
12669 : "for (var i = 0; i < 100; i++) {"
12670 : " result = receiver.method(41);"
12671 : " if (i == 50) {"
12672 : " saved_result = result;"
12673 : " receiver = {method: receiver.method};"
12674 : " }"
12675 : "}");
12676 11 : CHECK(try_catch.HasCaught());
12677 55 : CHECK(
12678 : v8_str("TypeError: Illegal invocation")
12679 : ->Equals(
12680 : context.local(),
12681 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12682 : .FromJust());
12683 66 : CHECK_EQ(42, context->Global()
12684 : ->Get(context.local(), v8_str("saved_result"))
12685 : .ToLocalChecked()
12686 : ->Int32Value(context.local())
12687 : .FromJust());
12688 22 : CHECK_GE(interceptor_call_count, 50);
12689 11 : }
12690 :
12691 :
12692 56690 : THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12693 11 : v8::Isolate* isolate = CcTest::isolate();
12694 11 : v8::HandleScope scope(isolate);
12695 : v8::Local<v8::FunctionTemplate> fun_templ =
12696 11 : v8::FunctionTemplate::New(isolate);
12697 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12698 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12699 22 : v8::Local<v8::Signature>());
12700 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12701 22 : proto_templ->Set(v8_str("method"), method_templ);
12702 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12703 : USE(templ);
12704 22 : LocalContext context;
12705 : v8::Local<v8::Function> fun =
12706 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12707 11 : GenerateSomeGarbage();
12708 66 : CHECK(context->Global()
12709 : ->Set(context.local(), v8_str("o"),
12710 : fun->NewInstance(context.local()).ToLocalChecked())
12711 : .FromJust());
12712 : CompileRun(
12713 : "var result = 0;"
12714 : "for (var i = 0; i < 100; i++) {"
12715 : " result = o.method(41);"
12716 : "}");
12717 :
12718 66 : CHECK_EQ(42, context->Global()
12719 : ->Get(context.local(), v8_str("result"))
12720 : .ToLocalChecked()
12721 : ->Int32Value(context.local())
12722 11 : .FromJust());
12723 11 : }
12724 :
12725 :
12726 56690 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12727 11 : v8::Isolate* isolate = CcTest::isolate();
12728 11 : v8::HandleScope scope(isolate);
12729 : v8::Local<v8::FunctionTemplate> fun_templ =
12730 11 : v8::FunctionTemplate::New(isolate);
12731 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12732 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12733 22 : v8::Signature::New(isolate, fun_templ));
12734 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12735 22 : proto_templ->Set(v8_str("method"), method_templ);
12736 11 : fun_templ->SetHiddenPrototype(true);
12737 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12738 11 : CHECK(!templ.IsEmpty());
12739 22 : LocalContext context;
12740 : v8::Local<v8::Function> fun =
12741 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12742 11 : GenerateSomeGarbage();
12743 66 : CHECK(context->Global()
12744 : ->Set(context.local(), v8_str("o"),
12745 : fun->NewInstance(context.local()).ToLocalChecked())
12746 : .FromJust());
12747 : CompileRun(
12748 : "o.foo = 17;"
12749 : "var receiver = {};"
12750 : "receiver.__proto__ = o;"
12751 : "var result = 0;"
12752 : "for (var i = 0; i < 100; i++) {"
12753 : " result = receiver.method(41);"
12754 : "}");
12755 :
12756 66 : CHECK_EQ(42, context->Global()
12757 : ->Get(context.local(), v8_str("result"))
12758 : .ToLocalChecked()
12759 : ->Int32Value(context.local())
12760 11 : .FromJust());
12761 11 : }
12762 :
12763 :
12764 56690 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12765 11 : v8::Isolate* isolate = CcTest::isolate();
12766 11 : v8::HandleScope scope(isolate);
12767 : v8::Local<v8::FunctionTemplate> fun_templ =
12768 11 : v8::FunctionTemplate::New(isolate);
12769 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12770 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12771 22 : v8::Signature::New(isolate, fun_templ));
12772 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12773 22 : proto_templ->Set(v8_str("method"), method_templ);
12774 11 : fun_templ->SetHiddenPrototype(true);
12775 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12776 11 : CHECK(!templ.IsEmpty());
12777 22 : LocalContext context;
12778 : v8::Local<v8::Function> fun =
12779 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12780 11 : GenerateSomeGarbage();
12781 66 : CHECK(context->Global()
12782 : ->Set(context.local(), v8_str("o"),
12783 : fun->NewInstance(context.local()).ToLocalChecked())
12784 : .FromJust());
12785 : CompileRun(
12786 : "o.foo = 17;"
12787 : "var receiver = {};"
12788 : "receiver.__proto__ = o;"
12789 : "var result = 0;"
12790 : "var saved_result = 0;"
12791 : "for (var i = 0; i < 100; i++) {"
12792 : " result = receiver.method(41);"
12793 : " if (i == 50) {"
12794 : " saved_result = result;"
12795 : " receiver = {method: function(x) { return x - 1 }};"
12796 : " }"
12797 : "}");
12798 66 : CHECK_EQ(40, context->Global()
12799 : ->Get(context.local(), v8_str("result"))
12800 : .ToLocalChecked()
12801 : ->Int32Value(context.local())
12802 : .FromJust());
12803 66 : CHECK_EQ(42, context->Global()
12804 : ->Get(context.local(), v8_str("saved_result"))
12805 : .ToLocalChecked()
12806 : ->Int32Value(context.local())
12807 11 : .FromJust());
12808 11 : }
12809 :
12810 :
12811 56690 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12812 11 : v8::Isolate* isolate = CcTest::isolate();
12813 11 : v8::HandleScope scope(isolate);
12814 : v8::Local<v8::FunctionTemplate> fun_templ =
12815 11 : v8::FunctionTemplate::New(isolate);
12816 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12817 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12818 22 : v8::Signature::New(isolate, fun_templ));
12819 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12820 22 : proto_templ->Set(v8_str("method"), method_templ);
12821 11 : fun_templ->SetHiddenPrototype(true);
12822 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12823 11 : CHECK(!templ.IsEmpty());
12824 22 : LocalContext context;
12825 : v8::Local<v8::Function> fun =
12826 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12827 11 : GenerateSomeGarbage();
12828 66 : CHECK(context->Global()
12829 : ->Set(context.local(), v8_str("o"),
12830 : fun->NewInstance(context.local()).ToLocalChecked())
12831 : .FromJust());
12832 22 : v8::TryCatch try_catch(isolate);
12833 : CompileRun(
12834 : "o.foo = 17;"
12835 : "var receiver = {};"
12836 : "receiver.__proto__ = o;"
12837 : "var result = 0;"
12838 : "var saved_result = 0;"
12839 : "for (var i = 0; i < 100; i++) {"
12840 : " result = receiver.method(41);"
12841 : " if (i == 50) {"
12842 : " saved_result = result;"
12843 : " receiver = 333;"
12844 : " }"
12845 : "}");
12846 11 : CHECK(try_catch.HasCaught());
12847 : // TODO(verwaest): Adjust message.
12848 55 : CHECK(
12849 : v8_str("TypeError: receiver.method is not a function")
12850 : ->Equals(
12851 : context.local(),
12852 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12853 : .FromJust());
12854 66 : CHECK_EQ(42, context->Global()
12855 : ->Get(context.local(), v8_str("saved_result"))
12856 : .ToLocalChecked()
12857 : ->Int32Value(context.local())
12858 11 : .FromJust());
12859 11 : }
12860 :
12861 :
12862 56690 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12863 11 : v8::Isolate* isolate = CcTest::isolate();
12864 11 : v8::HandleScope scope(isolate);
12865 : v8::Local<v8::FunctionTemplate> fun_templ =
12866 11 : v8::FunctionTemplate::New(isolate);
12867 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12868 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12869 22 : v8::Signature::New(isolate, fun_templ));
12870 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12871 22 : proto_templ->Set(v8_str("method"), method_templ);
12872 11 : fun_templ->SetHiddenPrototype(true);
12873 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12874 11 : CHECK(!templ.IsEmpty());
12875 22 : LocalContext context;
12876 : v8::Local<v8::Function> fun =
12877 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12878 11 : GenerateSomeGarbage();
12879 66 : CHECK(context->Global()
12880 : ->Set(context.local(), v8_str("o"),
12881 : fun->NewInstance(context.local()).ToLocalChecked())
12882 : .FromJust());
12883 22 : v8::TryCatch try_catch(isolate);
12884 : CompileRun(
12885 : "o.foo = 17;"
12886 : "var receiver = {};"
12887 : "receiver.__proto__ = o;"
12888 : "var result = 0;"
12889 : "var saved_result = 0;"
12890 : "for (var i = 0; i < 100; i++) {"
12891 : " result = receiver.method(41);"
12892 : " if (i == 50) {"
12893 : " saved_result = result;"
12894 : " receiver = Object.create(receiver);"
12895 : " }"
12896 : "}");
12897 11 : CHECK(try_catch.HasCaught());
12898 55 : CHECK(
12899 : v8_str("TypeError: Illegal invocation")
12900 : ->Equals(
12901 : context.local(),
12902 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12903 : .FromJust());
12904 66 : CHECK_EQ(42, context->Global()
12905 : ->Get(context.local(), v8_str("saved_result"))
12906 : .ToLocalChecked()
12907 : ->Int32Value(context.local())
12908 11 : .FromJust());
12909 11 : }
12910 :
12911 :
12912 24 : static void ThrowingGetter(Local<String> name,
12913 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12914 24 : ApiTestFuzzer::Fuzz();
12915 24 : info.GetIsolate()->ThrowException(Local<Value>());
12916 : info.GetReturnValue().SetUndefined();
12917 24 : }
12918 :
12919 :
12920 28343 : THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12921 6 : LocalContext context;
12922 12 : HandleScope scope(context->GetIsolate());
12923 :
12924 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12925 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12926 12 : instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12927 :
12928 6 : Local<Object> instance = templ->GetFunction(context.local())
12929 6 : .ToLocalChecked()
12930 6 : ->NewInstance(context.local())
12931 : .ToLocalChecked();
12932 :
12933 6 : Local<Object> another = Object::New(context->GetIsolate());
12934 12 : CHECK(another->SetPrototype(context.local(), instance).FromJust());
12935 :
12936 : Local<Object> with_js_getter = CompileRun(
12937 : "o = {};\n"
12938 : "o.__defineGetter__('f', function() { throw undefined; });\n"
12939 : "o\n").As<Object>();
12940 6 : CHECK(!with_js_getter.IsEmpty());
12941 :
12942 12 : TryCatch try_catch(context->GetIsolate());
12943 :
12944 : v8::MaybeLocal<Value> result =
12945 12 : instance->GetRealNamedProperty(context.local(), v8_str("f"));
12946 6 : CHECK(try_catch.HasCaught());
12947 6 : try_catch.Reset();
12948 6 : CHECK(result.IsEmpty());
12949 :
12950 : Maybe<PropertyAttribute> attr =
12951 12 : instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12952 6 : CHECK(!try_catch.HasCaught());
12953 6 : CHECK(Just(None) == attr);
12954 :
12955 12 : result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12956 6 : CHECK(try_catch.HasCaught());
12957 6 : try_catch.Reset();
12958 6 : CHECK(result.IsEmpty());
12959 :
12960 12 : attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12961 6 : CHECK(!try_catch.HasCaught());
12962 6 : CHECK(Just(None) == attr);
12963 :
12964 : result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12965 12 : v8_str("f"));
12966 6 : CHECK(try_catch.HasCaught());
12967 6 : try_catch.Reset();
12968 6 : CHECK(result.IsEmpty());
12969 :
12970 : attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12971 12 : context.local(), v8_str("f"));
12972 6 : CHECK(!try_catch.HasCaught());
12973 6 : CHECK(Just(None) == attr);
12974 :
12975 12 : result = another->Get(context.local(), v8_str("f"));
12976 6 : CHECK(try_catch.HasCaught());
12977 6 : try_catch.Reset();
12978 6 : CHECK(result.IsEmpty());
12979 :
12980 12 : result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12981 6 : CHECK(try_catch.HasCaught());
12982 6 : try_catch.Reset();
12983 6 : CHECK(result.IsEmpty());
12984 :
12985 : attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12986 12 : v8_str("f"));
12987 6 : CHECK(!try_catch.HasCaught());
12988 6 : CHECK(Just(None) == attr);
12989 :
12990 12 : result = with_js_getter->Get(context.local(), v8_str("f"));
12991 6 : CHECK(try_catch.HasCaught());
12992 6 : try_catch.Reset();
12993 6 : CHECK(result.IsEmpty());
12994 :
12995 : Local<Object> target = CompileRun("({})").As<Object>();
12996 6 : Local<Object> handler = CompileRun("({})").As<Object>();
12997 : Local<v8::Proxy> proxy =
12998 6 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12999 :
13000 12 : result = target->GetRealNamedProperty(context.local(), v8_str("f"));
13001 6 : CHECK(!try_catch.HasCaught());
13002 6 : CHECK(result.IsEmpty());
13003 :
13004 12 : result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
13005 6 : CHECK(!try_catch.HasCaught());
13006 12 : CHECK(result.IsEmpty());
13007 6 : }
13008 :
13009 :
13010 30 : static void ThrowingCallbackWithTryCatch(
13011 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
13012 30 : TryCatch try_catch(args.GetIsolate());
13013 : // Verboseness is important: it triggers message delivery which can call into
13014 : // external code.
13015 30 : try_catch.SetVerbose(true);
13016 : CompileRun("throw 'from JS';");
13017 30 : CHECK(try_catch.HasCaught());
13018 30 : CHECK(!CcTest::i_isolate()->has_pending_exception());
13019 30 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13020 30 : }
13021 :
13022 :
13023 : static int call_depth;
13024 :
13025 :
13026 6 : static void WithTryCatch(Local<Message> message, Local<Value> data) {
13027 6 : TryCatch try_catch(CcTest::isolate());
13028 6 : }
13029 :
13030 :
13031 6 : static void ThrowFromJS(Local<Message> message, Local<Value> data) {
13032 6 : if (--call_depth) CompileRun("throw 'ThrowInJS';");
13033 6 : }
13034 :
13035 :
13036 6 : static void ThrowViaApi(Local<Message> message, Local<Value> data) {
13037 12 : if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13038 6 : }
13039 :
13040 :
13041 6 : static void WebKitLike(Local<Message> message, Local<Value> data) {
13042 6 : Local<String> errorMessageString = message->Get();
13043 6 : CHECK(!errorMessageString.IsEmpty());
13044 6 : message->GetStackTrace();
13045 6 : message->GetScriptOrigin().ResourceName();
13046 6 : }
13047 :
13048 :
13049 28343 : THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13050 6 : LocalContext context;
13051 6 : v8::Isolate* isolate = context->GetIsolate();
13052 12 : HandleScope scope(isolate);
13053 :
13054 : Local<Function> func =
13055 6 : FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
13056 18 : ->GetFunction(context.local())
13057 6 : .ToLocalChecked();
13058 30 : CHECK(
13059 : context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
13060 :
13061 : MessageCallback callbacks[] = {nullptr, WebKitLike, ThrowViaApi, ThrowFromJS,
13062 6 : WithTryCatch};
13063 36 : for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13064 30 : MessageCallback callback = callbacks[i];
13065 30 : if (callback != nullptr) {
13066 24 : isolate->AddMessageListener(callback);
13067 : }
13068 : // Some small number to control number of times message handler should
13069 : // throw an exception.
13070 30 : call_depth = 5;
13071 : ExpectFalse(
13072 : "var thrown = false;\n"
13073 : "try { func(); } catch(e) { thrown = true; }\n"
13074 : "thrown\n");
13075 30 : if (callback != nullptr) {
13076 24 : isolate->RemoveMessageListeners(callback);
13077 : }
13078 6 : }
13079 6 : }
13080 :
13081 :
13082 6 : static void ParentGetter(Local<String> name,
13083 : const v8::PropertyCallbackInfo<v8::Value>& info) {
13084 6 : ApiTestFuzzer::Fuzz();
13085 6 : info.GetReturnValue().Set(v8_num(1));
13086 6 : }
13087 :
13088 :
13089 18 : static void ChildGetter(Local<String> name,
13090 : const v8::PropertyCallbackInfo<v8::Value>& info) {
13091 18 : ApiTestFuzzer::Fuzz();
13092 18 : info.GetReturnValue().Set(v8_num(42));
13093 18 : }
13094 :
13095 :
13096 28343 : THREADED_TEST(Overriding) {
13097 6 : LocalContext context;
13098 6 : v8::Isolate* isolate = context->GetIsolate();
13099 12 : v8::HandleScope scope(isolate);
13100 :
13101 : // Parent template.
13102 6 : Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13103 : Local<ObjectTemplate> parent_instance_templ =
13104 6 : parent_templ->InstanceTemplate();
13105 12 : parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13106 :
13107 : // Template that inherits from the parent template.
13108 6 : Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13109 : Local<ObjectTemplate> child_instance_templ =
13110 6 : child_templ->InstanceTemplate();
13111 6 : child_templ->Inherit(parent_templ);
13112 : // Override 'f'. The child version of 'f' should get called for child
13113 : // instances.
13114 6 : child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13115 : // Add 'g' twice. The 'g' added last should get called for instances.
13116 6 : child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13117 6 : child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13118 :
13119 : // Add 'h' as an accessor to the proto template with ReadOnly attributes
13120 : // so 'h' can be shadowed on the instance object.
13121 6 : Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13122 : child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, nullptr,
13123 12 : v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
13124 :
13125 : // Add 'i' as an accessor to the instance template with ReadOnly attributes
13126 : // but the attribute does not have effect because it is duplicated with
13127 : // nullptr setter.
13128 : child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, nullptr,
13129 : v8::Local<Value>(), v8::DEFAULT,
13130 6 : v8::ReadOnly);
13131 :
13132 : // Instantiate the child template.
13133 6 : Local<v8::Object> instance = child_templ->GetFunction(context.local())
13134 6 : .ToLocalChecked()
13135 6 : ->NewInstance(context.local())
13136 : .ToLocalChecked();
13137 :
13138 : // Check that the child function overrides the parent one.
13139 30 : CHECK(context->Global()
13140 : ->Set(context.local(), v8_str("o"), instance)
13141 : .FromJust());
13142 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13143 : // Check that the 'g' that was added last is hit.
13144 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13145 12 : value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
13146 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13147 :
13148 : // Check that 'h' cannot be shadowed.
13149 12 : value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
13150 12 : CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
13151 :
13152 : // Check that 'i' cannot be shadowed or changed.
13153 12 : value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
13154 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13155 6 : }
13156 :
13157 :
13158 24 : static void ShouldThrowOnErrorGetter(
13159 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13160 24 : ApiTestFuzzer::Fuzz();
13161 : v8::Isolate* isolate = info.GetIsolate();
13162 : Local<Boolean> should_throw_on_error =
13163 : Boolean::New(isolate, info.ShouldThrowOnError());
13164 : info.GetReturnValue().Set(should_throw_on_error);
13165 24 : }
13166 :
13167 :
13168 : template <typename T>
13169 24 : static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
13170 : const v8::PropertyCallbackInfo<T>& info) {
13171 24 : ApiTestFuzzer::Fuzz();
13172 : v8::Isolate* isolate = info.GetIsolate();
13173 24 : auto context = isolate->GetCurrentContext();
13174 : Local<Boolean> should_throw_on_error_value =
13175 : Boolean::New(isolate, info.ShouldThrowOnError());
13176 120 : CHECK(context->Global()
13177 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
13178 : should_throw_on_error_value)
13179 : .FromJust());
13180 24 : }
13181 :
13182 :
13183 28343 : THREADED_TEST(AccessorShouldThrowOnError) {
13184 6 : LocalContext context;
13185 6 : v8::Isolate* isolate = context->GetIsolate();
13186 12 : v8::HandleScope scope(isolate);
13187 6 : Local<Object> global = context->Global();
13188 :
13189 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13190 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13191 : instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
13192 12 : ShouldThrowOnErrorSetter<void>);
13193 :
13194 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13195 6 : .ToLocalChecked()
13196 6 : ->NewInstance(context.local())
13197 : .ToLocalChecked();
13198 :
13199 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13200 :
13201 : // SLOPPY mode
13202 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13203 6 : CHECK(value->IsFalse());
13204 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13205 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13206 6 : .ToLocalChecked();
13207 6 : CHECK(value->IsFalse());
13208 :
13209 : // STRICT mode
13210 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13211 6 : CHECK(value->IsFalse());
13212 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13213 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13214 6 : .ToLocalChecked();
13215 12 : CHECK(value->IsTrue());
13216 6 : }
13217 :
13218 :
13219 0 : static void ShouldThrowOnErrorQuery(
13220 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
13221 0 : ApiTestFuzzer::Fuzz();
13222 : v8::Isolate* isolate = info.GetIsolate();
13223 : info.GetReturnValue().Set(v8::None);
13224 :
13225 0 : auto context = isolate->GetCurrentContext();
13226 : Local<Boolean> should_throw_on_error_value =
13227 : Boolean::New(isolate, info.ShouldThrowOnError());
13228 0 : CHECK(context->Global()
13229 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
13230 : should_throw_on_error_value)
13231 : .FromJust());
13232 0 : }
13233 :
13234 :
13235 12 : static void ShouldThrowOnErrorDeleter(
13236 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
13237 12 : ApiTestFuzzer::Fuzz();
13238 : v8::Isolate* isolate = info.GetIsolate();
13239 : info.GetReturnValue().Set(v8::True(isolate));
13240 :
13241 12 : auto context = isolate->GetCurrentContext();
13242 : Local<Boolean> should_throw_on_error_value =
13243 : Boolean::New(isolate, info.ShouldThrowOnError());
13244 60 : CHECK(context->Global()
13245 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
13246 : should_throw_on_error_value)
13247 : .FromJust());
13248 12 : }
13249 :
13250 :
13251 12 : static void ShouldThrowOnErrorPropertyEnumerator(
13252 : const v8::PropertyCallbackInfo<v8::Array>& info) {
13253 12 : ApiTestFuzzer::Fuzz();
13254 : v8::Isolate* isolate = info.GetIsolate();
13255 12 : Local<v8::Array> names = v8::Array::New(isolate, 1);
13256 36 : CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
13257 : info.GetReturnValue().Set(names);
13258 :
13259 12 : auto context = isolate->GetCurrentContext();
13260 : Local<Boolean> should_throw_on_error_value =
13261 : Boolean::New(isolate, info.ShouldThrowOnError());
13262 60 : CHECK(context->Global()
13263 : ->Set(isolate->GetCurrentContext(),
13264 : v8_str("should_throw_enumerator"),
13265 : should_throw_on_error_value)
13266 : .FromJust());
13267 12 : }
13268 :
13269 :
13270 28343 : THREADED_TEST(InterceptorShouldThrowOnError) {
13271 6 : LocalContext context;
13272 6 : v8::Isolate* isolate = context->GetIsolate();
13273 12 : v8::HandleScope scope(isolate);
13274 6 : Local<Object> global = context->Global();
13275 :
13276 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
13277 : v8::NamedPropertyHandlerConfiguration handler(
13278 : ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
13279 : ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
13280 : ShouldThrowOnErrorPropertyEnumerator);
13281 6 : interceptor_templ->SetHandler(handler);
13282 :
13283 : Local<v8::Object> instance =
13284 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
13285 :
13286 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13287 :
13288 : // SLOPPY mode
13289 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13290 6 : CHECK(value->IsFalse());
13291 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13292 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13293 6 : .ToLocalChecked();
13294 6 : CHECK(value->IsFalse());
13295 :
13296 12 : v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
13297 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
13298 6 : .ToLocalChecked();
13299 6 : CHECK(value->IsFalse());
13300 :
13301 : v8_compile("Object.getOwnPropertyNames(o)")
13302 6 : ->Run(context.local())
13303 6 : .ToLocalChecked();
13304 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13305 6 : .ToLocalChecked();
13306 6 : CHECK(value->IsFalse());
13307 :
13308 : // STRICT mode
13309 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13310 6 : CHECK(value->IsFalse());
13311 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13312 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13313 6 : .ToLocalChecked();
13314 6 : CHECK(value->IsTrue());
13315 :
13316 12 : v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
13317 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
13318 6 : .ToLocalChecked();
13319 6 : CHECK(value->IsTrue());
13320 :
13321 : v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
13322 6 : ->Run(context.local())
13323 6 : .ToLocalChecked();
13324 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13325 6 : .ToLocalChecked();
13326 12 : CHECK(value->IsFalse());
13327 6 : }
13328 :
13329 55 : static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
13330 :
13331 28342 : TEST(CallHandlerHasNoSideEffect) {
13332 5 : v8::Isolate* isolate = CcTest::isolate();
13333 5 : v8::HandleScope scope(isolate);
13334 10 : LocalContext context;
13335 :
13336 : // Function template with call handler.
13337 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13338 5 : templ->SetCallHandler(EmptyHandler);
13339 30 : CHECK(context->Global()
13340 : ->Set(context.local(), v8_str("f"),
13341 : templ->GetFunction(context.local()).ToLocalChecked())
13342 : .FromJust());
13343 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13344 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
13345 :
13346 : // Side-effect-free version.
13347 5 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
13348 : templ2->SetCallHandler(EmptyHandler, v8::Local<Value>(),
13349 5 : v8::SideEffectType::kHasNoSideEffect);
13350 30 : CHECK(context->Global()
13351 : ->Set(context.local(), v8_str("f2"),
13352 : templ2->GetFunction(context.local()).ToLocalChecked())
13353 : .FromJust());
13354 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
13355 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
13356 5 : }
13357 :
13358 28342 : TEST(FunctionTemplateNewHasNoSideEffect) {
13359 5 : v8::Isolate* isolate = CcTest::isolate();
13360 5 : v8::HandleScope scope(isolate);
13361 10 : LocalContext context;
13362 :
13363 : // Function template with call handler.
13364 : Local<v8::FunctionTemplate> templ =
13365 5 : v8::FunctionTemplate::New(isolate, EmptyHandler);
13366 35 : CHECK(context->Global()
13367 : ->Set(context.local(), v8_str("f"),
13368 : templ->GetFunction(context.local()).ToLocalChecked())
13369 : .FromJust());
13370 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13371 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
13372 :
13373 : // Side-effect-free version.
13374 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(
13375 : isolate, EmptyHandler, v8::Local<Value>(), v8::Local<v8::Signature>(), 0,
13376 5 : v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasNoSideEffect);
13377 35 : CHECK(context->Global()
13378 : ->Set(context.local(), v8_str("f2"),
13379 : templ2->GetFunction(context.local()).ToLocalChecked())
13380 : .FromJust());
13381 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
13382 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
13383 5 : }
13384 :
13385 28342 : TEST(FunctionTemplateNewWithCacheHasNoSideEffect) {
13386 5 : v8::Isolate* isolate = CcTest::isolate();
13387 5 : v8::HandleScope scope(isolate);
13388 10 : LocalContext context;
13389 : v8::Local<v8::Private> priv =
13390 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
13391 :
13392 : // Function template with call handler.
13393 : Local<v8::FunctionTemplate> templ =
13394 5 : v8::FunctionTemplate::NewWithCache(isolate, EmptyHandler, priv);
13395 35 : CHECK(context->Global()
13396 : ->Set(context.local(), v8_str("f"),
13397 : templ->GetFunction(context.local()).ToLocalChecked())
13398 : .FromJust());
13399 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13400 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
13401 :
13402 : // Side-effect-free version.
13403 : Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::NewWithCache(
13404 : isolate, EmptyHandler, priv, v8::Local<Value>(),
13405 5 : v8::Local<v8::Signature>(), 0, v8::SideEffectType::kHasNoSideEffect);
13406 35 : CHECK(context->Global()
13407 : ->Set(context.local(), v8_str("f2"),
13408 : templ2->GetFunction(context.local()).ToLocalChecked())
13409 : .FromJust());
13410 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
13411 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
13412 5 : }
13413 :
13414 28342 : TEST(FunctionNewHasNoSideEffect) {
13415 5 : v8::Isolate* isolate = CcTest::isolate();
13416 5 : v8::HandleScope scope(isolate);
13417 10 : LocalContext context;
13418 :
13419 : // Function with side-effect.
13420 : Local<Function> func =
13421 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
13422 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
13423 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13424 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
13425 :
13426 : // Side-effect-free version.
13427 : Local<Function> func2 =
13428 : Function::New(context.local(), EmptyHandler, Local<Value>(), 0,
13429 : v8::ConstructorBehavior::kAllow,
13430 10 : v8::SideEffectType::kHasNoSideEffect)
13431 5 : .ToLocalChecked();
13432 25 : CHECK(
13433 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
13434 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
13435 10 : v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
13436 5 : }
13437 :
13438 : // These handlers instantiate a function the embedder considers safe in some
13439 : // cases (e.g. "building object wrappers"), but those functions themselves were
13440 : // not explicitly marked as side-effect-free.
13441 5 : static void DefaultConstructHandler(
13442 5 : const v8::FunctionCallbackInfo<v8::Value>& info) {
13443 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
13444 : v8::Context::Scope context_scope(context);
13445 5 : v8::MaybeLocal<v8::Object> instance = Function::New(context, EmptyHandler)
13446 5 : .ToLocalChecked()
13447 5 : ->NewInstance(context, 0, nullptr);
13448 : USE(instance);
13449 5 : }
13450 :
13451 10 : static void NoSideEffectConstructHandler(
13452 10 : const v8::FunctionCallbackInfo<v8::Value>& info) {
13453 10 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
13454 : v8::Context::Scope context_scope(context);
13455 : v8::MaybeLocal<v8::Object> instance =
13456 10 : Function::New(context, EmptyHandler)
13457 10 : .ToLocalChecked()
13458 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
13459 10 : v8::SideEffectType::kHasNoSideEffect);
13460 : USE(instance);
13461 10 : }
13462 :
13463 5 : static void NoSideEffectAndSideEffectConstructHandler(
13464 5 : const v8::FunctionCallbackInfo<v8::Value>& info) {
13465 5 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
13466 : v8::Context::Scope context_scope(context);
13467 : // Constructs an instance in a side-effect-free way, followed by another with
13468 : // side effects.
13469 : v8::MaybeLocal<v8::Object> instance =
13470 5 : Function::New(context, EmptyHandler)
13471 5 : .ToLocalChecked()
13472 : ->NewInstanceWithSideEffectType(context, 0, nullptr,
13473 5 : v8::SideEffectType::kHasNoSideEffect);
13474 5 : v8::MaybeLocal<v8::Object> instance2 = Function::New(context, EmptyHandler)
13475 5 : .ToLocalChecked()
13476 5 : ->NewInstance(context, 0, nullptr);
13477 : USE(instance);
13478 : USE(instance2);
13479 5 : }
13480 :
13481 28342 : TEST(FunctionNewInstanceHasNoSideEffect) {
13482 5 : v8::Isolate* isolate = CcTest::isolate();
13483 5 : v8::HandleScope scope(isolate);
13484 10 : LocalContext context;
13485 :
13486 : // A whitelisted function that creates a new object with both side-effect
13487 : // free/full instantiations. Should throw.
13488 : Local<Function> func0 =
13489 : Function::New(context.local(), NoSideEffectAndSideEffectConstructHandler,
13490 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
13491 10 : v8::SideEffectType::kHasNoSideEffect)
13492 5 : .ToLocalChecked();
13493 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func0).FromJust());
13494 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13495 :
13496 : // A whitelisted function that creates a new object. Should throw.
13497 : Local<Function> func =
13498 : Function::New(context.local(), DefaultConstructHandler, Local<Value>(), 0,
13499 : v8::ConstructorBehavior::kAllow,
13500 10 : v8::SideEffectType::kHasNoSideEffect)
13501 5 : .ToLocalChecked();
13502 25 : CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
13503 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
13504 :
13505 : // A whitelisted function that creates a new object with explicit intent to
13506 : // have no side-effects (e.g. building an "object wrapper"). Should not throw.
13507 : Local<Function> func2 =
13508 : Function::New(context.local(), NoSideEffectConstructHandler,
13509 : Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
13510 10 : v8::SideEffectType::kHasNoSideEffect)
13511 5 : .ToLocalChecked();
13512 25 : CHECK(
13513 : context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
13514 5 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
13515 :
13516 : // Check that side effect skipping did not leak outside to future evaluations.
13517 : Local<Function> func3 =
13518 10 : Function::New(context.local(), EmptyHandler).ToLocalChecked();
13519 25 : CHECK(
13520 : context->Global()->Set(context.local(), v8_str("f3"), func3).FromJust());
13521 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f3()"), true).IsEmpty());
13522 :
13523 : // Check that using side effect free NewInstance works in normal evaluation
13524 : // (without throwOnSideEffect).
13525 10 : v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), false).ToLocalChecked();
13526 5 : }
13527 :
13528 28342 : TEST(CallHandlerAsFunctionHasNoSideEffectNotSupported) {
13529 5 : v8::Isolate* isolate = CcTest::isolate();
13530 5 : v8::HandleScope scope(isolate);
13531 10 : LocalContext context;
13532 :
13533 : // Object template with call as function handler.
13534 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
13535 5 : templ->SetCallAsFunctionHandler(EmptyHandler);
13536 5 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
13537 25 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
13538 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
13539 :
13540 : // Side-effect-free version is not supported.
13541 : i::FunctionTemplateInfo cons = i::FunctionTemplateInfo::cast(
13542 10 : v8::Utils::OpenHandle(*templ)->constructor());
13543 5 : i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
13544 : i::CallHandlerInfo handler_info =
13545 10 : i::CallHandlerInfo::cast(cons->GetInstanceCallHandler());
13546 5 : CHECK(!handler_info->IsSideEffectFreeCallHandlerInfo());
13547 : handler_info->set_map(
13548 5 : i::ReadOnlyRoots(heap).side_effect_free_call_handler_info_map());
13549 15 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
13550 5 : }
13551 :
13552 12 : static void IsConstructHandler(
13553 : const v8::FunctionCallbackInfo<v8::Value>& args) {
13554 12 : ApiTestFuzzer::Fuzz();
13555 : args.GetReturnValue().Set(args.IsConstructCall());
13556 12 : }
13557 :
13558 :
13559 28343 : THREADED_TEST(IsConstructCall) {
13560 6 : v8::Isolate* isolate = CcTest::isolate();
13561 6 : v8::HandleScope scope(isolate);
13562 :
13563 : // Function template with call handler.
13564 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13565 6 : templ->SetCallHandler(IsConstructHandler);
13566 :
13567 12 : LocalContext context;
13568 :
13569 36 : CHECK(context->Global()
13570 : ->Set(context.local(), v8_str("f"),
13571 : templ->GetFunction(context.local()).ToLocalChecked())
13572 : .FromJust());
13573 12 : Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
13574 6 : CHECK(!value->BooleanValue(isolate));
13575 12 : value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
13576 12 : CHECK(value->BooleanValue(isolate));
13577 6 : }
13578 :
13579 48 : static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
13580 24 : ApiTestFuzzer::Fuzz();
13581 : args.GetReturnValue().Set(args.NewTarget());
13582 24 : }
13583 :
13584 28343 : THREADED_TEST(NewTargetHandler) {
13585 6 : v8::Isolate* isolate = CcTest::isolate();
13586 6 : v8::HandleScope scope(isolate);
13587 :
13588 : // Function template with call handler.
13589 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13590 6 : templ->SetCallHandler(NewTargetHandler);
13591 :
13592 12 : LocalContext context;
13593 :
13594 : Local<Function> function =
13595 6 : templ->GetFunction(context.local()).ToLocalChecked();
13596 30 : CHECK(context->Global()
13597 : ->Set(context.local(), v8_str("f"), function)
13598 : .FromJust());
13599 : Local<Value> value = CompileRun("f()");
13600 6 : CHECK(value->IsUndefined());
13601 : value = CompileRun("new f()");
13602 6 : CHECK(value->IsFunction());
13603 6 : CHECK(value == function);
13604 : Local<Value> subclass = CompileRun("var g = class extends f { }; g");
13605 6 : CHECK(subclass->IsFunction());
13606 : value = CompileRun("new g()");
13607 6 : CHECK(value->IsFunction());
13608 6 : CHECK(value == subclass);
13609 : value = CompileRun("Reflect.construct(f, [], Array)");
13610 6 : CHECK(value->IsFunction());
13611 30 : CHECK(value ==
13612 : context->Global()
13613 : ->Get(context.local(), v8_str("Array"))
13614 6 : .ToLocalChecked());
13615 6 : }
13616 :
13617 28343 : THREADED_TEST(ObjectProtoToString) {
13618 6 : v8::Isolate* isolate = CcTest::isolate();
13619 6 : v8::HandleScope scope(isolate);
13620 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13621 6 : templ->SetClassName(v8_str("MyClass"));
13622 :
13623 12 : LocalContext context;
13624 :
13625 6 : Local<String> customized_tostring = v8_str("customized toString");
13626 :
13627 : // Replace Object.prototype.toString
13628 : v8_compile(
13629 : "Object.prototype.toString = function() {"
13630 : " return 'customized toString';"
13631 : "}")
13632 6 : ->Run(context.local())
13633 6 : .ToLocalChecked();
13634 :
13635 : // Normal ToString call should call replaced Object.prototype.toString
13636 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13637 6 : .ToLocalChecked()
13638 6 : ->NewInstance(context.local())
13639 : .ToLocalChecked();
13640 6 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13641 18 : CHECK(value->IsString() &&
13642 : value->Equals(context.local(), customized_tostring).FromJust());
13643 :
13644 : // ObjectProtoToString should not call replace toString function.
13645 6 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13646 18 : CHECK(value->IsString() &&
13647 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13648 :
13649 : // Check global
13650 : value =
13651 24 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13652 18 : CHECK(value->IsString() &&
13653 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13654 :
13655 : // Check ordinary object
13656 : Local<Value> object =
13657 12 : v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13658 : value = object.As<v8::Object>()
13659 6 : ->ObjectProtoToString(context.local())
13660 6 : .ToLocalChecked();
13661 18 : CHECK(value->IsString() &&
13662 6 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13663 6 : }
13664 :
13665 :
13666 28342 : TEST(ObjectProtoToStringES6) {
13667 5 : LocalContext context;
13668 5 : v8::Isolate* isolate = CcTest::isolate();
13669 10 : v8::HandleScope scope(isolate);
13670 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13671 5 : templ->SetClassName(v8_str("MyClass"));
13672 :
13673 5 : Local<String> customized_tostring = v8_str("customized toString");
13674 :
13675 : // Replace Object.prototype.toString
13676 : CompileRun(
13677 : "Object.prototype.toString = function() {"
13678 : " return 'customized toString';"
13679 : "}");
13680 :
13681 : // Normal ToString call should call replaced Object.prototype.toString
13682 5 : Local<v8::Object> instance = templ->GetFunction(context.local())
13683 5 : .ToLocalChecked()
13684 5 : ->NewInstance(context.local())
13685 : .ToLocalChecked();
13686 5 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13687 15 : CHECK(value->IsString() &&
13688 : value->Equals(context.local(), customized_tostring).FromJust());
13689 :
13690 : // ObjectProtoToString should not call replace toString function.
13691 5 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13692 15 : CHECK(value->IsString() &&
13693 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13694 :
13695 : // Check global
13696 : value =
13697 20 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13698 15 : CHECK(value->IsString() &&
13699 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13700 :
13701 : // Check ordinary object
13702 : Local<Value> object = CompileRun("new Object()");
13703 : value = object.As<v8::Object>()
13704 5 : ->ObjectProtoToString(context.local())
13705 5 : .ToLocalChecked();
13706 15 : CHECK(value->IsString() &&
13707 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13708 :
13709 : // Check that ES6 semantics using @@toStringTag work
13710 5 : Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13711 :
13712 : #define TEST_TOSTRINGTAG(type, tag, expected) \
13713 : do { \
13714 : object = CompileRun("new " #type "()"); \
13715 : CHECK(object.As<v8::Object>() \
13716 : ->Set(context.local(), toStringTag, v8_str(#tag)) \
13717 : .FromJust()); \
13718 : value = object.As<v8::Object>() \
13719 : ->ObjectProtoToString(context.local()) \
13720 : .ToLocalChecked(); \
13721 : CHECK(value->IsString() && \
13722 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13723 : .FromJust()); \
13724 : } while (false)
13725 :
13726 30 : TEST_TOSTRINGTAG(Array, Object, Object);
13727 30 : TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13728 30 : TEST_TOSTRINGTAG(Object, Array, Array);
13729 30 : TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13730 30 : TEST_TOSTRINGTAG(Object, Date, Date);
13731 30 : TEST_TOSTRINGTAG(Object, Error, Error);
13732 30 : TEST_TOSTRINGTAG(Object, Function, Function);
13733 30 : TEST_TOSTRINGTAG(Object, Number, Number);
13734 30 : TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13735 30 : TEST_TOSTRINGTAG(Object, String, String);
13736 30 : TEST_TOSTRINGTAG(Object, Foo, Foo);
13737 :
13738 : #undef TEST_TOSTRINGTAG
13739 :
13740 : Local<v8::RegExp> valueRegExp =
13741 5 : v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13742 5 : .ToLocalChecked();
13743 5 : Local<Value> valueNumber = v8_num(123);
13744 5 : Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13745 : Local<v8::Function> valueFunction =
13746 : CompileRun("(function fn() {})").As<v8::Function>();
13747 5 : Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13748 5 : Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13749 5 : Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13750 :
13751 : #define TEST_TOSTRINGTAG(type, tagValue, expected) \
13752 : do { \
13753 : object = CompileRun("new " #type "()"); \
13754 : CHECK(object.As<v8::Object>() \
13755 : ->Set(context.local(), toStringTag, tagValue) \
13756 : .FromJust()); \
13757 : value = object.As<v8::Object>() \
13758 : ->ObjectProtoToString(context.local()) \
13759 : .ToLocalChecked(); \
13760 : CHECK(value->IsString() && \
13761 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13762 : .FromJust()); \
13763 : } while (false)
13764 :
13765 : #define TEST_TOSTRINGTAG_TYPES(tagValue) \
13766 : TEST_TOSTRINGTAG(Array, tagValue, Array); \
13767 : TEST_TOSTRINGTAG(Object, tagValue, Object); \
13768 : TEST_TOSTRINGTAG(Function, tagValue, Function); \
13769 : TEST_TOSTRINGTAG(Date, tagValue, Date); \
13770 : TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13771 : TEST_TOSTRINGTAG(Error, tagValue, Error); \
13772 :
13773 : // Test non-String-valued @@toStringTag
13774 150 : TEST_TOSTRINGTAG_TYPES(valueRegExp);
13775 150 : TEST_TOSTRINGTAG_TYPES(valueNumber);
13776 150 : TEST_TOSTRINGTAG_TYPES(valueSymbol);
13777 150 : TEST_TOSTRINGTAG_TYPES(valueFunction);
13778 150 : TEST_TOSTRINGTAG_TYPES(valueObject);
13779 150 : TEST_TOSTRINGTAG_TYPES(valueNull);
13780 150 : TEST_TOSTRINGTAG_TYPES(valueUndef);
13781 :
13782 : #undef TEST_TOSTRINGTAG
13783 : #undef TEST_TOSTRINGTAG_TYPES
13784 :
13785 : // @@toStringTag getter throws
13786 5 : Local<Value> obj = v8::Object::New(isolate);
13787 : obj.As<v8::Object>()
13788 10 : ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13789 10 : .FromJust();
13790 : {
13791 5 : TryCatch try_catch(isolate);
13792 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13793 5 : CHECK(try_catch.HasCaught());
13794 : }
13795 :
13796 : // @@toStringTag getter does not throw
13797 5 : obj = v8::Object::New(isolate);
13798 : obj.As<v8::Object>()
13799 : ->SetAccessor(context.local(), toStringTag,
13800 15 : SymbolAccessorGetterReturnsDefault, nullptr, v8_str("Test"))
13801 10 : .FromJust();
13802 : {
13803 5 : TryCatch try_catch(isolate);
13804 : value = obj.As<v8::Object>()
13805 5 : ->ObjectProtoToString(context.local())
13806 5 : .ToLocalChecked();
13807 15 : CHECK(value->IsString() &&
13808 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13809 5 : CHECK(!try_catch.HasCaught());
13810 : }
13811 :
13812 : // JS @@toStringTag value
13813 : obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13814 : {
13815 5 : TryCatch try_catch(isolate);
13816 : value = obj.As<v8::Object>()
13817 5 : ->ObjectProtoToString(context.local())
13818 5 : .ToLocalChecked();
13819 15 : CHECK(value->IsString() &&
13820 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13821 5 : CHECK(!try_catch.HasCaught());
13822 : }
13823 :
13824 : // JS @@toStringTag getter throws
13825 : obj = CompileRun(
13826 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13827 : " get: function() { throw 'Test'; }"
13828 : "}); obj");
13829 : {
13830 5 : TryCatch try_catch(isolate);
13831 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13832 5 : CHECK(try_catch.HasCaught());
13833 : }
13834 :
13835 : // JS @@toStringTag getter does not throw
13836 : obj = CompileRun(
13837 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13838 : " get: function() { return 'Test'; }"
13839 : "}); obj");
13840 : {
13841 5 : TryCatch try_catch(isolate);
13842 : value = obj.As<v8::Object>()
13843 5 : ->ObjectProtoToString(context.local())
13844 5 : .ToLocalChecked();
13845 15 : CHECK(value->IsString() &&
13846 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13847 5 : CHECK(!try_catch.HasCaught());
13848 5 : }
13849 5 : }
13850 :
13851 :
13852 28343 : THREADED_TEST(ObjectGetConstructorName) {
13853 6 : v8::Isolate* isolate = CcTest::isolate();
13854 6 : LocalContext context;
13855 12 : v8::HandleScope scope(isolate);
13856 : v8_compile(
13857 : "function Parent() {};"
13858 : "function Child() {};"
13859 : "Child.prototype = new Parent();"
13860 : "Child.prototype.constructor = Child;"
13861 : "var outer = { inner: (0, function() { }) };"
13862 : "var p = new Parent();"
13863 : "var c = new Child();"
13864 : "var x = new outer.inner();"
13865 : "var proto = Child.prototype;")
13866 6 : ->Run(context.local())
13867 6 : .ToLocalChecked();
13868 :
13869 : Local<v8::Value> p =
13870 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13871 30 : CHECK(p->IsObject() &&
13872 : p->ToObject(context.local())
13873 : .ToLocalChecked()
13874 : ->GetConstructorName()
13875 : ->Equals(context.local(), v8_str("Parent"))
13876 : .FromJust());
13877 :
13878 : Local<v8::Value> c =
13879 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13880 30 : CHECK(c->IsObject() &&
13881 : c->ToObject(context.local())
13882 : .ToLocalChecked()
13883 : ->GetConstructorName()
13884 : ->Equals(context.local(), v8_str("Child"))
13885 : .FromJust());
13886 :
13887 : Local<v8::Value> x =
13888 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13889 30 : CHECK(x->IsObject() &&
13890 : x->ToObject(context.local())
13891 : .ToLocalChecked()
13892 : ->GetConstructorName()
13893 : ->Equals(context.local(), v8_str("outer.inner"))
13894 : .FromJust());
13895 :
13896 : Local<v8::Value> child_prototype =
13897 30 : context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13898 30 : CHECK(child_prototype->IsObject() &&
13899 : child_prototype->ToObject(context.local())
13900 : .ToLocalChecked()
13901 : ->GetConstructorName()
13902 : ->Equals(context.local(), v8_str("Parent"))
13903 6 : .FromJust());
13904 6 : }
13905 :
13906 :
13907 28343 : THREADED_TEST(SubclassGetConstructorName) {
13908 6 : v8::Isolate* isolate = CcTest::isolate();
13909 6 : LocalContext context;
13910 12 : v8::HandleScope scope(isolate);
13911 : v8_compile(
13912 : "\"use strict\";"
13913 : "class Parent {}"
13914 : "class Child extends Parent {}"
13915 : "var p = new Parent();"
13916 : "var c = new Child();")
13917 6 : ->Run(context.local())
13918 6 : .ToLocalChecked();
13919 :
13920 : Local<v8::Value> p =
13921 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13922 30 : CHECK(p->IsObject() &&
13923 : p->ToObject(context.local())
13924 : .ToLocalChecked()
13925 : ->GetConstructorName()
13926 : ->Equals(context.local(), v8_str("Parent"))
13927 : .FromJust());
13928 :
13929 : Local<v8::Value> c =
13930 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13931 30 : CHECK(c->IsObject() &&
13932 : c->ToObject(context.local())
13933 : .ToLocalChecked()
13934 : ->GetConstructorName()
13935 : ->Equals(context.local(), v8_str("Child"))
13936 6 : .FromJust());
13937 6 : }
13938 :
13939 :
13940 : bool ApiTestFuzzer::fuzzing_ = false;
13941 28337 : v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13942 : int ApiTestFuzzer::active_tests_;
13943 : int ApiTestFuzzer::tests_being_run_;
13944 : int ApiTestFuzzer::current_;
13945 :
13946 :
13947 : // We are in a callback and want to switch to another thread (if we
13948 : // are currently running the thread fuzzing test).
13949 470743 : void ApiTestFuzzer::Fuzz() {
13950 941486 : if (!fuzzing_) return;
13951 77218 : ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13952 77218 : test->ContextSwitch();
13953 : }
13954 :
13955 :
13956 : // Let the next thread go. Since it is also waiting on the V8 lock it may
13957 : // not start immediately.
13958 77698 : bool ApiTestFuzzer::NextThread() {
13959 77698 : int test_position = GetNextTestNumber();
13960 77698 : const char* test_name = RegisterThreadedTest::nth(current_)->name();
13961 77698 : if (test_position == current_) {
13962 : if (kLogThreading)
13963 : printf("Stay with %s\n", test_name);
13964 : return false;
13965 : }
13966 : if (kLogThreading) {
13967 : printf("Switch from %s to %s\n",
13968 : test_name,
13969 : RegisterThreadedTest::nth(test_position)->name());
13970 : }
13971 23643 : current_ = test_position;
13972 23643 : RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13973 23643 : return true;
13974 : }
13975 :
13976 :
13977 480 : void ApiTestFuzzer::Run() {
13978 : // When it is our turn...
13979 480 : gate_.Wait();
13980 : {
13981 : // ... get the V8 lock and start running the test.
13982 480 : v8::Locker locker(CcTest::isolate());
13983 480 : CallTest();
13984 : }
13985 : // This test finished.
13986 480 : active_ = false;
13987 480 : active_tests_--;
13988 : // If it was the last then signal that fact.
13989 480 : if (active_tests_ == 0) {
13990 8 : all_tests_done_.Signal();
13991 : } else {
13992 : // Otherwise select a new test and start that.
13993 472 : NextThread();
13994 : }
13995 480 : }
13996 :
13997 :
13998 : static unsigned linear_congruential_generator;
13999 :
14000 :
14001 8 : void ApiTestFuzzer::SetUp(PartOfTest part) {
14002 8 : linear_congruential_generator = i::FLAG_testing_prng_seed;
14003 8 : fuzzing_ = true;
14004 : int count = RegisterThreadedTest::count();
14005 8 : int start = count * part / (LAST_PART + 1);
14006 8 : int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
14007 8 : active_tests_ = tests_being_run_ = end - start + 1;
14008 488 : for (int i = 0; i < tests_being_run_; i++) {
14009 480 : RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
14010 : }
14011 480 : for (int i = 0; i < active_tests_; i++) {
14012 480 : RegisterThreadedTest::nth(i)->fuzzer_->Start();
14013 : }
14014 8 : }
14015 :
14016 :
14017 : static void CallTestNumber(int test_number) {
14018 480 : (RegisterThreadedTest::nth(test_number)->callback())();
14019 : }
14020 :
14021 :
14022 0 : void ApiTestFuzzer::RunAllTests() {
14023 : // Set off the first test.
14024 8 : current_ = -1;
14025 8 : NextThread();
14026 : // Wait till they are all done.
14027 8 : all_tests_done_.Wait();
14028 0 : }
14029 :
14030 :
14031 77698 : int ApiTestFuzzer::GetNextTestNumber() {
14032 : int next_test;
14033 3251552 : do {
14034 3251552 : next_test = (linear_congruential_generator >> 16) % tests_being_run_;
14035 3251552 : linear_congruential_generator *= 1664525u;
14036 3251552 : linear_congruential_generator += 1013904223u;
14037 3251552 : } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
14038 77698 : return next_test;
14039 : }
14040 :
14041 :
14042 77218 : void ApiTestFuzzer::ContextSwitch() {
14043 : // If the new thread is the same as the current thread there is nothing to do.
14044 77218 : if (NextThread()) {
14045 : // Now it can start.
14046 23163 : v8::Unlocker unlocker(CcTest::isolate());
14047 : // Wait till someone starts us again.
14048 23163 : gate_.Wait();
14049 : // And we're off.
14050 : }
14051 77218 : }
14052 :
14053 :
14054 8 : void ApiTestFuzzer::TearDown() {
14055 8 : fuzzing_ = false;
14056 7696 : for (int i = 0; i < RegisterThreadedTest::count(); i++) {
14057 3840 : ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
14058 3840 : if (fuzzer != nullptr) fuzzer->Join();
14059 : }
14060 8 : }
14061 :
14062 480 : void ApiTestFuzzer::CallTest() {
14063 480 : v8::Isolate::Scope scope(CcTest::isolate());
14064 : if (kLogThreading)
14065 : printf("Start test %s #%d\n",
14066 : RegisterThreadedTest::nth(test_number_)->name(), test_number_);
14067 480 : CallTestNumber(test_number_);
14068 : if (kLogThreading)
14069 : printf("End test %s #%d\n", RegisterThreadedTest::nth(test_number_)->name(),
14070 : test_number_);
14071 480 : }
14072 :
14073 : #define THREADING_TEST(INDEX, NAME) \
14074 : TEST(Threading##INDEX) { \
14075 : ApiTestFuzzer::SetUp(ApiTestFuzzer::NAME); \
14076 : ApiTestFuzzer::RunAllTests(); \
14077 : ApiTestFuzzer::TearDown(); \
14078 : }
14079 :
14080 28339 : THREADING_TEST(1, FIRST_PART)
14081 28339 : THREADING_TEST(2, SECOND_PART)
14082 28339 : THREADING_TEST(3, THIRD_PART)
14083 28339 : THREADING_TEST(4, FOURTH_PART)
14084 28339 : THREADING_TEST(5, FIFTH_PART)
14085 28339 : THREADING_TEST(6, SIXTH_PART)
14086 28339 : THREADING_TEST(7, SEVENTH_PART)
14087 28339 : THREADING_TEST(8, EIGHTH_PART)
14088 :
14089 : #undef THREADING_TEST
14090 :
14091 10 : static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
14092 : v8::Isolate* isolate = args.GetIsolate();
14093 5 : CHECK(v8::Locker::IsLocked(isolate));
14094 5 : ApiTestFuzzer::Fuzz();
14095 : v8::Unlocker unlocker(isolate);
14096 : const char* code = "throw 7;";
14097 : {
14098 : v8::Locker nested_locker(isolate);
14099 10 : v8::HandleScope scope(isolate);
14100 : v8::Local<Value> exception;
14101 : {
14102 5 : v8::TryCatch try_catch(isolate);
14103 : v8::Local<Value> value = CompileRun(code);
14104 5 : CHECK(value.IsEmpty());
14105 5 : CHECK(try_catch.HasCaught());
14106 : // Make sure to wrap the exception in a new handle because
14107 : // the handle returned from the TryCatch is destroyed
14108 : // when the TryCatch is destroyed.
14109 10 : exception = Local<Value>::New(isolate, try_catch.Exception());
14110 : }
14111 10 : args.GetIsolate()->ThrowException(exception);
14112 5 : }
14113 5 : }
14114 :
14115 :
14116 15 : static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
14117 5 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14118 5 : ApiTestFuzzer::Fuzz();
14119 5 : v8::Unlocker unlocker(CcTest::isolate());
14120 : const char* code = "throw 7;";
14121 : {
14122 5 : v8::Locker nested_locker(CcTest::isolate());
14123 10 : v8::HandleScope scope(args.GetIsolate());
14124 : v8::Local<Value> value = CompileRun(code);
14125 5 : CHECK(value.IsEmpty());
14126 10 : args.GetReturnValue().Set(v8_str("foo"));
14127 5 : }
14128 5 : }
14129 :
14130 :
14131 : // These are locking tests that don't need to be run again
14132 : // as part of the locking aggregation tests.
14133 28342 : TEST(NestedLockers) {
14134 5 : v8::Isolate* isolate = CcTest::isolate();
14135 : v8::Locker locker(isolate);
14136 5 : CHECK(v8::Locker::IsLocked(isolate));
14137 10 : LocalContext env;
14138 10 : v8::HandleScope scope(env->GetIsolate());
14139 : Local<v8::FunctionTemplate> fun_templ =
14140 5 : v8::FunctionTemplate::New(isolate, ThrowInJS);
14141 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
14142 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
14143 : Local<Script> script = v8_compile("(function () {"
14144 : " try {"
14145 : " throw_in_js();"
14146 : " return 42;"
14147 : " } catch (e) {"
14148 : " return e * 13;"
14149 : " }"
14150 : "})();");
14151 15 : CHECK_EQ(91, script->Run(env.local())
14152 : .ToLocalChecked()
14153 : ->Int32Value(env.local())
14154 5 : .FromJust());
14155 5 : }
14156 :
14157 :
14158 : // These are locking tests that don't need to be run again
14159 : // as part of the locking aggregation tests.
14160 28342 : TEST(NestedLockersNoTryCatch) {
14161 5 : v8::Locker locker(CcTest::isolate());
14162 10 : LocalContext env;
14163 10 : v8::HandleScope scope(env->GetIsolate());
14164 : Local<v8::FunctionTemplate> fun_templ =
14165 5 : v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
14166 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
14167 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
14168 : Local<Script> script = v8_compile("(function () {"
14169 : " try {"
14170 : " throw_in_js();"
14171 : " return 42;"
14172 : " } catch (e) {"
14173 : " return e * 13;"
14174 : " }"
14175 : "})();");
14176 15 : CHECK_EQ(91, script->Run(env.local())
14177 : .ToLocalChecked()
14178 : ->Int32Value(env.local())
14179 5 : .FromJust());
14180 5 : }
14181 :
14182 :
14183 28343 : THREADED_TEST(RecursiveLocking) {
14184 6 : v8::Locker locker(CcTest::isolate());
14185 : {
14186 6 : v8::Locker locker2(CcTest::isolate());
14187 6 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14188 6 : }
14189 6 : }
14190 :
14191 :
14192 12 : static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
14193 12 : ApiTestFuzzer::Fuzz();
14194 24 : v8::Unlocker unlocker(CcTest::isolate());
14195 12 : }
14196 :
14197 :
14198 28343 : THREADED_TEST(LockUnlockLock) {
14199 : {
14200 6 : v8::Locker locker(CcTest::isolate());
14201 12 : v8::HandleScope scope(CcTest::isolate());
14202 12 : LocalContext env;
14203 : Local<v8::FunctionTemplate> fun_templ =
14204 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14205 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
14206 30 : CHECK(env->Global()
14207 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
14208 : .FromJust());
14209 : Local<Script> script = v8_compile("(function () {"
14210 : " unlock_for_a_moment();"
14211 : " return 42;"
14212 : "})();");
14213 18 : CHECK_EQ(42, script->Run(env.local())
14214 : .ToLocalChecked()
14215 : ->Int32Value(env.local())
14216 6 : .FromJust());
14217 : }
14218 : {
14219 6 : v8::Locker locker(CcTest::isolate());
14220 12 : v8::HandleScope scope(CcTest::isolate());
14221 12 : LocalContext env;
14222 : Local<v8::FunctionTemplate> fun_templ =
14223 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14224 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
14225 30 : CHECK(env->Global()
14226 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
14227 : .FromJust());
14228 : Local<Script> script = v8_compile("(function () {"
14229 : " unlock_for_a_moment();"
14230 : " return 42;"
14231 : "})();");
14232 18 : CHECK_EQ(42, script->Run(env.local())
14233 : .ToLocalChecked()
14234 : ->Int32Value(env.local())
14235 6 : .FromJust());
14236 : }
14237 6 : }
14238 :
14239 :
14240 130 : static int GetGlobalObjectsCount() {
14241 : int count = 0;
14242 130 : i::HeapIterator it(CcTest::heap());
14243 1398494 : for (i::HeapObject object = it.next(); !object.is_null();
14244 : object = it.next()) {
14245 699117 : if (object->IsJSGlobalObject()) {
14246 30 : i::JSGlobalObject g = i::JSGlobalObject::cast(object);
14247 : // Skip dummy global object.
14248 30 : if (g->global_dictionary()->NumberOfElements() != 0) {
14249 30 : count++;
14250 : }
14251 : }
14252 : }
14253 130 : return count;
14254 : }
14255 :
14256 :
14257 100 : static void CheckSurvivingGlobalObjectsCount(int expected) {
14258 : // We need to collect all garbage twice to be sure that everything
14259 : // has been collected. This is because inline caches are cleared in
14260 : // the first garbage collection but some of the maps have already
14261 : // been marked at that point. Therefore some of the maps are not
14262 : // collected until the second garbage collection.
14263 100 : CcTest::CollectAllGarbage();
14264 100 : CcTest::CollectAllGarbage();
14265 100 : int count = GetGlobalObjectsCount();
14266 100 : CHECK_EQ(expected, count);
14267 100 : }
14268 :
14269 :
14270 28342 : TEST(DontLeakGlobalObjects) {
14271 : // Regression test for issues 1139850 and 1174891.
14272 :
14273 5 : i::FLAG_expose_gc = true;
14274 5 : v8::V8::Initialize();
14275 :
14276 30 : for (int i = 0; i < 5; i++) {
14277 25 : { v8::HandleScope scope(CcTest::isolate());
14278 25 : LocalContext context;
14279 : }
14280 25 : CcTest::isolate()->ContextDisposedNotification();
14281 25 : CheckSurvivingGlobalObjectsCount(0);
14282 :
14283 25 : { v8::HandleScope scope(CcTest::isolate());
14284 50 : LocalContext context;
14285 75 : v8_compile("Date")->Run(context.local()).ToLocalChecked();
14286 : }
14287 25 : CcTest::isolate()->ContextDisposedNotification();
14288 25 : CheckSurvivingGlobalObjectsCount(0);
14289 :
14290 25 : { v8::HandleScope scope(CcTest::isolate());
14291 50 : LocalContext context;
14292 75 : v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
14293 : }
14294 25 : CcTest::isolate()->ContextDisposedNotification();
14295 25 : CheckSurvivingGlobalObjectsCount(0);
14296 :
14297 25 : { v8::HandleScope scope(CcTest::isolate());
14298 25 : const char* extension_list[] = { "v8/gc" };
14299 : v8::ExtensionConfiguration extensions(1, extension_list);
14300 50 : LocalContext context(&extensions);
14301 75 : v8_compile("gc();")->Run(context.local()).ToLocalChecked();
14302 : }
14303 25 : CcTest::isolate()->ContextDisposedNotification();
14304 25 : CheckSurvivingGlobalObjectsCount(0);
14305 : }
14306 5 : }
14307 :
14308 :
14309 28342 : TEST(CopyablePersistent) {
14310 5 : LocalContext context;
14311 5 : v8::Isolate* isolate = context->GetIsolate();
14312 25 : i::GlobalHandles* globals =
14313 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14314 : int initial_handles = globals->global_handles_count();
14315 : typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14316 : CopyableObject;
14317 : {
14318 : CopyableObject handle1;
14319 : {
14320 5 : v8::HandleScope scope(isolate);
14321 10 : handle1.Reset(isolate, v8::Object::New(isolate));
14322 : }
14323 5 : CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14324 : CopyableObject handle2;
14325 : handle2 = handle1;
14326 5 : CHECK(handle1 == handle2);
14327 5 : CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14328 : CopyableObject handle3(handle2);
14329 5 : CHECK(handle1 == handle3);
14330 5 : CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14331 : }
14332 : // Verify autodispose
14333 5 : CHECK_EQ(initial_handles, globals->global_handles_count());
14334 5 : }
14335 :
14336 :
14337 5 : static void WeakApiCallback(
14338 10 : const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
14339 : data.GetParameter()->Reset();
14340 5 : delete data.GetParameter();
14341 5 : }
14342 :
14343 :
14344 28342 : TEST(WeakCallbackApi) {
14345 5 : LocalContext context;
14346 5 : v8::Isolate* isolate = context->GetIsolate();
14347 10 : i::GlobalHandles* globals =
14348 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14349 : int initial_handles = globals->global_handles_count();
14350 : {
14351 5 : v8::HandleScope scope(isolate);
14352 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
14353 25 : CHECK(
14354 : obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
14355 : .FromJust());
14356 : v8::Persistent<v8::Object>* handle =
14357 5 : new v8::Persistent<v8::Object>(isolate, obj);
14358 : handle->SetWeak<v8::Persistent<v8::Object>>(
14359 5 : handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
14360 : }
14361 5 : CcTest::PreciseCollectAllGarbage();
14362 : // Verify disposed.
14363 5 : CHECK_EQ(initial_handles, globals->global_handles_count());
14364 5 : }
14365 :
14366 :
14367 28337 : v8::Persistent<v8::Object> some_object;
14368 28337 : v8::Persistent<v8::Object> bad_handle;
14369 :
14370 :
14371 6 : void NewPersistentHandleCallback2(
14372 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14373 6 : v8::HandleScope scope(data.GetIsolate());
14374 6 : bad_handle.Reset(data.GetIsolate(), some_object);
14375 6 : }
14376 :
14377 :
14378 6 : void NewPersistentHandleCallback1(
14379 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14380 : data.GetParameter()->Reset();
14381 : data.SetSecondPassCallback(NewPersistentHandleCallback2);
14382 6 : }
14383 :
14384 :
14385 28343 : THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14386 6 : LocalContext context;
14387 6 : v8::Isolate* isolate = context->GetIsolate();
14388 :
14389 : v8::Persistent<v8::Object> handle1, handle2;
14390 : {
14391 6 : v8::HandleScope scope(isolate);
14392 12 : some_object.Reset(isolate, v8::Object::New(isolate));
14393 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14394 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14395 : }
14396 : // Note: order is implementation dependent alas: currently
14397 : // global handle nodes are processed by PostGarbageCollectionProcessing
14398 : // in reverse allocation order, so if second allocated handle is deleted,
14399 : // weak callback of the first handle would be able to 'reallocate' it.
14400 : handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
14401 : v8::WeakCallbackType::kParameter);
14402 : handle2.Reset();
14403 6 : CcTest::CollectAllGarbage();
14404 6 : }
14405 :
14406 :
14407 28337 : v8::Persistent<v8::Object> to_be_disposed;
14408 :
14409 :
14410 6 : void DisposeAndForceGcCallback2(
14411 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14412 : to_be_disposed.Reset();
14413 6 : CcTest::CollectAllGarbage();
14414 6 : }
14415 :
14416 :
14417 6 : void DisposeAndForceGcCallback1(
14418 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14419 : data.GetParameter()->Reset();
14420 : data.SetSecondPassCallback(DisposeAndForceGcCallback2);
14421 6 : }
14422 :
14423 :
14424 28343 : THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14425 6 : LocalContext context;
14426 6 : v8::Isolate* isolate = context->GetIsolate();
14427 :
14428 : v8::Persistent<v8::Object> handle1, handle2;
14429 : {
14430 6 : v8::HandleScope scope(isolate);
14431 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14432 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14433 : }
14434 : handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
14435 : v8::WeakCallbackType::kParameter);
14436 : to_be_disposed.Reset(isolate, handle2);
14437 6 : CcTest::CollectAllGarbage();
14438 6 : }
14439 :
14440 6 : void DisposingCallback(
14441 6 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14442 : data.GetParameter()->Reset();
14443 6 : }
14444 :
14445 6 : void HandleCreatingCallback2(
14446 18 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14447 6 : v8::HandleScope scope(data.GetIsolate());
14448 12 : v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
14449 6 : }
14450 :
14451 :
14452 6 : void HandleCreatingCallback1(
14453 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14454 : data.GetParameter()->Reset();
14455 : data.SetSecondPassCallback(HandleCreatingCallback2);
14456 6 : }
14457 :
14458 :
14459 28343 : THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14460 6 : v8::Locker locker(CcTest::isolate());
14461 12 : LocalContext context;
14462 6 : v8::Isolate* isolate = context->GetIsolate();
14463 :
14464 : v8::Persistent<v8::Object> handle1, handle2, handle3;
14465 : {
14466 6 : v8::HandleScope scope(isolate);
14467 12 : handle3.Reset(isolate, v8::Object::New(isolate));
14468 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14469 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14470 : }
14471 : handle2.SetWeak(&handle2, DisposingCallback,
14472 : v8::WeakCallbackType::kParameter);
14473 : handle3.SetWeak(&handle3, HandleCreatingCallback1,
14474 : v8::WeakCallbackType::kParameter);
14475 6 : CcTest::CollectAllGarbage();
14476 12 : EmptyMessageQueues(isolate);
14477 6 : }
14478 :
14479 :
14480 28343 : THREADED_TEST(CheckForCrossContextObjectLiterals) {
14481 6 : v8::V8::Initialize();
14482 :
14483 : const int nof = 2;
14484 : const char* sources[nof] = {
14485 : "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14486 : "Object()"
14487 6 : };
14488 :
14489 18 : for (int i = 0; i < nof; i++) {
14490 12 : const char* source = sources[i];
14491 12 : { v8::HandleScope scope(CcTest::isolate());
14492 24 : LocalContext context;
14493 12 : CompileRun(source);
14494 : }
14495 12 : { v8::HandleScope scope(CcTest::isolate());
14496 24 : LocalContext context;
14497 12 : CompileRun(source);
14498 : }
14499 : }
14500 6 : }
14501 :
14502 :
14503 6 : static v8::Local<Value> NestedScope(v8::Local<Context> env) {
14504 6 : v8::EscapableHandleScope inner(env->GetIsolate());
14505 6 : env->Enter();
14506 6 : v8::Local<Value> three = v8_num(3);
14507 : v8::Local<Value> value = inner.Escape(three);
14508 6 : env->Exit();
14509 12 : return value;
14510 : }
14511 :
14512 :
14513 28343 : THREADED_TEST(NestedHandleScopeAndContexts) {
14514 6 : v8::Isolate* isolate = CcTest::isolate();
14515 6 : v8::HandleScope outer(isolate);
14516 6 : v8::Local<Context> env = Context::New(isolate);
14517 6 : env->Enter();
14518 6 : v8::Local<Value> value = NestedScope(env);
14519 6 : v8::Local<String> str(value->ToString(env).ToLocalChecked());
14520 6 : CHECK(!str.IsEmpty());
14521 6 : env->Exit();
14522 6 : }
14523 :
14524 : static v8::base::HashMap* code_map = nullptr;
14525 : static v8::base::HashMap* jitcode_line_info = nullptr;
14526 : static int saw_bar = 0;
14527 : static int move_events = 0;
14528 :
14529 :
14530 5381 : static bool FunctionNameIs(const char* expected,
14531 : const v8::JitCodeEvent* event) {
14532 : // Log lines for functions are of the general form:
14533 : // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
14534 : // where the type is one of "*", "~" or "".
14535 : static const char* kPreamble;
14536 5381 : if (!i::FLAG_lazy) {
14537 0 : kPreamble = "Function:";
14538 : } else {
14539 5381 : kPreamble = "LazyCompile:";
14540 : }
14541 5381 : static size_t kPreambleLen = strlen(kPreamble);
14542 :
14543 10707 : if (event->name.len < kPreambleLen ||
14544 5326 : strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14545 : return false;
14546 : }
14547 :
14548 153 : const char* tail = event->name.str + kPreambleLen;
14549 153 : size_t tail_len = event->name.len - kPreambleLen;
14550 153 : size_t expected_len = strlen(expected);
14551 153 : if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14552 148 : --tail_len;
14553 148 : ++tail;
14554 : }
14555 :
14556 : // Check for tails like 'bar :1'.
14557 285 : if (tail_len > expected_len + 2 &&
14558 264 : tail[expected_len] == ' ' &&
14559 264 : tail[expected_len + 1] == ':' &&
14560 264 : tail[expected_len + 2] &&
14561 132 : !strncmp(tail, expected, expected_len)) {
14562 : return true;
14563 : }
14564 :
14565 87 : if (tail_len != expected_len)
14566 : return false;
14567 :
14568 21 : return strncmp(tail, expected, expected_len) == 0;
14569 : }
14570 :
14571 :
14572 7662 : static void event_handler(const v8::JitCodeEvent* event) {
14573 7662 : CHECK_NOT_NULL(event);
14574 7662 : CHECK_NOT_NULL(code_map);
14575 7662 : CHECK_NOT_NULL(jitcode_line_info);
14576 :
14577 : class DummyJitCodeLineInfo {
14578 : };
14579 :
14580 7662 : switch (event->type) {
14581 : case v8::JitCodeEvent::CODE_ADDED: {
14582 5381 : CHECK_NOT_NULL(event->code_start);
14583 5381 : CHECK_NE(0, static_cast<int>(event->code_len));
14584 5381 : CHECK_NOT_NULL(event->name.str);
14585 : v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
14586 5381 : event->code_start, i::ComputePointerHash(event->code_start));
14587 5381 : entry->value = reinterpret_cast<void*>(event->code_len);
14588 :
14589 5381 : if (FunctionNameIs("bar", event)) {
14590 66 : ++saw_bar;
14591 : }
14592 : }
14593 : break;
14594 :
14595 : case v8::JitCodeEvent::CODE_MOVED: {
14596 171 : uint32_t hash = i::ComputePointerHash(event->code_start);
14597 : // We would like to never see code move that we haven't seen before,
14598 : // but the code creation event does not happen until the line endings
14599 : // have been calculated (this is so that we can report the line in the
14600 : // script at which the function source is found, see
14601 : // Compiler::RecordFunctionCompilation) and the line endings
14602 : // calculations can cause a GC, which can move the newly created code
14603 : // before its existence can be logged.
14604 : v8::base::HashMap::Entry* entry =
14605 171 : code_map->Lookup(event->code_start, hash);
14606 171 : if (entry != nullptr) {
14607 171 : ++move_events;
14608 :
14609 171 : CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14610 171 : code_map->Remove(event->code_start, hash);
14611 :
14612 : entry = code_map->LookupOrInsert(
14613 : event->new_code_start,
14614 342 : i::ComputePointerHash(event->new_code_start));
14615 171 : entry->value = reinterpret_cast<void*>(event->code_len);
14616 : }
14617 : }
14618 : break;
14619 :
14620 : case v8::JitCodeEvent::CODE_REMOVED:
14621 : // Object/code removal events are currently not dispatched from the GC.
14622 0 : UNREACHABLE();
14623 :
14624 : // For CODE_START_LINE_INFO_RECORDING event, we will create one
14625 : // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14626 : // record it in jitcode_line_info.
14627 : case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14628 180 : DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14629 : v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14630 180 : temp_event->user_data = line_info;
14631 : v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14632 360 : line_info, i::ComputePointerHash(line_info));
14633 180 : entry->value = reinterpret_cast<void*>(line_info);
14634 : }
14635 180 : break;
14636 : // For these two events, we will check whether the event->user_data
14637 : // data structure is created before during CODE_START_LINE_INFO_RECORDING
14638 : // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14639 : case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14640 180 : CHECK_NOT_NULL(event->user_data);
14641 : uint32_t hash = i::ComputePointerHash(event->user_data);
14642 : v8::base::HashMap::Entry* entry =
14643 180 : jitcode_line_info->Lookup(event->user_data, hash);
14644 180 : CHECK_NOT_NULL(entry);
14645 180 : delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14646 : }
14647 180 : break;
14648 :
14649 : case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14650 1750 : CHECK_NOT_NULL(event->user_data);
14651 : uint32_t hash = i::ComputePointerHash(event->user_data);
14652 : v8::base::HashMap::Entry* entry =
14653 1750 : jitcode_line_info->Lookup(event->user_data, hash);
14654 1750 : CHECK_NOT_NULL(entry);
14655 : }
14656 : break;
14657 :
14658 : default:
14659 : // Impossible event.
14660 0 : UNREACHABLE();
14661 : }
14662 7662 : }
14663 :
14664 :
14665 28342 : UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14666 5 : i::FLAG_stress_compaction = true;
14667 5 : i::FLAG_incremental_marking = false;
14668 5 : if (i::FLAG_never_compact) return;
14669 : const char* script =
14670 : "function bar() {"
14671 : " var sum = 0;"
14672 : " for (i = 0; i < 10; ++i)"
14673 : " sum = foo(i);"
14674 : " return sum;"
14675 : "}"
14676 : "function foo(i) { return i; };"
14677 : "bar();";
14678 :
14679 : // Run this test in a new isolate to make sure we don't
14680 : // have remnants of state from other code.
14681 : v8::Isolate::CreateParams create_params;
14682 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14683 55 : v8::Isolate* isolate = v8::Isolate::New(create_params);
14684 5 : isolate->Enter();
14685 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14686 5 : i::Heap* heap = i_isolate->heap();
14687 :
14688 : // Start with a clean slate.
14689 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14690 :
14691 : {
14692 5 : v8::HandleScope scope(isolate);
14693 : v8::base::HashMap code;
14694 5 : code_map = &code;
14695 :
14696 : v8::base::HashMap lineinfo;
14697 5 : jitcode_line_info = &lineinfo;
14698 :
14699 5 : saw_bar = 0;
14700 5 : move_events = 0;
14701 :
14702 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14703 :
14704 : // Generate new code objects sparsely distributed across several
14705 : // different fragmented code-space pages.
14706 : const int kIterations = 10;
14707 55 : for (int i = 0; i < kIterations; ++i) {
14708 : LocalContext env(isolate);
14709 : i::AlwaysAllocateScope always_allocate(i_isolate);
14710 : CompileRun(script);
14711 :
14712 : // Keep a strong reference to the code object in the handle scope.
14713 : i::Handle<i::JSFunction> bar(i::Handle<i::JSFunction>::cast(
14714 : v8::Utils::OpenHandle(*env->Global()
14715 200 : ->Get(env.local(), v8_str("bar"))
14716 100 : .ToLocalChecked())));
14717 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
14718 : v8::Utils::OpenHandle(*env->Global()
14719 200 : ->Get(env.local(), v8_str("foo"))
14720 100 : .ToLocalChecked())));
14721 :
14722 : i::PagedSpace* foo_owning_space = reinterpret_cast<i::PagedSpace*>(
14723 100 : i::Page::FromHeapObject(foo->abstract_code())->owner());
14724 : i::PagedSpace* bar_owning_space = reinterpret_cast<i::PagedSpace*>(
14725 100 : i::Page::FromHeapObject(bar->abstract_code())->owner());
14726 50 : CHECK_EQ(foo_owning_space, bar_owning_space);
14727 50 : i::heap::SimulateFullSpace(foo_owning_space);
14728 :
14729 : // Clear the compilation cache to get more wastage.
14730 50 : reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14731 50 : }
14732 :
14733 : // Force code movement.
14734 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14735 :
14736 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14737 :
14738 5 : CHECK_LE(kIterations, saw_bar);
14739 5 : CHECK_LT(0, move_events);
14740 :
14741 5 : code_map = nullptr;
14742 10 : jitcode_line_info = nullptr;
14743 : }
14744 :
14745 5 : isolate->Exit();
14746 5 : isolate->Dispose();
14747 :
14748 : // Do this in a new isolate.
14749 5 : isolate = v8::Isolate::New(create_params);
14750 5 : isolate->Enter();
14751 :
14752 : // Verify that we get callbacks for existing code objects when we
14753 : // request enumeration of existing code.
14754 : {
14755 5 : v8::HandleScope scope(isolate);
14756 5 : LocalContext env(isolate);
14757 : CompileRun(script);
14758 :
14759 : // Now get code through initial iteration.
14760 : v8::base::HashMap code;
14761 5 : code_map = &code;
14762 :
14763 : v8::base::HashMap lineinfo;
14764 5 : jitcode_line_info = &lineinfo;
14765 :
14766 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14767 5 : event_handler);
14768 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14769 :
14770 5 : jitcode_line_info = nullptr;
14771 : // We expect that we got some events. Note that if we could get code removal
14772 : // notifications, we could compare two collections, one created by listening
14773 : // from the time of creation of an isolate, and the other by subscribing
14774 : // with EnumExisting.
14775 5 : CHECK_LT(0u, code.occupancy());
14776 :
14777 10 : code_map = nullptr;
14778 : }
14779 :
14780 5 : isolate->Exit();
14781 5 : isolate->Dispose();
14782 : }
14783 :
14784 28342 : TEST(ExternalAllocatedMemory) {
14785 5 : v8::Isolate* isolate = CcTest::isolate();
14786 5 : v8::HandleScope outer(isolate);
14787 5 : v8::Local<Context> env(Context::New(isolate));
14788 5 : CHECK(!env.IsEmpty());
14789 : const int64_t kSize = 1024*1024;
14790 : int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14791 5 : CHECK_EQ(baseline + kSize,
14792 : isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14793 5 : CHECK_EQ(baseline,
14794 : isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14795 : const int64_t kTriggerGCSize =
14796 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14797 5 : CHECK_EQ(baseline + kTriggerGCSize,
14798 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14799 10 : CHECK_EQ(baseline,
14800 5 : isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14801 5 : }
14802 :
14803 :
14804 28342 : TEST(Regress51719) {
14805 5 : i::FLAG_incremental_marking = false;
14806 5 : CcTest::InitializeVM();
14807 :
14808 : const int64_t kTriggerGCSize =
14809 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14810 5 : v8::Isolate* isolate = CcTest::isolate();
14811 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14812 5 : }
14813 :
14814 : // Regression test for issue 54, object templates with embedder fields
14815 : // but no accessors or interceptors did not get their embedder field
14816 : // count set on instances.
14817 28343 : THREADED_TEST(Regress54) {
14818 6 : LocalContext context;
14819 6 : v8::Isolate* isolate = context->GetIsolate();
14820 12 : v8::HandleScope outer(isolate);
14821 12 : static v8::Persistent<v8::ObjectTemplate> templ;
14822 6 : if (templ.IsEmpty()) {
14823 6 : v8::EscapableHandleScope inner(isolate);
14824 6 : v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14825 6 : local->SetInternalFieldCount(1);
14826 : templ.Reset(isolate, inner.Escape(local));
14827 : }
14828 : v8::Local<v8::Object> result =
14829 : v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14830 6 : ->NewInstance(context.local())
14831 6 : .ToLocalChecked();
14832 12 : CHECK_EQ(1, result->InternalFieldCount());
14833 6 : }
14834 :
14835 :
14836 : // If part of the threaded tests, this test makes ThreadingTest fail
14837 : // on mac.
14838 28342 : TEST(CatchStackOverflow) {
14839 5 : LocalContext context;
14840 10 : v8::HandleScope scope(context->GetIsolate());
14841 10 : v8::TryCatch try_catch(context->GetIsolate());
14842 : v8::Local<v8::Value> result = CompileRun(
14843 : "function f() {"
14844 : " return f();"
14845 : "}"
14846 : ""
14847 : "f();");
14848 10 : CHECK(result.IsEmpty());
14849 5 : }
14850 :
14851 :
14852 18 : static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14853 : const char* resource_name,
14854 : int line_offset) {
14855 18 : v8::HandleScope scope(CcTest::isolate());
14856 36 : v8::TryCatch try_catch(CcTest::isolate());
14857 18 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14858 36 : CHECK(script->Run(context).IsEmpty());
14859 18 : CHECK(try_catch.HasCaught());
14860 18 : v8::Local<v8::Message> message = try_catch.Message();
14861 18 : CHECK(!message.IsEmpty());
14862 36 : CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14863 18 : CHECK_EQ(91, message->GetStartPosition());
14864 18 : CHECK_EQ(92, message->GetEndPosition());
14865 36 : CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14866 36 : CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14867 : v8::String::Utf8Value line(CcTest::isolate(),
14868 54 : message->GetSourceLine(context).ToLocalChecked());
14869 18 : CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14870 : v8::String::Utf8Value name(CcTest::isolate(),
14871 36 : message->GetScriptOrigin().ResourceName());
14872 36 : CHECK_EQ(0, strcmp(resource_name, *name));
14873 18 : }
14874 :
14875 :
14876 28343 : THREADED_TEST(TryCatchSourceInfo) {
14877 6 : LocalContext context;
14878 12 : v8::HandleScope scope(context->GetIsolate());
14879 : v8::Local<v8::String> source = v8_str(
14880 : "function Foo() {\n"
14881 : " return Bar();\n"
14882 : "}\n"
14883 : "\n"
14884 : "function Bar() {\n"
14885 : " return Baz();\n"
14886 : "}\n"
14887 : "\n"
14888 : "function Baz() {\n"
14889 : " throw 'nirk';\n"
14890 : "}\n"
14891 : "\n"
14892 6 : "Foo();\n");
14893 :
14894 : const char* resource_name;
14895 : v8::Local<v8::Script> script;
14896 : resource_name = "test.js";
14897 6 : script = CompileWithOrigin(source, resource_name);
14898 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14899 :
14900 : resource_name = "test1.js";
14901 6 : v8::ScriptOrigin origin1(v8_str(resource_name));
14902 : script =
14903 12 : v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
14904 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14905 :
14906 : resource_name = "test2.js";
14907 : v8::ScriptOrigin origin2(v8_str(resource_name),
14908 6 : v8::Integer::New(context->GetIsolate(), 7));
14909 : script =
14910 12 : v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
14911 12 : CheckTryCatchSourceInfo(script, resource_name, 7);
14912 6 : }
14913 :
14914 :
14915 28343 : THREADED_TEST(TryCatchSourceInfoForEOSError) {
14916 6 : LocalContext context;
14917 12 : v8::HandleScope scope(context->GetIsolate());
14918 12 : v8::TryCatch try_catch(context->GetIsolate());
14919 12 : CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
14920 6 : CHECK(try_catch.HasCaught());
14921 6 : v8::Local<v8::Message> message = try_catch.Message();
14922 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
14923 18 : CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
14924 6 : }
14925 :
14926 :
14927 28343 : THREADED_TEST(CompilationCache) {
14928 6 : LocalContext context;
14929 12 : v8::HandleScope scope(context->GetIsolate());
14930 6 : v8::Local<v8::String> source0 = v8_str("1234");
14931 6 : v8::Local<v8::String> source1 = v8_str("1234");
14932 : v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14933 : v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14934 6 : v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
14935 6 : .ToLocalChecked(); // different origin
14936 18 : CHECK_EQ(1234, script0->Run(context.local())
14937 : .ToLocalChecked()
14938 : ->Int32Value(context.local())
14939 : .FromJust());
14940 18 : CHECK_EQ(1234, script1->Run(context.local())
14941 : .ToLocalChecked()
14942 : ->Int32Value(context.local())
14943 : .FromJust());
14944 18 : CHECK_EQ(1234, script2->Run(context.local())
14945 : .ToLocalChecked()
14946 : ->Int32Value(context.local())
14947 6 : .FromJust());
14948 6 : }
14949 :
14950 :
14951 0 : static void FunctionNameCallback(
14952 0 : const v8::FunctionCallbackInfo<v8::Value>& args) {
14953 0 : ApiTestFuzzer::Fuzz();
14954 0 : args.GetReturnValue().Set(v8_num(42));
14955 0 : }
14956 :
14957 :
14958 28343 : THREADED_TEST(CallbackFunctionName) {
14959 6 : LocalContext context;
14960 6 : v8::Isolate* isolate = context->GetIsolate();
14961 12 : v8::HandleScope scope(isolate);
14962 6 : Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14963 : t->Set(v8_str("asdf"),
14964 18 : v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14965 36 : CHECK(context->Global()
14966 : ->Set(context.local(), v8_str("obj"),
14967 : t->NewInstance(context.local()).ToLocalChecked())
14968 : .FromJust());
14969 : v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
14970 6 : CHECK(value->IsString());
14971 12 : v8::String::Utf8Value name(isolate, value);
14972 12 : CHECK_EQ(0, strcmp("asdf", *name));
14973 6 : }
14974 :
14975 :
14976 28343 : THREADED_TEST(DateAccess) {
14977 6 : LocalContext context;
14978 12 : v8::HandleScope scope(context->GetIsolate());
14979 : v8::Local<v8::Value> date =
14980 6 : v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
14981 6 : CHECK(date->IsDate());
14982 12 : CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14983 6 : }
14984 :
14985 48 : void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14986 : unsigned index, const char* name) {
14987 48 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
14988 : v8::Local<v8::Value> value =
14989 96 : properties->Get(context, v8::Integer::New(isolate, index))
14990 48 : .ToLocalChecked();
14991 48 : CHECK(value->IsSymbol());
14992 : v8::String::Utf8Value symbol_name(isolate,
14993 48 : Local<Symbol>::Cast(value)->Name());
14994 48 : if (strcmp(name, *symbol_name) != 0) {
14995 : FATAL("properties[%u] was Symbol('%s') instead of Symbol('%s').", index,
14996 0 : name, *symbol_name);
14997 48 : }
14998 48 : }
14999 :
15000 150 : void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
15001 : unsigned length, const char* names[]) {
15002 150 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15003 150 : CHECK_EQ(length, properties->Length());
15004 924 : for (unsigned i = 0; i < length; i++) {
15005 : v8::Local<v8::Value> value =
15006 2772 : properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
15007 924 : if (names[i] == nullptr) {
15008 : DCHECK(value->IsSymbol());
15009 : } else {
15010 876 : v8::String::Utf8Value elm(isolate, value);
15011 876 : if (strcmp(names[i], *elm) != 0) {
15012 0 : FATAL("properties[%u] was '%s' instead of '%s'.", i, *elm, names[i]);
15013 876 : }
15014 : }
15015 : }
15016 150 : }
15017 :
15018 42 : void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15019 : unsigned length, const char* names[]) {
15020 42 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15021 : v8::Local<v8::Object> obj = val.As<v8::Object>();
15022 84 : v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
15023 42 : CheckStringArray(isolate, props, length, names);
15024 42 : }
15025 :
15026 :
15027 24 : void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15028 : unsigned elmc, const char* elmv[]) {
15029 24 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15030 : v8::Local<v8::Object> obj = val.As<v8::Object>();
15031 : v8::Local<v8::Array> props =
15032 24 : obj->GetOwnPropertyNames(context).ToLocalChecked();
15033 24 : CHECK_EQ(elmc, props->Length());
15034 42 : for (unsigned i = 0; i < elmc; i++) {
15035 : v8::String::Utf8Value elm(
15036 : isolate,
15037 126 : props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
15038 42 : CHECK_EQ(0, strcmp(elmv[i], *elm));
15039 42 : }
15040 24 : }
15041 :
15042 :
15043 28343 : THREADED_TEST(PropertyEnumeration) {
15044 6 : LocalContext context;
15045 6 : v8::Isolate* isolate = context->GetIsolate();
15046 12 : v8::HandleScope scope(isolate);
15047 : v8::Local<v8::Value> obj = CompileRun(
15048 : "var result = [];"
15049 : "result[0] = {};"
15050 : "result[1] = {a: 1, b: 2};"
15051 : "result[2] = [1, 2, 3];"
15052 : "var proto = {x: 1, y: 2, z: 3};"
15053 : "var x = { __proto__: proto, w: 0, z: 1 };"
15054 : "result[3] = x;"
15055 : "result[4] = {21350:1};"
15056 : "x = Object.create(null);"
15057 : "x.a = 1; x[12345678] = 1;"
15058 : "result[5] = x;"
15059 : "result;");
15060 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
15061 6 : CHECK_EQ(6u, elms->Length());
15062 : int elmc0 = 0;
15063 : const char** elmv0 = nullptr;
15064 : CheckProperties(
15065 : isolate,
15066 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15067 12 : elmc0, elmv0);
15068 : CheckOwnProperties(
15069 : isolate,
15070 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15071 12 : elmc0, elmv0);
15072 : int elmc1 = 2;
15073 6 : const char* elmv1[] = {"a", "b"};
15074 : CheckProperties(
15075 : isolate,
15076 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15077 12 : elmc1, elmv1);
15078 : CheckOwnProperties(
15079 : isolate,
15080 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15081 12 : elmc1, elmv1);
15082 : int elmc2 = 3;
15083 6 : const char* elmv2[] = {"0", "1", "2"};
15084 : CheckProperties(
15085 : isolate,
15086 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15087 12 : elmc2, elmv2);
15088 : CheckOwnProperties(
15089 : isolate,
15090 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15091 12 : elmc2, elmv2);
15092 : int elmc3 = 4;
15093 6 : const char* elmv3[] = {"w", "z", "x", "y"};
15094 : CheckProperties(
15095 : isolate,
15096 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15097 12 : elmc3, elmv3);
15098 : int elmc4 = 2;
15099 6 : const char* elmv4[] = {"w", "z"};
15100 : CheckOwnProperties(
15101 : isolate,
15102 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15103 12 : elmc4, elmv4);
15104 : // Dictionary elements.
15105 : int elmc5 = 1;
15106 6 : const char* elmv5[] = {"21350"};
15107 : CheckProperties(
15108 : isolate,
15109 18 : elms->Get(context.local(), v8::Integer::New(isolate, 4)).ToLocalChecked(),
15110 12 : elmc5, elmv5);
15111 : // Dictionary properties.
15112 : int elmc6 = 2;
15113 6 : const char* elmv6[] = {"12345678", "a"};
15114 : CheckProperties(
15115 : isolate,
15116 18 : elms->Get(context.local(), v8::Integer::New(isolate, 5)).ToLocalChecked(),
15117 18 : elmc6, elmv6);
15118 6 : }
15119 :
15120 :
15121 28343 : THREADED_TEST(PropertyEnumeration2) {
15122 6 : LocalContext context;
15123 6 : v8::Isolate* isolate = context->GetIsolate();
15124 12 : v8::HandleScope scope(isolate);
15125 : v8::Local<v8::Value> obj = CompileRun(
15126 : "var result = [];"
15127 : "result[0] = {};"
15128 : "result[1] = {a: 1, b: 2};"
15129 : "result[2] = [1, 2, 3];"
15130 : "var proto = {x: 1, y: 2, z: 3};"
15131 : "var x = { __proto__: proto, w: 0, z: 1 };"
15132 : "result[3] = x;"
15133 : "result;");
15134 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
15135 6 : CHECK_EQ(4u, elms->Length());
15136 : int elmc0 = 0;
15137 : const char** elmv0 = nullptr;
15138 : CheckProperties(
15139 : isolate,
15140 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15141 12 : elmc0, elmv0);
15142 :
15143 : v8::Local<v8::Value> val =
15144 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
15145 : v8::Local<v8::Array> props =
15146 6 : val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
15147 6 : CHECK_EQ(0u, props->Length());
15148 0 : for (uint32_t i = 0; i < props->Length(); i++) {
15149 : printf("p[%u]\n", i);
15150 6 : }
15151 6 : }
15152 :
15153 28343 : THREADED_TEST(GetPropertyNames) {
15154 6 : LocalContext context;
15155 6 : v8::Isolate* isolate = context->GetIsolate();
15156 12 : v8::HandleScope scope(isolate);
15157 : v8::Local<v8::Value> result = CompileRun(
15158 : "var result = {0: 0, 1: 1, a: 2, b: 3};"
15159 : "result[2**32] = '4294967296';"
15160 : "result[2**32-1] = '4294967295';"
15161 : "result[2**32-2] = '4294967294';"
15162 : "result[Symbol('symbol')] = true;"
15163 : "result.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
15164 : "result;");
15165 : v8::Local<v8::Object> object = result.As<v8::Object>();
15166 : v8::PropertyFilter default_filter =
15167 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
15168 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
15169 :
15170 : v8::Local<v8::Array> properties =
15171 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
15172 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
15173 : "b", "4294967296", "4294967295", "2",
15174 6 : "3", "c", "d"};
15175 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
15176 :
15177 : properties =
15178 : object
15179 : ->GetPropertyNames(context.local(),
15180 : v8::KeyCollectionMode::kIncludePrototypes,
15181 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15182 12 : .ToLocalChecked();
15183 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
15184 :
15185 : properties = object
15186 : ->GetPropertyNames(context.local(),
15187 : v8::KeyCollectionMode::kIncludePrototypes,
15188 : include_symbols_filter,
15189 6 : v8::IndexFilter::kIncludeIndices)
15190 12 : .ToLocalChecked();
15191 : const char* expected_properties1_1[] = {
15192 : "0", "1", "4294967294", "a", "b", "4294967296",
15193 6 : "4294967295", nullptr, "2", "3", "c", "d"};
15194 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
15195 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
15196 :
15197 : properties =
15198 : object
15199 : ->GetPropertyNames(context.local(),
15200 : v8::KeyCollectionMode::kIncludePrototypes,
15201 6 : default_filter, v8::IndexFilter::kSkipIndices)
15202 12 : .ToLocalChecked();
15203 : const char* expected_properties2[] = {"a", "b", "4294967296",
15204 6 : "4294967295", "c", "d"};
15205 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
15206 :
15207 : properties = object
15208 : ->GetPropertyNames(context.local(),
15209 : v8::KeyCollectionMode::kIncludePrototypes,
15210 : include_symbols_filter,
15211 6 : v8::IndexFilter::kSkipIndices)
15212 12 : .ToLocalChecked();
15213 : const char* expected_properties2_1[] = {
15214 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
15215 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
15216 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15217 :
15218 : properties =
15219 : object
15220 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15221 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15222 12 : .ToLocalChecked();
15223 : const char* expected_properties3[] = {
15224 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295",
15225 6 : };
15226 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
15227 :
15228 : properties = object
15229 : ->GetPropertyNames(
15230 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15231 6 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
15232 12 : .ToLocalChecked();
15233 : const char* expected_properties3_1[] = {
15234 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
15235 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
15236 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
15237 :
15238 : properties =
15239 : object
15240 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15241 6 : default_filter, v8::IndexFilter::kSkipIndices)
15242 12 : .ToLocalChecked();
15243 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
15244 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
15245 :
15246 : properties = object
15247 : ->GetPropertyNames(
15248 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15249 6 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
15250 12 : .ToLocalChecked();
15251 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
15252 6 : nullptr};
15253 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
15254 12 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15255 6 : }
15256 :
15257 28343 : THREADED_TEST(ProxyGetPropertyNames) {
15258 6 : LocalContext context;
15259 6 : v8::Isolate* isolate = context->GetIsolate();
15260 12 : v8::HandleScope scope(isolate);
15261 : v8::Local<v8::Value> result = CompileRun(
15262 : "var target = {0: 0, 1: 1, a: 2, b: 3};"
15263 : "target[2**32] = '4294967296';"
15264 : "target[2**32-1] = '4294967295';"
15265 : "target[2**32-2] = '4294967294';"
15266 : "target[Symbol('symbol')] = true;"
15267 : "target.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
15268 : "var result = new Proxy(target, {});"
15269 : "result;");
15270 : v8::Local<v8::Object> object = result.As<v8::Object>();
15271 : v8::PropertyFilter default_filter =
15272 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
15273 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
15274 :
15275 : v8::Local<v8::Array> properties =
15276 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
15277 : const char* expected_properties1[] = {"0", "1", "4294967294", "a",
15278 : "b", "4294967296", "4294967295", "2",
15279 6 : "3", "c", "d"};
15280 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
15281 :
15282 : properties =
15283 : object
15284 : ->GetPropertyNames(context.local(),
15285 : v8::KeyCollectionMode::kIncludePrototypes,
15286 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15287 12 : .ToLocalChecked();
15288 6 : CheckStringArray(isolate, properties, 11, expected_properties1);
15289 :
15290 : properties = object
15291 : ->GetPropertyNames(context.local(),
15292 : v8::KeyCollectionMode::kIncludePrototypes,
15293 : include_symbols_filter,
15294 6 : v8::IndexFilter::kIncludeIndices)
15295 12 : .ToLocalChecked();
15296 : const char* expected_properties1_1[] = {
15297 : "0", "1", "4294967294", "a", "b", "4294967296",
15298 6 : "4294967295", nullptr, "2", "3", "c", "d"};
15299 6 : CheckStringArray(isolate, properties, 12, expected_properties1_1);
15300 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
15301 :
15302 : properties =
15303 : object
15304 : ->GetPropertyNames(context.local(),
15305 : v8::KeyCollectionMode::kIncludePrototypes,
15306 6 : default_filter, v8::IndexFilter::kSkipIndices)
15307 12 : .ToLocalChecked();
15308 : const char* expected_properties2[] = {"a", "b", "4294967296",
15309 6 : "4294967295", "c", "d"};
15310 6 : CheckStringArray(isolate, properties, 6, expected_properties2);
15311 :
15312 : properties = object
15313 : ->GetPropertyNames(context.local(),
15314 : v8::KeyCollectionMode::kIncludePrototypes,
15315 : include_symbols_filter,
15316 6 : v8::IndexFilter::kSkipIndices)
15317 12 : .ToLocalChecked();
15318 : const char* expected_properties2_1[] = {
15319 6 : "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
15320 6 : CheckStringArray(isolate, properties, 7, expected_properties2_1);
15321 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15322 :
15323 : properties =
15324 : object
15325 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15326 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15327 12 : .ToLocalChecked();
15328 : const char* expected_properties3[] = {"0", "1", "4294967294", "a",
15329 6 : "b", "4294967296", "4294967295"};
15330 6 : CheckStringArray(isolate, properties, 7, expected_properties3);
15331 :
15332 : properties = object
15333 : ->GetPropertyNames(
15334 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15335 6 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
15336 12 : .ToLocalChecked();
15337 : const char* expected_properties3_1[] = {
15338 6 : "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
15339 6 : CheckStringArray(isolate, properties, 8, expected_properties3_1);
15340 6 : CheckIsSymbolAt(isolate, properties, 7, "symbol");
15341 :
15342 : properties =
15343 : object
15344 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15345 6 : default_filter, v8::IndexFilter::kSkipIndices)
15346 12 : .ToLocalChecked();
15347 6 : const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
15348 6 : CheckStringArray(isolate, properties, 4, expected_properties4);
15349 :
15350 : properties = object
15351 : ->GetPropertyNames(
15352 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15353 6 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
15354 12 : .ToLocalChecked();
15355 : const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
15356 6 : nullptr};
15357 6 : CheckStringArray(isolate, properties, 5, expected_properties4_1);
15358 12 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15359 6 : }
15360 :
15361 28343 : THREADED_TEST(AccessChecksReenabledCorrectly) {
15362 6 : LocalContext context;
15363 6 : v8::Isolate* isolate = context->GetIsolate();
15364 12 : v8::HandleScope scope(isolate);
15365 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15366 6 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15367 18 : templ->Set(v8_str("a"), v8_str("a"));
15368 : // Add more than 8 (see kMaxFastProperties) properties
15369 : // so that the constructor will force copying map.
15370 : // Cannot sprintf, gcc complains unsafety.
15371 : char buf[4];
15372 66 : for (char i = '0'; i <= '9' ; i++) {
15373 60 : buf[0] = i;
15374 660 : for (char j = '0'; j <= '9'; j++) {
15375 600 : buf[1] = j;
15376 6600 : for (char k = '0'; k <= '9'; k++) {
15377 6000 : buf[2] = k;
15378 6000 : buf[3] = 0;
15379 18000 : templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15380 : }
15381 : }
15382 : }
15383 :
15384 : Local<v8::Object> instance_1 =
15385 6 : templ->NewInstance(context.local()).ToLocalChecked();
15386 30 : CHECK(context->Global()
15387 : ->Set(context.local(), v8_str("obj_1"), instance_1)
15388 : .FromJust());
15389 :
15390 : Local<Value> value_1 = CompileRun("obj_1.a");
15391 6 : CHECK(value_1.IsEmpty());
15392 :
15393 : Local<v8::Object> instance_2 =
15394 6 : templ->NewInstance(context.local()).ToLocalChecked();
15395 30 : CHECK(context->Global()
15396 : ->Set(context.local(), v8_str("obj_2"), instance_2)
15397 : .FromJust());
15398 :
15399 : Local<Value> value_2 = CompileRun("obj_2.a");
15400 12 : CHECK(value_2.IsEmpty());
15401 6 : }
15402 :
15403 :
15404 : // This tests that we do not allow dictionary load/call inline caches
15405 : // to use functions that have not yet been compiled. The potential
15406 : // problem of loading a function that has not yet been compiled can
15407 : // arise because we share code between contexts via the compilation
15408 : // cache.
15409 28343 : THREADED_TEST(DictionaryICLoadedFunction) {
15410 6 : v8::HandleScope scope(CcTest::isolate());
15411 : // Test LoadIC.
15412 18 : for (int i = 0; i < 2; i++) {
15413 12 : LocalContext context;
15414 72 : CHECK(context->Global()
15415 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
15416 : .FromJust());
15417 60 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
15418 : CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15419 12 : }
15420 : // Test CallIC.
15421 12 : for (int i = 0; i < 2; i++) {
15422 12 : LocalContext context;
15423 72 : CHECK(context->Global()
15424 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
15425 : .FromJust());
15426 60 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
15427 : CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15428 18 : }
15429 6 : }
15430 :
15431 :
15432 : // Test that cross-context new calls use the context of the callee to
15433 : // create the new JavaScript object.
15434 28343 : THREADED_TEST(CrossContextNew) {
15435 6 : v8::Isolate* isolate = CcTest::isolate();
15436 6 : v8::HandleScope scope(isolate);
15437 6 : v8::Local<Context> context0 = Context::New(isolate);
15438 6 : v8::Local<Context> context1 = Context::New(isolate);
15439 :
15440 : // Allow cross-domain access.
15441 6 : Local<String> token = v8_str("<security token>");
15442 6 : context0->SetSecurityToken(token);
15443 6 : context1->SetSecurityToken(token);
15444 :
15445 : // Set an 'x' property on the Object prototype and define a
15446 : // constructor function in context0.
15447 6 : context0->Enter();
15448 : CompileRun("Object.prototype.x = 42; function C() {};");
15449 6 : context0->Exit();
15450 :
15451 : // Call the constructor function from context0 and check that the
15452 : // result has the 'x' property.
15453 6 : context1->Enter();
15454 30 : CHECK(context1->Global()
15455 : ->Set(context1, v8_str("other"), context0->Global())
15456 : .FromJust());
15457 : Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15458 6 : CHECK(value->IsInt32());
15459 12 : CHECK_EQ(42, value->Int32Value(context1).FromJust());
15460 6 : context1->Exit();
15461 6 : }
15462 :
15463 :
15464 : // Verify that we can clone an object
15465 28342 : TEST(ObjectClone) {
15466 5 : LocalContext env;
15467 5 : v8::Isolate* isolate = env->GetIsolate();
15468 10 : v8::HandleScope scope(isolate);
15469 :
15470 : const char* sample =
15471 : "var rv = {};" \
15472 : "rv.alpha = 'hello';" \
15473 : "rv.beta = 123;" \
15474 : "rv;";
15475 :
15476 : // Create an object, verify basics.
15477 : Local<Value> val = CompileRun(sample);
15478 5 : CHECK(val->IsObject());
15479 : Local<v8::Object> obj = val.As<v8::Object>();
15480 20 : obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
15481 :
15482 25 : CHECK(v8_str("hello")
15483 : ->Equals(env.local(),
15484 : obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15485 : .FromJust());
15486 25 : CHECK(v8::Integer::New(isolate, 123)
15487 : ->Equals(env.local(),
15488 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15489 : .FromJust());
15490 25 : CHECK(v8_str("cloneme")
15491 : ->Equals(env.local(),
15492 : obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15493 : .FromJust());
15494 :
15495 : // Clone it.
15496 5 : Local<v8::Object> clone = obj->Clone();
15497 25 : CHECK(v8_str("hello")
15498 : ->Equals(env.local(),
15499 : clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15500 : .FromJust());
15501 25 : CHECK(v8::Integer::New(isolate, 123)
15502 : ->Equals(env.local(),
15503 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15504 : .FromJust());
15505 25 : CHECK(v8_str("cloneme")
15506 : ->Equals(env.local(),
15507 : clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15508 : .FromJust());
15509 :
15510 : // Set a property on the clone, verify each object.
15511 20 : CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
15512 : .FromJust());
15513 25 : CHECK(v8::Integer::New(isolate, 123)
15514 : ->Equals(env.local(),
15515 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15516 : .FromJust());
15517 25 : CHECK(v8::Integer::New(isolate, 456)
15518 : ->Equals(env.local(),
15519 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15520 5 : .FromJust());
15521 5 : }
15522 :
15523 :
15524 : class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15525 : public:
15526 : explicit OneByteVectorResource(i::Vector<const char> vector)
15527 6 : : data_(vector) {}
15528 6 : ~OneByteVectorResource() override = default;
15529 48 : size_t length() const override { return data_.length(); }
15530 26 : const char* data() const override { return data_.start(); }
15531 0 : void Dispose() override {}
15532 :
15533 : private:
15534 : i::Vector<const char> data_;
15535 : };
15536 :
15537 :
15538 : class UC16VectorResource : public v8::String::ExternalStringResource {
15539 : public:
15540 : explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15541 11 : : data_(vector) {}
15542 6 : ~UC16VectorResource() override = default;
15543 24 : size_t length() const override { return data_.length(); }
15544 416 : const i::uc16* data() const override { return data_.start(); }
15545 0 : void Dispose() override {}
15546 :
15547 : private:
15548 : i::Vector<const i::uc16> data_;
15549 : };
15550 :
15551 12 : static void MorphAString(i::String string,
15552 : OneByteVectorResource* one_byte_resource,
15553 : UC16VectorResource* uc16_resource) {
15554 : i::Isolate* isolate = CcTest::i_isolate();
15555 12 : CHECK(i::StringShape(string).IsExternal());
15556 12 : i::ReadOnlyRoots roots(CcTest::heap());
15557 12 : if (string->IsOneByteRepresentation()) {
15558 : // Check old map is not internalized or long.
15559 12 : CHECK(string->map() == roots.external_one_byte_string_map());
15560 : // Morph external string to be TwoByte string.
15561 12 : string->set_map(roots.external_string_map());
15562 12 : i::ExternalTwoByteString morphed = i::ExternalTwoByteString::cast(string);
15563 12 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
15564 12 : morphed->SetResource(isolate, uc16_resource);
15565 : } else {
15566 : // Check old map is not internalized or long.
15567 0 : CHECK(string->map() == roots.external_string_map());
15568 : // Morph external string to be one-byte string.
15569 0 : string->set_map(roots.external_one_byte_string_map());
15570 0 : i::ExternalOneByteString morphed = i::ExternalOneByteString::cast(string);
15571 0 : CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
15572 0 : morphed->SetResource(isolate, one_byte_resource);
15573 : }
15574 12 : }
15575 :
15576 : // Test that we can still flatten a string if the components it is built up
15577 : // from have been turned into 16 bit strings in the mean time.
15578 28343 : THREADED_TEST(MorphCompositeStringTest) {
15579 : char utf_buffer[129];
15580 : const char* c_string = "Now is the time for all good men"
15581 : " to come to the aid of the party";
15582 6 : uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15583 : {
15584 6 : LocalContext env;
15585 : i::Factory* factory = CcTest::i_isolate()->factory();
15586 6 : v8::Isolate* isolate = env->GetIsolate();
15587 : i::Isolate* i_isolate = CcTest::i_isolate();
15588 12 : v8::HandleScope scope(isolate);
15589 : OneByteVectorResource one_byte_resource(
15590 : i::Vector<const char>(c_string, i::StrLength(c_string)));
15591 : UC16VectorResource uc16_resource(
15592 : i::Vector<const uint16_t>(two_byte_string, i::StrLength(c_string)));
15593 :
15594 : Local<String> lhs(v8::Utils::ToLocal(
15595 : factory->NewExternalStringFromOneByte(&one_byte_resource)
15596 12 : .ToHandleChecked()));
15597 : Local<String> rhs(v8::Utils::ToLocal(
15598 : factory->NewExternalStringFromOneByte(&one_byte_resource)
15599 12 : .ToHandleChecked()));
15600 :
15601 30 : CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
15602 30 : CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
15603 :
15604 : CompileRun(
15605 : "var cons = lhs + rhs;"
15606 : "var slice = lhs.substring(1, lhs.length - 1);"
15607 : "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15608 :
15609 6 : CHECK(lhs->IsOneByte());
15610 6 : CHECK(rhs->IsOneByte());
15611 :
15612 6 : i::String ilhs = *v8::Utils::OpenHandle(*lhs);
15613 6 : i::String irhs = *v8::Utils::OpenHandle(*rhs);
15614 6 : MorphAString(ilhs, &one_byte_resource, &uc16_resource);
15615 6 : MorphAString(irhs, &one_byte_resource, &uc16_resource);
15616 :
15617 : // This should UTF-8 without flattening, since everything is ASCII.
15618 : Local<String> cons =
15619 12 : v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15620 6 : CHECK_EQ(128, cons->Utf8Length(isolate));
15621 6 : int nchars = -1;
15622 6 : CHECK_EQ(129, cons->WriteUtf8(isolate, utf_buffer, -1, &nchars));
15623 6 : CHECK_EQ(128, nchars);
15624 6 : CHECK_EQ(0, strcmp(
15625 : utf_buffer,
15626 : "Now is the time for all good men to come to the aid of the party"
15627 : "Now is the time for all good men to come to the aid of the party"));
15628 :
15629 : // Now do some stuff to make sure the strings are flattened, etc.
15630 : CompileRun(
15631 : "/[^a-z]/.test(cons);"
15632 : "/[^a-z]/.test(slice);"
15633 : "/[^a-z]/.test(slice_on_cons);");
15634 : const char* expected_cons =
15635 : "Now is the time for all good men to come to the aid of the party"
15636 : "Now is the time for all good men to come to the aid of the party";
15637 : const char* expected_slice =
15638 : "ow is the time for all good men to come to the aid of the part";
15639 : const char* expected_slice_on_cons =
15640 : "ow is the time for all good men to come to the aid of the party"
15641 : "Now is the time for all good men to come to the aid of the part";
15642 42 : CHECK(v8_str(expected_cons)
15643 : ->Equals(env.local(), env->Global()
15644 : ->Get(env.local(), v8_str("cons"))
15645 : .ToLocalChecked())
15646 : .FromJust());
15647 42 : CHECK(v8_str(expected_slice)
15648 : ->Equals(env.local(), env->Global()
15649 : ->Get(env.local(), v8_str("slice"))
15650 : .ToLocalChecked())
15651 : .FromJust());
15652 42 : CHECK(v8_str(expected_slice_on_cons)
15653 : ->Equals(env.local(),
15654 : env->Global()
15655 : ->Get(env.local(), v8_str("slice_on_cons"))
15656 : .ToLocalChecked())
15657 : .FromJust());
15658 :
15659 : // This avoids the GC from trying to free a stack allocated resource.
15660 6 : if (ilhs->IsExternalOneByteString())
15661 0 : i::ExternalOneByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15662 : else
15663 6 : i::ExternalTwoByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15664 6 : if (irhs->IsExternalOneByteString())
15665 0 : i::ExternalOneByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15666 : else
15667 12 : i::ExternalTwoByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15668 : }
15669 : i::DeleteArray(two_byte_string);
15670 6 : }
15671 :
15672 :
15673 28342 : TEST(CompileExternalTwoByteSource) {
15674 5 : LocalContext context;
15675 10 : v8::HandleScope scope(context->GetIsolate());
15676 :
15677 : // This is a very short list of sources, which currently is to check for a
15678 : // regression caused by r2703.
15679 : const char* one_byte_sources[] = {
15680 : "0.5",
15681 : "-0.5", // This mainly testes PushBack in the Scanner.
15682 : "--0.5", // This mainly testes PushBack in the Scanner.
15683 5 : nullptr};
15684 :
15685 : // Compile the sources as external two byte strings.
15686 20 : for (int i = 0; one_byte_sources[i] != nullptr; i++) {
15687 15 : uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15688 15 : TestResource* uc16_resource = new TestResource(two_byte_string);
15689 : v8::Local<v8::String> source =
15690 15 : v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15691 30 : .ToLocalChecked();
15692 15 : v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15693 5 : }
15694 5 : }
15695 :
15696 :
15697 : #ifndef V8_INTERPRETED_REGEXP
15698 :
15699 28337 : struct RegExpInterruptionData {
15700 : v8::base::Atomic32 loop_count;
15701 : UC16VectorResource* string_resource;
15702 : v8::Persistent<v8::String> string;
15703 28337 : } regexp_interruption_data;
15704 :
15705 :
15706 5 : class RegExpInterruptionThread : public v8::base::Thread {
15707 : public:
15708 : explicit RegExpInterruptionThread(v8::Isolate* isolate)
15709 5 : : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15710 :
15711 5 : void Run() override {
15712 40 : for (v8::base::Relaxed_Store(®exp_interruption_data.loop_count, 0);
15713 : v8::base::Relaxed_Load(®exp_interruption_data.loop_count) < 7;
15714 : v8::base::Relaxed_AtomicIncrement(®exp_interruption_data.loop_count,
15715 : 1)) {
15716 : // Wait a bit before requesting GC.
15717 35 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15718 35 : reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15719 : }
15720 : // Wait a bit before terminating.
15721 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15722 5 : isolate_->TerminateExecution();
15723 5 : }
15724 :
15725 : private:
15726 : v8::Isolate* isolate_;
15727 : };
15728 :
15729 :
15730 2 : void RunBeforeGC(v8::Isolate* isolate, v8::GCType type,
15731 : v8::GCCallbackFlags flags) {
15732 2 : if (v8::base::Relaxed_Load(®exp_interruption_data.loop_count) != 2) {
15733 2 : return;
15734 : }
15735 0 : v8::HandleScope scope(isolate);
15736 : v8::Local<v8::String> string = v8::Local<v8::String>::New(
15737 0 : CcTest::isolate(), regexp_interruption_data.string);
15738 0 : string->MakeExternal(regexp_interruption_data.string_resource);
15739 : }
15740 :
15741 :
15742 : // Test that RegExp execution can be interrupted. Specifically, we test
15743 : // * interrupting with GC
15744 : // * turn the subject string from one-byte internal to two-byte external string
15745 : // * force termination
15746 28342 : TEST(RegExpInterruption) {
15747 5 : LocalContext env;
15748 10 : v8::HandleScope scope(env->GetIsolate());
15749 :
15750 5 : RegExpInterruptionThread timeout_thread(env->GetIsolate());
15751 :
15752 5 : env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC);
15753 : static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15754 5 : i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15755 5 : v8::Local<v8::String> string = v8_str(one_byte_content);
15756 :
15757 25 : env->Global()->Set(env.local(), v8_str("a"), string).FromJust();
15758 5 : regexp_interruption_data.string.Reset(env->GetIsolate(), string);
15759 : regexp_interruption_data.string_resource = new UC16VectorResource(
15760 15 : i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15761 :
15762 10 : v8::TryCatch try_catch(env->GetIsolate());
15763 5 : timeout_thread.Start();
15764 :
15765 : CompileRun("/((a*)*)*b/.exec(a)");
15766 5 : CHECK(try_catch.HasTerminated());
15767 :
15768 5 : timeout_thread.Join();
15769 :
15770 : regexp_interruption_data.string.Reset();
15771 5 : i::DeleteArray(uc16_content);
15772 5 : }
15773 :
15774 : #endif // V8_INTERPRETED_REGEXP
15775 :
15776 :
15777 : // Test that we cannot set a property on the global object if there
15778 : // is a read-only property in the prototype chain.
15779 28342 : TEST(ReadOnlyPropertyInGlobalProto) {
15780 5 : v8::Isolate* isolate = CcTest::isolate();
15781 5 : v8::HandleScope scope(isolate);
15782 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15783 10 : LocalContext context(nullptr, templ);
15784 5 : v8::Local<v8::Object> global = context->Global();
15785 : v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15786 20 : global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15787 : global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15788 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15789 10 : .FromJust();
15790 : global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15791 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15792 10 : .FromJust();
15793 : // Check without 'eval' or 'with'.
15794 : v8::Local<v8::Value> res =
15795 5 : CompileRun("function f() { x = 42; return x; }; f()");
15796 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15797 : // Check with 'eval'.
15798 5 : res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15799 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15800 : // Check with 'with'.
15801 5 : res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15802 20 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15803 5 : }
15804 :
15805 :
15806 28342 : TEST(CreateDataProperty) {
15807 5 : LocalContext env;
15808 5 : v8::Isolate* isolate = env->GetIsolate();
15809 10 : v8::HandleScope handle_scope(isolate);
15810 :
15811 : CompileRun(
15812 : "var a = {};"
15813 : "var b = [];"
15814 : "Object.defineProperty(a, 'foo', {value: 23});"
15815 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15816 :
15817 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15818 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15819 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15820 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15821 : {
15822 : // Can't change a non-configurable properties.
15823 5 : v8::TryCatch try_catch(isolate);
15824 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15825 : v8::Integer::New(isolate, 42)).FromJust());
15826 5 : CHECK(!try_catch.HasCaught());
15827 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15828 : v8::Integer::New(isolate, 42)).FromJust());
15829 5 : CHECK(!try_catch.HasCaught());
15830 : v8::Local<v8::Value> val =
15831 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15832 5 : CHECK(val->IsNumber());
15833 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15834 : }
15835 :
15836 : {
15837 : // Set a regular property.
15838 5 : v8::TryCatch try_catch(isolate);
15839 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15840 : v8::Integer::New(isolate, 42)).FromJust());
15841 5 : CHECK(!try_catch.HasCaught());
15842 : v8::Local<v8::Value> val =
15843 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15844 5 : CHECK(val->IsNumber());
15845 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15846 : }
15847 :
15848 : {
15849 : // Set an indexed property.
15850 5 : v8::TryCatch try_catch(isolate);
15851 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15852 : v8::Integer::New(isolate, 42)).FromJust());
15853 5 : CHECK(!try_catch.HasCaught());
15854 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15855 5 : CHECK(val->IsNumber());
15856 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15857 : }
15858 :
15859 : {
15860 : // Special cases for arrays.
15861 5 : v8::TryCatch try_catch(isolate);
15862 20 : CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15863 : v8::Integer::New(isolate, 1)).FromJust());
15864 5 : CHECK(!try_catch.HasCaught());
15865 : }
15866 : {
15867 : // Special cases for arrays: index exceeds the array's length
15868 5 : v8::TryCatch try_catch(isolate);
15869 15 : CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15870 : .FromJust());
15871 5 : CHECK(!try_catch.HasCaught());
15872 5 : CHECK_EQ(2U, arr->Length());
15873 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15874 5 : CHECK(val->IsNumber());
15875 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15876 :
15877 : // Set an existing entry.
15878 15 : CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15879 : .FromJust());
15880 5 : CHECK(!try_catch.HasCaught());
15881 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15882 5 : CHECK(val->IsNumber());
15883 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15884 : }
15885 :
15886 : CompileRun("Object.freeze(a);");
15887 : {
15888 : // Can't change non-extensible objects.
15889 5 : v8::TryCatch try_catch(isolate);
15890 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15891 : v8::Integer::New(isolate, 42)).FromJust());
15892 5 : CHECK(!try_catch.HasCaught());
15893 : }
15894 :
15895 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15896 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15897 : v8::Local<v8::Object> access_checked =
15898 5 : templ->NewInstance(env.local()).ToLocalChecked();
15899 : {
15900 5 : v8::TryCatch try_catch(isolate);
15901 20 : CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15902 : v8::Integer::New(isolate, 42))
15903 : .IsNothing());
15904 5 : CHECK(try_catch.HasCaught());
15905 5 : }
15906 5 : }
15907 :
15908 :
15909 28342 : TEST(DefineOwnProperty) {
15910 5 : LocalContext env;
15911 5 : v8::Isolate* isolate = env->GetIsolate();
15912 10 : v8::HandleScope handle_scope(isolate);
15913 :
15914 : CompileRun(
15915 : "var a = {};"
15916 : "var b = [];"
15917 : "Object.defineProperty(a, 'foo', {value: 23});"
15918 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15919 :
15920 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15921 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15922 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15923 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15924 : {
15925 : // Can't change a non-configurable properties.
15926 5 : v8::TryCatch try_catch(isolate);
15927 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15928 : v8::Integer::New(isolate, 42)).FromJust());
15929 5 : CHECK(!try_catch.HasCaught());
15930 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15931 : v8::Integer::New(isolate, 42)).FromJust());
15932 5 : CHECK(!try_catch.HasCaught());
15933 : v8::Local<v8::Value> val =
15934 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15935 5 : CHECK(val->IsNumber());
15936 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15937 : }
15938 :
15939 : {
15940 : // Set a regular property.
15941 5 : v8::TryCatch try_catch(isolate);
15942 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15943 : v8::Integer::New(isolate, 42)).FromJust());
15944 5 : CHECK(!try_catch.HasCaught());
15945 : v8::Local<v8::Value> val =
15946 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15947 5 : CHECK(val->IsNumber());
15948 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15949 : }
15950 :
15951 : {
15952 : // Set an indexed property.
15953 5 : v8::TryCatch try_catch(isolate);
15954 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15955 : v8::Integer::New(isolate, 42)).FromJust());
15956 5 : CHECK(!try_catch.HasCaught());
15957 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15958 5 : CHECK(val->IsNumber());
15959 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15960 : }
15961 :
15962 : {
15963 : // Special cases for arrays.
15964 5 : v8::TryCatch try_catch(isolate);
15965 20 : CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15966 : v8::Integer::New(isolate, 1)).FromJust());
15967 5 : CHECK(!try_catch.HasCaught());
15968 : }
15969 : {
15970 : // Special cases for arrays: index exceeds the array's length
15971 5 : v8::TryCatch try_catch(isolate);
15972 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15973 : v8::Integer::New(isolate, 23)).FromJust());
15974 5 : CHECK(!try_catch.HasCaught());
15975 5 : CHECK_EQ(2U, arr->Length());
15976 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15977 5 : CHECK(val->IsNumber());
15978 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15979 :
15980 : // Set an existing entry.
15981 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15982 : v8::Integer::New(isolate, 42)).FromJust());
15983 5 : CHECK(!try_catch.HasCaught());
15984 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15985 5 : CHECK(val->IsNumber());
15986 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15987 : }
15988 :
15989 : {
15990 : // Set a non-writable property.
15991 5 : v8::TryCatch try_catch(isolate);
15992 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15993 : v8::Integer::New(isolate, 42),
15994 : v8::ReadOnly).FromJust());
15995 5 : CHECK(!try_catch.HasCaught());
15996 : v8::Local<v8::Value> val =
15997 15 : obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15998 5 : CHECK(val->IsNumber());
15999 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16000 15 : CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
16001 : env.local(), v8_str("lala")).FromJust());
16002 5 : CHECK(!try_catch.HasCaught());
16003 : }
16004 :
16005 : CompileRun("Object.freeze(a);");
16006 : {
16007 : // Can't change non-extensible objects.
16008 5 : v8::TryCatch try_catch(isolate);
16009 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
16010 : v8::Integer::New(isolate, 42)).FromJust());
16011 5 : CHECK(!try_catch.HasCaught());
16012 : }
16013 :
16014 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16015 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
16016 : v8::Local<v8::Object> access_checked =
16017 5 : templ->NewInstance(env.local()).ToLocalChecked();
16018 : {
16019 5 : v8::TryCatch try_catch(isolate);
16020 20 : CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
16021 : v8::Integer::New(isolate, 42))
16022 : .IsNothing());
16023 5 : CHECK(try_catch.HasCaught());
16024 5 : }
16025 5 : }
16026 :
16027 28342 : TEST(DefineProperty) {
16028 5 : LocalContext env;
16029 5 : v8::Isolate* isolate = env->GetIsolate();
16030 10 : v8::HandleScope handle_scope(isolate);
16031 :
16032 : v8::Local<v8::Name> p;
16033 :
16034 : CompileRun(
16035 : "var a = {};"
16036 : "var b = [];"
16037 : "Object.defineProperty(a, 'v1', {value: 23});"
16038 : "Object.defineProperty(a, 'v2', {value: 23, configurable: true});");
16039 :
16040 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
16041 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
16042 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
16043 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
16044 :
16045 10 : v8::PropertyDescriptor desc(v8_num(42));
16046 : {
16047 : // Use a data descriptor.
16048 :
16049 : // Cannot change a non-configurable property.
16050 5 : p = v8_str("v1");
16051 5 : v8::TryCatch try_catch(isolate);
16052 10 : CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
16053 5 : CHECK(!try_catch.HasCaught());
16054 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16055 5 : CHECK(val->IsNumber());
16056 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
16057 :
16058 : // Change a configurable property.
16059 5 : p = v8_str("v2");
16060 10 : obj->DefineProperty(env.local(), p, desc).FromJust();
16061 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16062 5 : CHECK(!try_catch.HasCaught());
16063 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16064 5 : CHECK(val->IsNumber());
16065 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16066 :
16067 : // Check that missing writable has default value false.
16068 5 : p = v8_str("v12");
16069 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16070 5 : CHECK(!try_catch.HasCaught());
16071 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16072 5 : CHECK(val->IsNumber());
16073 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16074 10 : v8::PropertyDescriptor desc2(v8_num(43));
16075 10 : CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust());
16076 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16077 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16078 10 : CHECK(!try_catch.HasCaught());
16079 : }
16080 :
16081 : {
16082 : // Set a regular property.
16083 5 : p = v8_str("v3");
16084 5 : v8::TryCatch try_catch(isolate);
16085 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16086 5 : CHECK(!try_catch.HasCaught());
16087 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16088 5 : CHECK(val->IsNumber());
16089 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16090 : }
16091 :
16092 : {
16093 : // Set an indexed property.
16094 5 : v8::TryCatch try_catch(isolate);
16095 15 : CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust());
16096 5 : CHECK(!try_catch.HasCaught());
16097 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
16098 5 : CHECK(val->IsNumber());
16099 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16100 : }
16101 :
16102 : {
16103 : // No special case when changing array length.
16104 5 : v8::TryCatch try_catch(isolate);
16105 : // Use a writable descriptor, otherwise the next test, that changes
16106 : // the array length will fail.
16107 10 : v8::PropertyDescriptor desc(v8_num(42), true);
16108 15 : CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust());
16109 10 : CHECK(!try_catch.HasCaught());
16110 : }
16111 :
16112 : {
16113 : // Special cases for arrays: index exceeds the array's length.
16114 5 : v8::TryCatch try_catch(isolate);
16115 15 : CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust());
16116 5 : CHECK(!try_catch.HasCaught());
16117 5 : CHECK_EQ(101U, arr->Length());
16118 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
16119 5 : CHECK(val->IsNumber());
16120 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16121 :
16122 : // Set an existing entry.
16123 15 : CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust());
16124 5 : CHECK(!try_catch.HasCaught());
16125 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
16126 5 : CHECK(val->IsNumber());
16127 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16128 : }
16129 :
16130 : {
16131 : // Use a generic descriptor.
16132 5 : v8::PropertyDescriptor desc_generic;
16133 :
16134 5 : p = v8_str("v4");
16135 10 : v8::TryCatch try_catch(isolate);
16136 10 : CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust());
16137 5 : CHECK(!try_catch.HasCaught());
16138 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16139 5 : CHECK(val->IsUndefined());
16140 :
16141 15 : obj->Set(env.local(), p, v8_num(1)).FromJust();
16142 5 : CHECK(!try_catch.HasCaught());
16143 :
16144 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16145 5 : CHECK(val->IsUndefined());
16146 10 : CHECK(!try_catch.HasCaught());
16147 : }
16148 :
16149 : {
16150 : // Use a data descriptor with undefined value.
16151 5 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate));
16152 :
16153 10 : v8::TryCatch try_catch(isolate);
16154 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16155 5 : CHECK(!try_catch.HasCaught());
16156 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16157 5 : CHECK(val->IsUndefined());
16158 10 : CHECK(!try_catch.HasCaught());
16159 : }
16160 :
16161 : {
16162 : // Use a descriptor with attribute == v8::ReadOnly.
16163 5 : v8::PropertyDescriptor desc_read_only(v8_num(42), false);
16164 5 : desc_read_only.set_enumerable(true);
16165 5 : desc_read_only.set_configurable(true);
16166 :
16167 5 : p = v8_str("v5");
16168 10 : v8::TryCatch try_catch(isolate);
16169 10 : CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust());
16170 5 : CHECK(!try_catch.HasCaught());
16171 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16172 5 : CHECK(val->IsNumber());
16173 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16174 10 : CHECK_EQ(v8::ReadOnly,
16175 : obj->GetPropertyAttributes(env.local(), p).FromJust());
16176 10 : CHECK(!try_catch.HasCaught());
16177 : }
16178 :
16179 : {
16180 : // Use an accessor descriptor with empty handles.
16181 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate),
16182 5 : v8::Undefined(isolate));
16183 :
16184 5 : p = v8_str("v6");
16185 10 : v8::TryCatch try_catch(isolate);
16186 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16187 5 : CHECK(!try_catch.HasCaught());
16188 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16189 5 : CHECK(val->IsUndefined());
16190 10 : CHECK(!try_catch.HasCaught());
16191 : }
16192 :
16193 : {
16194 : // Use an accessor descriptor.
16195 : CompileRun(
16196 : "var set = function(x) {this.val = 2*x;};"
16197 : "var get = function() {return this.val || 0;};");
16198 :
16199 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
16200 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
16201 : v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
16202 25 : env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
16203 5 : v8::PropertyDescriptor desc(get, set);
16204 :
16205 5 : p = v8_str("v7");
16206 10 : v8::TryCatch try_catch(isolate);
16207 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16208 5 : CHECK(!try_catch.HasCaught());
16209 :
16210 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16211 5 : CHECK(val->IsNumber());
16212 10 : CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
16213 5 : CHECK(!try_catch.HasCaught());
16214 :
16215 15 : obj->Set(env.local(), p, v8_num(7)).FromJust();
16216 5 : CHECK(!try_catch.HasCaught());
16217 :
16218 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16219 5 : CHECK(val->IsNumber());
16220 10 : CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
16221 10 : CHECK(!try_catch.HasCaught());
16222 : }
16223 :
16224 : {
16225 : // Redefine an existing property.
16226 :
16227 : // desc = {value: 42, enumerable: true}
16228 5 : v8::PropertyDescriptor desc(v8_num(42));
16229 5 : desc.set_enumerable(true);
16230 :
16231 5 : p = v8_str("v8");
16232 10 : v8::TryCatch try_catch(isolate);
16233 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16234 5 : CHECK(!try_catch.HasCaught());
16235 :
16236 : // desc = {enumerable: true}
16237 10 : v8::PropertyDescriptor desc_true((v8::Local<v8::Value>()));
16238 5 : desc_true.set_enumerable(true);
16239 :
16240 : // Successful redefinition because all present attributes have the same
16241 : // value as the current descriptor.
16242 10 : CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust());
16243 5 : CHECK(!try_catch.HasCaught());
16244 :
16245 : // desc = {}
16246 10 : v8::PropertyDescriptor desc_empty;
16247 : // Successful redefinition because no attributes are overwritten in the
16248 : // current descriptor.
16249 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16250 5 : CHECK(!try_catch.HasCaught());
16251 :
16252 : // desc = {enumerable: false}
16253 10 : v8::PropertyDescriptor desc_false((v8::Local<v8::Value>()));
16254 5 : desc_false.set_enumerable(false);
16255 : // Not successful because we cannot define a different value for enumerable.
16256 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
16257 10 : CHECK(!try_catch.HasCaught());
16258 : }
16259 :
16260 : {
16261 : // Redefine a property that has a getter.
16262 : CompileRun("var get = function() {};");
16263 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
16264 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
16265 :
16266 : // desc = {get: function() {}}
16267 5 : v8::PropertyDescriptor desc(get, v8::Local<v8::Function>());
16268 10 : v8::TryCatch try_catch(isolate);
16269 :
16270 5 : p = v8_str("v9");
16271 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16272 5 : CHECK(!try_catch.HasCaught());
16273 :
16274 : // desc_empty = {}
16275 : // Successful because we are not redefining the current getter.
16276 10 : v8::PropertyDescriptor desc_empty;
16277 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16278 5 : CHECK(!try_catch.HasCaught());
16279 :
16280 : // desc = {get: function() {}}
16281 : // Successful because we redefine the getter with its current value.
16282 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16283 5 : CHECK(!try_catch.HasCaught());
16284 :
16285 : // desc = {get: undefined}
16286 : v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate),
16287 10 : v8::Local<v8::Function>());
16288 : // Not successful because we cannot redefine with the current value of get
16289 : // with undefined.
16290 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust());
16291 10 : CHECK(!try_catch.HasCaught());
16292 : }
16293 :
16294 : CompileRun("Object.freeze(a);");
16295 : {
16296 : // We cannot change non-extensible objects.
16297 5 : v8::TryCatch try_catch(isolate);
16298 15 : CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust());
16299 5 : CHECK(!try_catch.HasCaught());
16300 : }
16301 :
16302 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16303 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
16304 : v8::Local<v8::Object> access_checked =
16305 5 : templ->NewInstance(env.local()).ToLocalChecked();
16306 : {
16307 5 : v8::TryCatch try_catch(isolate);
16308 15 : CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc)
16309 : .IsNothing());
16310 5 : CHECK(try_catch.HasCaught());
16311 5 : }
16312 5 : }
16313 :
16314 28343 : THREADED_TEST(GetCurrentContextWhenNotInContext) {
16315 : i::Isolate* isolate = CcTest::i_isolate();
16316 6 : CHECK_NOT_NULL(isolate);
16317 6 : CHECK(isolate->context().is_null());
16318 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16319 6 : v8::HandleScope scope(v8_isolate);
16320 : // The following should not crash, but return an empty handle.
16321 6 : v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16322 6 : CHECK(current.IsEmpty());
16323 6 : }
16324 :
16325 :
16326 : // Check that a variable declaration with no explicit initialization
16327 : // value does shadow an existing property in the prototype chain.
16328 28343 : THREADED_TEST(InitGlobalVarInProtoChain) {
16329 6 : LocalContext context;
16330 12 : v8::HandleScope scope(context->GetIsolate());
16331 : // Introduce a variable in the prototype chain.
16332 : CompileRun("__proto__.x = 42");
16333 : v8::Local<v8::Value> result = CompileRun("var x = 43; x");
16334 6 : CHECK(!result->IsUndefined());
16335 18 : CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
16336 6 : }
16337 :
16338 :
16339 : // Regression test for issue 398.
16340 : // If a function is added to an object, creating a constant function
16341 : // field, and the result is cloned, replacing the constant function on the
16342 : // original should not affect the clone.
16343 : // See http://code.google.com/p/v8/issues/detail?id=398
16344 28343 : THREADED_TEST(ReplaceConstantFunction) {
16345 6 : LocalContext context;
16346 6 : v8::Isolate* isolate = context->GetIsolate();
16347 12 : v8::HandleScope scope(isolate);
16348 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
16349 : v8::Local<v8::FunctionTemplate> func_templ =
16350 6 : v8::FunctionTemplate::New(isolate);
16351 6 : v8::Local<v8::String> foo_string = v8_str("foo");
16352 : obj->Set(context.local(), foo_string,
16353 24 : func_templ->GetFunction(context.local()).ToLocalChecked())
16354 12 : .FromJust();
16355 6 : v8::Local<v8::Object> obj_clone = obj->Clone();
16356 24 : obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
16357 18 : CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
16358 6 : }
16359 :
16360 :
16361 504 : static void CheckElementValue(i::Isolate* isolate,
16362 : int expected,
16363 : i::Handle<i::Object> obj,
16364 : int offset) {
16365 : i::Object element =
16366 1008 : *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16367 504 : CHECK_EQ(expected, i::Smi::ToInt(element));
16368 504 : }
16369 :
16370 :
16371 : template <class ExternalArrayClass, class ElementType>
16372 162 : static void ObjectWithExternalArrayTestHelper(Local<Context> context,
16373 : v8::Local<Object> obj,
16374 : int element_count,
16375 : i::ExternalArrayType array_type,
16376 : int64_t low, int64_t high) {
16377 : i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
16378 162 : v8::Isolate* v8_isolate = context->GetIsolate();
16379 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
16380 486 : obj->Set(context, v8_str("field"), v8::Int32::New(v8_isolate, 1503))
16381 324 : .FromJust();
16382 648 : CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
16383 : v8::Local<v8::Value> result = CompileRun("ext_array.field");
16384 324 : CHECK_EQ(1503, result->Int32Value(context).FromJust());
16385 : result = CompileRun("ext_array[1]");
16386 324 : CHECK_EQ(1, result->Int32Value(context).FromJust());
16387 :
16388 : // Check assigned smis
16389 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16390 : " ext_array[i] = i;"
16391 : "}"
16392 : "var sum = 0;"
16393 : "for (var i = 0; i < 8; i++) {"
16394 : " sum += ext_array[i];"
16395 : "}"
16396 : "sum;");
16397 :
16398 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16399 : // Check pass through of assigned smis
16400 : result = CompileRun("var sum = 0;"
16401 : "for (var i = 0; i < 8; i++) {"
16402 : " sum += ext_array[i] = ext_array[i] = -i;"
16403 : "}"
16404 : "sum;");
16405 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
16406 :
16407 :
16408 : // Check assigned smis in reverse order
16409 : result = CompileRun("for (var i = 8; --i >= 0; ) {"
16410 : " ext_array[i] = i;"
16411 : "}"
16412 : "var sum = 0;"
16413 : "for (var i = 0; i < 8; i++) {"
16414 : " sum += ext_array[i];"
16415 : "}"
16416 : "sum;");
16417 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16418 :
16419 : // Check pass through of assigned HeapNumbers
16420 : result = CompileRun("var sum = 0;"
16421 : "for (var i = 0; i < 16; i+=2) {"
16422 : " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16423 : "}"
16424 : "sum;");
16425 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
16426 :
16427 : // Check assigned HeapNumbers
16428 : result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16429 : " ext_array[i] = (i * 0.5);"
16430 : "}"
16431 : "var sum = 0;"
16432 : "for (var i = 0; i < 16; i+=2) {"
16433 : " sum += ext_array[i];"
16434 : "}"
16435 : "sum;");
16436 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16437 :
16438 : // Check assigned HeapNumbers in reverse order
16439 : result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16440 : " ext_array[i] = (i * 0.5);"
16441 : "}"
16442 : "var sum = 0;"
16443 : "for (var i = 0; i < 16; i+=2) {"
16444 : " sum += ext_array[i];"
16445 : "}"
16446 : "sum;");
16447 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16448 :
16449 : i::ScopedVector<char> test_buf(1024);
16450 :
16451 : // Check legal boundary conditions.
16452 : // The repeated loads and stores ensure the ICs are exercised.
16453 : const char* boundary_program =
16454 : "var res = 0;"
16455 : "for (var i = 0; i < 16; i++) {"
16456 : " ext_array[i] = %lld;"
16457 : " if (i > 8) {"
16458 : " res = ext_array[i];"
16459 : " }"
16460 : "}"
16461 : "res;";
16462 162 : i::SNPrintF(test_buf,
16463 : boundary_program,
16464 : low);
16465 : result = CompileRun(test_buf.start());
16466 324 : CHECK_EQ(low, result->IntegerValue(context).FromJust());
16467 :
16468 162 : i::SNPrintF(test_buf,
16469 : boundary_program,
16470 : high);
16471 : result = CompileRun(test_buf.start());
16472 324 : CHECK_EQ(high, result->IntegerValue(context).FromJust());
16473 :
16474 : // Check misprediction of type in IC.
16475 : result = CompileRun("var tmp_array = ext_array;"
16476 : "var sum = 0;"
16477 : "for (var i = 0; i < 8; i++) {"
16478 : " tmp_array[i] = i;"
16479 : " sum += tmp_array[i];"
16480 : " if (i == 4) {"
16481 : " tmp_array = {};"
16482 : " }"
16483 : "}"
16484 : "sum;");
16485 : // Force GC to trigger verification.
16486 162 : CcTest::CollectAllGarbage();
16487 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16488 :
16489 : // Make sure out-of-range loads do not throw.
16490 162 : i::SNPrintF(test_buf,
16491 : "var caught_exception = false;"
16492 : "try {"
16493 : " ext_array[%d];"
16494 : "} catch (e) {"
16495 : " caught_exception = true;"
16496 : "}"
16497 : "caught_exception;",
16498 : element_count);
16499 : result = CompileRun(test_buf.start());
16500 162 : CHECK(!result->BooleanValue(v8_isolate));
16501 :
16502 : // Make sure out-of-range stores do not throw.
16503 162 : i::SNPrintF(test_buf,
16504 : "var caught_exception = false;"
16505 : "try {"
16506 : " ext_array[%d] = 1;"
16507 : "} catch (e) {"
16508 : " caught_exception = true;"
16509 : "}"
16510 : "caught_exception;",
16511 : element_count);
16512 : result = CompileRun(test_buf.start());
16513 162 : CHECK(!result->BooleanValue(v8_isolate));
16514 :
16515 : // Check other boundary conditions, values and operations.
16516 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16517 : " ext_array[7] = undefined;"
16518 : "}"
16519 : "ext_array[7];");
16520 324 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16521 162 : if (array_type == i::kExternalFloat64Array ||
16522 : array_type == i::kExternalFloat32Array) {
16523 72 : CHECK(std::isnan(
16524 : i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
16525 : } else {
16526 126 : CheckElementValue(isolate, 0, jsobj, 7);
16527 : }
16528 :
16529 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16530 : " ext_array[6] = '2.3';"
16531 : "}"
16532 : "ext_array[6];");
16533 324 : CHECK_EQ(2, result->Int32Value(context).FromJust());
16534 324 : CHECK_EQ(2,
16535 : static_cast<int>(
16536 : i::Object::GetElement(
16537 : isolate, jsobj, 6).ToHandleChecked()->Number()));
16538 :
16539 162 : if (array_type != i::kExternalFloat32Array &&
16540 : array_type != i::kExternalFloat64Array) {
16541 : // Though the specification doesn't state it, be explicit about
16542 : // converting NaNs and +/-Infinity to zero.
16543 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16544 : " ext_array[i] = 5;"
16545 : "}"
16546 : "for (var i = 0; i < 8; i++) {"
16547 : " ext_array[i] = NaN;"
16548 : "}"
16549 : "ext_array[5];");
16550 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16551 126 : CheckElementValue(isolate, 0, jsobj, 5);
16552 :
16553 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16554 : " ext_array[i] = 5;"
16555 : "}"
16556 : "for (var i = 0; i < 8; i++) {"
16557 : " ext_array[i] = Infinity;"
16558 : "}"
16559 : "ext_array[5];");
16560 : int expected_value =
16561 126 : (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
16562 252 : CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
16563 126 : CheckElementValue(isolate, expected_value, jsobj, 5);
16564 :
16565 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16566 : " ext_array[i] = 5;"
16567 : "}"
16568 : "for (var i = 0; i < 8; i++) {"
16569 : " ext_array[i] = -Infinity;"
16570 : "}"
16571 : "ext_array[5];");
16572 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16573 126 : CheckElementValue(isolate, 0, jsobj, 5);
16574 :
16575 : // Check truncation behavior of integral arrays.
16576 : const char* unsigned_data =
16577 : "var source_data = [0.6, 10.6];"
16578 : "var expected_results = [0, 10];";
16579 : const char* signed_data =
16580 : "var source_data = [0.6, 10.6, -0.6, -10.6];"
16581 : "var expected_results = [0, 10, 0, -10];";
16582 : const char* pixel_data =
16583 : "var source_data = [0.6, 10.6];"
16584 : "var expected_results = [1, 11];";
16585 : bool is_unsigned = (array_type == i::kExternalUint8Array ||
16586 : array_type == i::kExternalUint16Array ||
16587 126 : array_type == i::kExternalUint32Array);
16588 : bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
16589 :
16590 126 : i::SNPrintF(test_buf,
16591 : "%s"
16592 : "var all_passed = true;"
16593 : "for (var i = 0; i < source_data.length; i++) {"
16594 : " for (var j = 0; j < 8; j++) {"
16595 : " ext_array[j] = source_data[i];"
16596 : " }"
16597 : " all_passed = all_passed &&"
16598 : " (ext_array[5] == expected_results[i]);"
16599 : "}"
16600 : "all_passed;",
16601 : (is_unsigned ?
16602 : unsigned_data :
16603 126 : (is_pixel_data ? pixel_data : signed_data)));
16604 : result = CompileRun(test_buf.start());
16605 126 : CHECK(result->BooleanValue(v8_isolate));
16606 : }
16607 :
16608 : i::Handle<ExternalArrayClass> array(
16609 486 : ExternalArrayClass::cast(i::Handle<i::JSObject>::cast(jsobj)->elements()),
16610 324 : isolate);
16611 19602 : for (int i = 0; i < element_count; i++) {
16612 36720 : array->set(i, static_cast<ElementType>(i));
16613 : }
16614 :
16615 162 : bool old_natives_flag_sentry = i::FLAG_allow_natives_syntax;
16616 162 : i::FLAG_allow_natives_syntax = true;
16617 :
16618 : // Test complex assignments
16619 : result = CompileRun(
16620 : "function ee_op_test_complex_func(sum) {"
16621 : " for (var i = 0; i < 40; ++i) {"
16622 : " sum += (ext_array[i] += 1);"
16623 : " sum += (ext_array[i] -= 1);"
16624 : " } "
16625 : " return sum;"
16626 : "}"
16627 : "sum=0;"
16628 : "sum=ee_op_test_complex_func(sum);"
16629 : "sum=ee_op_test_complex_func(sum);"
16630 : "%OptimizeFunctionOnNextCall(ee_op_test_complex_func);"
16631 : "sum=ee_op_test_complex_func(sum);"
16632 : "sum;");
16633 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
16634 :
16635 : // Test count operations
16636 : result = CompileRun(
16637 : "function ee_op_test_count_func(sum) {"
16638 : " for (var i = 0; i < 40; ++i) {"
16639 : " sum += (++ext_array[i]);"
16640 : " sum += (--ext_array[i]);"
16641 : " } "
16642 : " return sum;"
16643 : "}"
16644 : "sum=0;"
16645 : "sum=ee_op_test_count_func(sum);"
16646 : "sum=ee_op_test_count_func(sum);"
16647 : "%OptimizeFunctionOnNextCall(ee_op_test_count_func);"
16648 : "sum=ee_op_test_count_func(sum);"
16649 : "sum;");
16650 324 : CHECK_EQ(4800, result->Int32Value(context).FromJust());
16651 :
16652 162 : i::FLAG_allow_natives_syntax = old_natives_flag_sentry;
16653 :
16654 : result = CompileRun("ext_array[3] = 33;"
16655 : "delete ext_array[3];"
16656 : "ext_array[3];");
16657 324 : CHECK_EQ(33, result->Int32Value(context).FromJust());
16658 :
16659 : result = CompileRun(
16660 : "ext_array[0] = 10; ext_array[1] = 11;"
16661 : "ext_array[2] = 12; ext_array[3] = 13;"
16662 : "try { ext_array.__defineGetter__('2', function() { return 120; }); }"
16663 : "catch (e) { }"
16664 : "ext_array[2];");
16665 324 : CHECK_EQ(12, result->Int32Value(context).FromJust());
16666 :
16667 : result = CompileRun("var js_array = new Array(40);"
16668 : "js_array[0] = 77;"
16669 : "js_array;");
16670 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16671 : ->Get(context, v8_str("0"))
16672 : .ToLocalChecked()
16673 : ->Int32Value(context)
16674 : .FromJust());
16675 :
16676 : result = CompileRun("ext_array[1] = 23;"
16677 : "ext_array.__proto__ = [];"
16678 : "js_array.__proto__ = ext_array;"
16679 : "js_array.concat(ext_array);");
16680 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16681 : ->Get(context, v8_str("0"))
16682 : .ToLocalChecked()
16683 : ->Int32Value(context)
16684 : .FromJust());
16685 648 : CHECK_EQ(23, v8::Object::Cast(*result)
16686 : ->Get(context, v8_str("1"))
16687 : .ToLocalChecked()
16688 : ->Int32Value(context)
16689 : .FromJust());
16690 :
16691 : result = CompileRun("ext_array[1] = 23;");
16692 324 : CHECK_EQ(23, result->Int32Value(context).FromJust());
16693 162 : }
16694 :
16695 :
16696 : template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16697 : class ElementType>
16698 54 : static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16699 : ElementType low, ElementType high) {
16700 54 : i::FLAG_allow_natives_syntax = true;
16701 54 : LocalContext context;
16702 : i::Isolate* isolate = CcTest::i_isolate();
16703 : i::Factory* factory = isolate->factory();
16704 108 : v8::HandleScope scope(context->GetIsolate());
16705 : const int kElementCount = 260;
16706 : i::Handle<i::JSTypedArray> jsobj =
16707 54 : factory->NewJSTypedArray(elements_kind, kElementCount);
16708 : i::Handle<FixedTypedArrayClass> fixed_array(
16709 108 : FixedTypedArrayClass::cast(jsobj->elements()), isolate);
16710 54 : CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16711 : fixed_array->map()->instance_type());
16712 54 : CHECK_EQ(kElementCount, fixed_array->length());
16713 54 : CcTest::CollectAllGarbage();
16714 14094 : for (int i = 0; i < kElementCount; i++) {
16715 26520 : fixed_array->set(i, static_cast<ElementType>(i));
16716 : }
16717 : // Force GC to trigger verification.
16718 54 : CcTest::CollectAllGarbage();
16719 14094 : for (int i = 0; i < kElementCount; i++) {
16720 14040 : CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16721 : static_cast<int64_t>(fixed_array->get_scalar(i)));
16722 : }
16723 : v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16724 :
16725 54 : ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16726 : context.local(), obj, kElementCount, array_type,
16727 : static_cast<int64_t>(low),
16728 108 : static_cast<int64_t>(high));
16729 54 : }
16730 :
16731 :
16732 28343 : THREADED_TEST(FixedUint8Array) {
16733 : FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16734 6 : i::kExternalUint8Array, 0x0, 0xFF);
16735 6 : }
16736 :
16737 :
16738 28343 : THREADED_TEST(FixedUint8ClampedArray) {
16739 : FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16740 : i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16741 6 : i::kExternalUint8ClampedArray, 0x0, 0xFF);
16742 6 : }
16743 :
16744 :
16745 28343 : THREADED_TEST(FixedInt8Array) {
16746 : FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16747 6 : i::kExternalInt8Array, -0x80, 0x7F);
16748 6 : }
16749 :
16750 :
16751 28343 : THREADED_TEST(FixedUint16Array) {
16752 : FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16753 6 : i::kExternalUint16Array, 0x0, 0xFFFF);
16754 6 : }
16755 :
16756 :
16757 28343 : THREADED_TEST(FixedInt16Array) {
16758 : FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16759 6 : i::kExternalInt16Array, -0x8000, 0x7FFF);
16760 6 : }
16761 :
16762 :
16763 28343 : THREADED_TEST(FixedUint32Array) {
16764 : FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16765 6 : i::kExternalUint32Array, 0x0, UINT_MAX);
16766 6 : }
16767 :
16768 :
16769 28343 : THREADED_TEST(FixedInt32Array) {
16770 : FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16771 6 : i::kExternalInt32Array, INT_MIN, INT_MAX);
16772 6 : }
16773 :
16774 :
16775 28343 : THREADED_TEST(FixedFloat32Array) {
16776 : FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16777 6 : i::kExternalFloat32Array, -500, 500);
16778 6 : }
16779 :
16780 :
16781 28343 : THREADED_TEST(FixedFloat64Array) {
16782 : FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16783 6 : i::kExternalFloat64Array, -500, 500);
16784 6 : }
16785 :
16786 :
16787 : template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16788 : class ArrayBufferType>
16789 108 : void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16790 : int64_t high) {
16791 : const int kElementCount = 50;
16792 :
16793 : i::ScopedVector<ElementType> backing_store(kElementCount+2);
16794 :
16795 216 : LocalContext env;
16796 108 : v8::Isolate* isolate = env->GetIsolate();
16797 216 : v8::HandleScope handle_scope(isolate);
16798 :
16799 : Local<ArrayBufferType> ab =
16800 : ArrayBufferType::New(isolate, backing_store.start(),
16801 108 : (kElementCount + 2) * sizeof(ElementType));
16802 : Local<TypedArray> ta =
16803 108 : TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16804 108 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16805 108 : CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16806 108 : CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16807 108 : CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16808 432 : CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16809 :
16810 108 : ElementType* data = backing_store.start() + 2;
16811 5508 : for (int i = 0; i < kElementCount; i++) {
16812 5400 : data[i] = static_cast<ElementType>(i);
16813 : }
16814 :
16815 108 : ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16816 216 : env.local(), ta, kElementCount, array_type, low, high);
16817 108 : }
16818 :
16819 :
16820 28343 : THREADED_TEST(Uint8Array) {
16821 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16822 6 : v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16823 6 : }
16824 :
16825 :
16826 28343 : THREADED_TEST(Int8Array) {
16827 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16828 6 : v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16829 6 : }
16830 :
16831 :
16832 28343 : THREADED_TEST(Uint16Array) {
16833 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16834 6 : v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16835 6 : }
16836 :
16837 :
16838 28343 : THREADED_TEST(Int16Array) {
16839 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16840 : v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16841 6 : 0x7FFF);
16842 6 : }
16843 :
16844 :
16845 28343 : THREADED_TEST(Uint32Array) {
16846 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16847 6 : v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16848 6 : }
16849 :
16850 :
16851 28343 : THREADED_TEST(Int32Array) {
16852 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16853 : v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16854 6 : INT_MAX);
16855 6 : }
16856 :
16857 :
16858 28343 : THREADED_TEST(Float32Array) {
16859 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16860 6 : v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16861 6 : }
16862 :
16863 :
16864 28343 : THREADED_TEST(Float64Array) {
16865 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16866 6 : v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16867 6 : }
16868 :
16869 :
16870 28343 : THREADED_TEST(Uint8ClampedArray) {
16871 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16872 : i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16873 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16874 6 : }
16875 :
16876 :
16877 28343 : THREADED_TEST(DataView) {
16878 : const int kSize = 50;
16879 :
16880 : i::ScopedVector<uint8_t> backing_store(kSize+2);
16881 :
16882 12 : LocalContext env;
16883 6 : v8::Isolate* isolate = env->GetIsolate();
16884 12 : v8::HandleScope handle_scope(isolate);
16885 :
16886 : Local<v8::ArrayBuffer> ab =
16887 6 : v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16888 6 : Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16889 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16890 6 : CHECK_EQ(2u, dv->ByteOffset());
16891 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16892 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16893 6 : }
16894 :
16895 :
16896 28343 : THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16897 6 : LocalContext env;
16898 6 : v8::Isolate* isolate = env->GetIsolate();
16899 12 : v8::HandleScope handle_scope(isolate);
16900 :
16901 : // Make sure the pointer looks like a heap object
16902 : uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16903 :
16904 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16905 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16906 :
16907 : // Should not crash
16908 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16909 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16910 6 : CcTest::CollectAllGarbage();
16911 6 : CcTest::CollectAllGarbage();
16912 :
16913 : // Should not move the pointer
16914 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16915 6 : }
16916 :
16917 :
16918 28343 : THREADED_TEST(SkipArrayBufferDuringScavenge) {
16919 6 : LocalContext env;
16920 6 : v8::Isolate* isolate = env->GetIsolate();
16921 12 : v8::HandleScope handle_scope(isolate);
16922 :
16923 : // Make sure the pointer looks like a heap object
16924 6 : Local<v8::Object> tmp = v8::Object::New(isolate);
16925 : uint8_t* store_ptr =
16926 6 : reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16927 :
16928 : // Make `store_ptr` point to from space
16929 6 : CcTest::CollectGarbage(i::NEW_SPACE);
16930 :
16931 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16932 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16933 :
16934 : // Should not crash,
16935 : // i.e. backing store pointer should not be treated as a heap object pointer
16936 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16937 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16938 :
16939 : // Use `ab` to silence compiler warning
16940 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16941 6 : }
16942 :
16943 :
16944 28343 : THREADED_TEST(SharedUint8Array) {
16945 6 : i::FLAG_harmony_sharedarraybuffer = true;
16946 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16947 6 : v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16948 6 : }
16949 :
16950 :
16951 28343 : THREADED_TEST(SharedInt8Array) {
16952 6 : i::FLAG_harmony_sharedarraybuffer = true;
16953 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16954 : v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16955 6 : 0x7F);
16956 6 : }
16957 :
16958 :
16959 28343 : THREADED_TEST(SharedUint16Array) {
16960 6 : i::FLAG_harmony_sharedarraybuffer = true;
16961 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16962 : v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16963 6 : 0xFFFF);
16964 6 : }
16965 :
16966 :
16967 28343 : THREADED_TEST(SharedInt16Array) {
16968 6 : i::FLAG_harmony_sharedarraybuffer = true;
16969 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16970 : v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16971 6 : 0x7FFF);
16972 6 : }
16973 :
16974 :
16975 28343 : THREADED_TEST(SharedUint32Array) {
16976 6 : i::FLAG_harmony_sharedarraybuffer = true;
16977 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16978 : v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16979 6 : UINT_MAX);
16980 6 : }
16981 :
16982 :
16983 28343 : THREADED_TEST(SharedInt32Array) {
16984 6 : i::FLAG_harmony_sharedarraybuffer = true;
16985 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16986 : v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16987 6 : INT_MAX);
16988 6 : }
16989 :
16990 :
16991 28343 : THREADED_TEST(SharedFloat32Array) {
16992 6 : i::FLAG_harmony_sharedarraybuffer = true;
16993 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16994 : v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16995 6 : 500);
16996 6 : }
16997 :
16998 :
16999 28343 : THREADED_TEST(SharedFloat64Array) {
17000 6 : i::FLAG_harmony_sharedarraybuffer = true;
17001 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
17002 : v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
17003 6 : 500);
17004 6 : }
17005 :
17006 :
17007 28343 : THREADED_TEST(SharedUint8ClampedArray) {
17008 6 : i::FLAG_harmony_sharedarraybuffer = true;
17009 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
17010 : i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
17011 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
17012 6 : }
17013 :
17014 :
17015 28343 : THREADED_TEST(SharedDataView) {
17016 6 : i::FLAG_harmony_sharedarraybuffer = true;
17017 : const int kSize = 50;
17018 :
17019 : i::ScopedVector<uint8_t> backing_store(kSize + 2);
17020 :
17021 12 : LocalContext env;
17022 6 : v8::Isolate* isolate = env->GetIsolate();
17023 12 : v8::HandleScope handle_scope(isolate);
17024 :
17025 : Local<v8::SharedArrayBuffer> ab =
17026 6 : v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17027 : Local<v8::DataView> dv =
17028 6 : v8::DataView::New(ab, 2, kSize);
17029 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17030 6 : CHECK_EQ(2u, dv->ByteOffset());
17031 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17032 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
17033 6 : }
17034 :
17035 : #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17036 : THREADED_TEST(Is##View) { \
17037 : LocalContext env; \
17038 : v8::Isolate* isolate = env->GetIsolate(); \
17039 : v8::HandleScope handle_scope(isolate); \
17040 : \
17041 : Local<Value> result = CompileRun( \
17042 : "var ab = new ArrayBuffer(128);" \
17043 : "new " #View "(ab)"); \
17044 : CHECK(result->IsArrayBufferView()); \
17045 : CHECK(result->Is##View()); \
17046 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17047 : }
17048 :
17049 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17050 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17051 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17052 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17053 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17054 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17055 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17056 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17057 28367 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17058 28367 : IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17059 :
17060 : #undef IS_ARRAY_BUFFER_VIEW_TEST
17061 :
17062 :
17063 :
17064 28343 : THREADED_TEST(ScriptContextDependence) {
17065 6 : LocalContext c1;
17066 12 : v8::HandleScope scope(c1->GetIsolate());
17067 : const char *source = "foo";
17068 : v8::Local<v8::Script> dep = v8_compile(source);
17069 : v8::ScriptCompiler::Source script_source(
17070 : v8::String::NewFromUtf8(c1->GetIsolate(), source,
17071 6 : v8::NewStringType::kNormal)
17072 6 : .ToLocalChecked());
17073 : v8::Local<v8::UnboundScript> indep =
17074 6 : v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
17075 6 : .ToLocalChecked();
17076 : c1->Global()
17077 : ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
17078 6 : v8::NewStringType::kNormal)
17079 : .ToLocalChecked(),
17080 30 : v8::Integer::New(c1->GetIsolate(), 100))
17081 12 : .FromJust();
17082 18 : CHECK_EQ(
17083 : dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
17084 : 100);
17085 24 : CHECK_EQ(indep->BindToCurrentContext()
17086 : ->Run(c1.local())
17087 : .ToLocalChecked()
17088 : ->Int32Value(c1.local())
17089 : .FromJust(),
17090 : 100);
17091 12 : LocalContext c2;
17092 : c2->Global()
17093 : ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
17094 6 : v8::NewStringType::kNormal)
17095 : .ToLocalChecked(),
17096 30 : v8::Integer::New(c2->GetIsolate(), 101))
17097 12 : .FromJust();
17098 18 : CHECK_EQ(
17099 : dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
17100 : 100);
17101 24 : CHECK_EQ(indep->BindToCurrentContext()
17102 : ->Run(c2.local())
17103 : .ToLocalChecked()
17104 : ->Int32Value(c2.local())
17105 : .FromJust(),
17106 6 : 101);
17107 6 : }
17108 :
17109 :
17110 28343 : THREADED_TEST(StackTrace) {
17111 6 : LocalContext context;
17112 12 : v8::HandleScope scope(context->GetIsolate());
17113 12 : v8::TryCatch try_catch(context->GetIsolate());
17114 : const char *source = "function foo() { FAIL.FAIL; }; foo();";
17115 6 : v8::Local<v8::String> src = v8_str(source);
17116 6 : v8::Local<v8::String> origin = v8_str("stack-trace-test");
17117 : v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17118 30 : CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
17119 : &script_source)
17120 : .ToLocalChecked()
17121 : ->BindToCurrentContext()
17122 : ->Run(context.local())
17123 : .IsEmpty());
17124 6 : CHECK(try_catch.HasCaught());
17125 : v8::String::Utf8Value stack(
17126 : context->GetIsolate(),
17127 18 : try_catch.StackTrace(context.local()).ToLocalChecked());
17128 18 : CHECK_NOT_NULL(strstr(*stack, "at foo (stack-trace-test"));
17129 6 : }
17130 :
17131 :
17132 : // Checks that a StackFrame has certain expected values.
17133 100 : void checkStackFrame(const char* expected_script_name,
17134 : const char* expected_func_name, int expected_line_number,
17135 : int expected_column, bool is_eval, bool is_constructor,
17136 : v8::Local<v8::StackFrame> frame) {
17137 100 : v8::HandleScope scope(CcTest::isolate());
17138 300 : v8::String::Utf8Value func_name(CcTest::isolate(), frame->GetFunctionName());
17139 300 : v8::String::Utf8Value script_name(CcTest::isolate(), frame->GetScriptName());
17140 100 : if (*script_name == nullptr) {
17141 : // The situation where there is no associated script, like for evals.
17142 35 : CHECK_NULL(expected_script_name);
17143 : } else {
17144 65 : CHECK_NOT_NULL(strstr(*script_name, expected_script_name));
17145 : }
17146 200 : CHECK_NOT_NULL(strstr(*func_name, expected_func_name));
17147 100 : CHECK_EQ(expected_line_number, frame->GetLineNumber());
17148 100 : CHECK_EQ(expected_column, frame->GetColumn());
17149 100 : CHECK_EQ(is_eval, frame->IsEval());
17150 200 : CHECK_EQ(is_constructor, frame->IsConstructor());
17151 100 : }
17152 :
17153 :
17154 180 : void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17155 35 : v8::HandleScope scope(args.GetIsolate());
17156 : const char* origin = "capture-stack-trace-test";
17157 : const int kOverviewTest = 1;
17158 : const int kDetailedTest = 2;
17159 : const int kFunctionName = 3;
17160 : const int kDisplayName = 4;
17161 : const int kFunctionNameAndDisplayName = 5;
17162 : const int kDisplayNameIsNotString = 6;
17163 : const int kFunctionNameIsNotString = 7;
17164 :
17165 35 : CHECK_EQ(args.Length(), 1);
17166 :
17167 35 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
17168 : v8::Isolate* isolate = args.GetIsolate();
17169 70 : int testGroup = args[0]->Int32Value(context).FromJust();
17170 35 : if (testGroup == kOverviewTest) {
17171 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17172 5 : args.GetIsolate(), 10, v8::StackTrace::kOverview);
17173 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
17174 : checkStackFrame(origin, "bar", 2, 10, false, false,
17175 5 : stackTrace->GetFrame(args.GetIsolate(), 0));
17176 : checkStackFrame(origin, "foo", 6, 3, false, true,
17177 5 : stackTrace->GetFrame(isolate, 1));
17178 : // This is the source string inside the eval which has the call to foo.
17179 : checkStackFrame(nullptr, "", 1, 1, true, false,
17180 5 : stackTrace->GetFrame(isolate, 2));
17181 : // The last frame is an anonymous function which has the initial eval call.
17182 : checkStackFrame(origin, "", 8, 7, false, false,
17183 5 : stackTrace->GetFrame(isolate, 3));
17184 30 : } else if (testGroup == kDetailedTest) {
17185 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17186 5 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17187 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
17188 : checkStackFrame(origin, "bat", 4, 22, false, false,
17189 5 : stackTrace->GetFrame(isolate, 0));
17190 : checkStackFrame(origin, "baz", 8, 3, false, true,
17191 5 : stackTrace->GetFrame(isolate, 1));
17192 : bool is_eval = true;
17193 : // This is the source string inside the eval which has the call to baz.
17194 : checkStackFrame(nullptr, "", 1, 1, is_eval, false,
17195 5 : stackTrace->GetFrame(isolate, 2));
17196 : // The last frame is an anonymous function which has the initial eval call.
17197 : checkStackFrame(origin, "", 10, 1, false, false,
17198 5 : stackTrace->GetFrame(isolate, 3));
17199 25 : } else if (testGroup == kFunctionName) {
17200 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17201 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17202 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17203 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
17204 5 : stackTrace->GetFrame(isolate, 0));
17205 20 : } else if (testGroup == kDisplayName) {
17206 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17207 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17208 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17209 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
17210 5 : stackTrace->GetFrame(isolate, 0));
17211 15 : } else if (testGroup == kFunctionNameAndDisplayName) {
17212 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17213 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17214 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17215 : checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
17216 5 : stackTrace->GetFrame(isolate, 0));
17217 10 : } else if (testGroup == kDisplayNameIsNotString) {
17218 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17219 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17220 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17221 : checkStackFrame(nullptr, "function.name", 3, 1, true, false,
17222 5 : stackTrace->GetFrame(isolate, 0));
17223 5 : } else if (testGroup == kFunctionNameIsNotString) {
17224 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17225 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17226 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17227 : checkStackFrame(nullptr, "", 3, 1, true, false,
17228 5 : stackTrace->GetFrame(isolate, 0));
17229 35 : }
17230 35 : }
17231 :
17232 :
17233 : // Tests the C++ StackTrace API.
17234 : // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17235 : // THREADED_TEST(CaptureStackTrace) {
17236 28342 : TEST(CaptureStackTrace) {
17237 5 : v8::Isolate* isolate = CcTest::isolate();
17238 5 : v8::HandleScope scope(isolate);
17239 5 : v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
17240 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17241 : templ->Set(v8_str("AnalyzeStackInNativeCode"),
17242 15 : v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17243 10 : LocalContext context(nullptr, templ);
17244 :
17245 : // Test getting OVERVIEW information. Should ignore information that is not
17246 : // script name, function name, line number, and column offset.
17247 : const char *overview_source =
17248 : "function bar() {\n"
17249 : " var y; AnalyzeStackInNativeCode(1);\n"
17250 : "}\n"
17251 : "function foo() {\n"
17252 : "\n"
17253 : " bar();\n"
17254 : "}\n"
17255 : "var x;eval('new foo();');";
17256 5 : v8::Local<v8::String> overview_src = v8_str(overview_source);
17257 : v8::ScriptCompiler::Source script_source(overview_src,
17258 : v8::ScriptOrigin(origin));
17259 : v8::Local<Value> overview_result(
17260 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
17261 5 : .ToLocalChecked()
17262 : ->BindToCurrentContext()
17263 15 : ->Run(context.local())
17264 5 : .ToLocalChecked());
17265 5 : CHECK(!overview_result.IsEmpty());
17266 5 : CHECK(overview_result->IsObject());
17267 :
17268 : // Test getting DETAILED information.
17269 : const char *detailed_source =
17270 : "function bat() {AnalyzeStackInNativeCode(2);\n"
17271 : "}\n"
17272 : "\n"
17273 : "function baz() {\n"
17274 : " bat();\n"
17275 : "}\n"
17276 : "eval('new baz();');";
17277 5 : v8::Local<v8::String> detailed_src = v8_str(detailed_source);
17278 : // Make the script using a non-zero line and column offset.
17279 5 : v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17280 5 : v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17281 : v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17282 : v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17283 : v8::Local<v8::UnboundScript> detailed_script(
17284 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
17285 5 : .ToLocalChecked());
17286 : v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
17287 10 : ->Run(context.local())
17288 5 : .ToLocalChecked());
17289 5 : CHECK(!detailed_result.IsEmpty());
17290 5 : CHECK(detailed_result->IsObject());
17291 :
17292 : // Test using function.name and function.displayName in stack trace
17293 : const char* function_name_source =
17294 : "function bar(function_name, display_name, testGroup) {\n"
17295 : " var f = new Function(`AnalyzeStackInNativeCode(${testGroup});`);\n"
17296 : " if (function_name) {\n"
17297 : " Object.defineProperty(f, 'name', { value: function_name });\n"
17298 : " }\n"
17299 : " if (display_name) {\n"
17300 : " f.displayName = display_name;"
17301 : " }\n"
17302 : " f()\n"
17303 : "}\n"
17304 : "bar('function.name', undefined, 3);\n"
17305 : "bar(undefined, 'function.displayName', 4);\n"
17306 : "bar('function.name', 'function.displayName', 5);\n"
17307 : "bar('function.name', 239, 6);\n"
17308 : "bar(239, undefined, 7);\n";
17309 : v8::Local<v8::String> function_name_src =
17310 : v8::String::NewFromUtf8(isolate, function_name_source,
17311 : v8::NewStringType::kNormal)
17312 5 : .ToLocalChecked();
17313 : v8::ScriptCompiler::Source script_source3(function_name_src,
17314 : v8::ScriptOrigin(origin));
17315 : v8::Local<Value> function_name_result(
17316 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
17317 5 : .ToLocalChecked()
17318 : ->BindToCurrentContext()
17319 15 : ->Run(context.local())
17320 5 : .ToLocalChecked());
17321 10 : CHECK(!function_name_result.IsEmpty());
17322 5 : }
17323 :
17324 :
17325 5 : static void StackTraceForUncaughtExceptionListener(
17326 : v8::Local<v8::Message> message, v8::Local<Value>) {
17327 5 : report_count++;
17328 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17329 5 : CHECK_EQ(2, stack_trace->GetFrameCount());
17330 : checkStackFrame("origin", "foo", 2, 3, false, false,
17331 5 : stack_trace->GetFrame(message->GetIsolate(), 0));
17332 : checkStackFrame("origin", "bar", 5, 3, false, false,
17333 5 : stack_trace->GetFrame(message->GetIsolate(), 1));
17334 5 : }
17335 :
17336 :
17337 28342 : TEST(CaptureStackTraceForUncaughtException) {
17338 5 : report_count = 0;
17339 5 : LocalContext env;
17340 5 : v8::Isolate* isolate = env->GetIsolate();
17341 10 : v8::HandleScope scope(isolate);
17342 5 : isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
17343 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17344 :
17345 : CompileRunWithOrigin(
17346 : "function foo() {\n"
17347 : " throw 1;\n"
17348 : "};\n"
17349 : "function bar() {\n"
17350 : " foo();\n"
17351 : "};",
17352 : "origin");
17353 5 : v8::Local<v8::Object> global = env->Global();
17354 : Local<Value> trouble =
17355 20 : global->Get(env.local(), v8_str("bar")).ToLocalChecked();
17356 5 : CHECK(trouble->IsFunction());
17357 10 : CHECK(Function::Cast(*trouble)
17358 : ->Call(env.local(), global, 0, nullptr)
17359 : .IsEmpty());
17360 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17361 5 : isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17362 10 : CHECK_EQ(1, report_count);
17363 5 : }
17364 :
17365 28342 : TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17366 5 : LocalContext env;
17367 5 : v8::Isolate* isolate = env->GetIsolate();
17368 10 : v8::HandleScope scope(isolate);
17369 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
17370 5 : v8::StackTrace::kDetailed);
17371 :
17372 : CompileRun(
17373 : "var setters = ['column', 'lineNumber', 'scriptName',\n"
17374 : " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17375 : " 'isConstructor'];\n"
17376 : "for (var i = 0; i < setters.length; i++) {\n"
17377 : " var prop = setters[i];\n"
17378 : " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17379 : "}\n");
17380 : CompileRun("throw 'exception';");
17381 10 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17382 5 : }
17383 :
17384 : static int asm_warning_triggered = 0;
17385 :
17386 5 : static void AsmJsWarningListener(v8::Local<v8::Message> message,
17387 : v8::Local<Value>) {
17388 : DCHECK_EQ(v8::Isolate::kMessageWarning, message->ErrorLevel());
17389 5 : asm_warning_triggered = 1;
17390 5 : }
17391 :
17392 28342 : TEST(AsmJsWarning) {
17393 5 : i::FLAG_validate_asm = true;
17394 5 : if (i::FLAG_suppress_asm_messages) return;
17395 :
17396 5 : LocalContext env;
17397 5 : v8::Isolate* isolate = env->GetIsolate();
17398 10 : v8::HandleScope scope(isolate);
17399 :
17400 5 : asm_warning_triggered = 0;
17401 : isolate->AddMessageListenerWithErrorLevel(AsmJsWarningListener,
17402 5 : v8::Isolate::kMessageAll);
17403 : CompileRun(
17404 : "function module() {\n"
17405 : " 'use asm';\n"
17406 : " var x = 'hi';\n"
17407 : " return {};\n"
17408 : "}\n"
17409 : "module();");
17410 : DCHECK_EQ(1, asm_warning_triggered);
17411 10 : isolate->RemoveMessageListeners(AsmJsWarningListener);
17412 : }
17413 :
17414 : static int error_level_message_count = 0;
17415 : static int expected_error_level = 0;
17416 :
17417 20 : static void ErrorLevelListener(v8::Local<v8::Message> message,
17418 : v8::Local<Value>) {
17419 : DCHECK_EQ(expected_error_level, message->ErrorLevel());
17420 20 : ++error_level_message_count;
17421 20 : }
17422 :
17423 28342 : TEST(ErrorLevelWarning) {
17424 5 : LocalContext env;
17425 5 : v8::Isolate* isolate = env->GetIsolate();
17426 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
17427 10 : v8::HandleScope scope(isolate);
17428 :
17429 : const char* source = "fake = 1;";
17430 5 : v8::Local<v8::Script> lscript = CompileWithOrigin(source, "test");
17431 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
17432 10 : v8::Utils::OpenHandle(*lscript->GetUnboundScript()));
17433 10 : CHECK(obj->script()->IsScript());
17434 10 : i::Handle<i::Script> script(i::Script::cast(obj->script()), i_isolate);
17435 :
17436 : int levels[] = {
17437 : v8::Isolate::kMessageLog, v8::Isolate::kMessageInfo,
17438 : v8::Isolate::kMessageDebug, v8::Isolate::kMessageWarning,
17439 5 : };
17440 5 : error_level_message_count = 0;
17441 : isolate->AddMessageListenerWithErrorLevel(ErrorLevelListener,
17442 5 : v8::Isolate::kMessageAll);
17443 25 : for (size_t i = 0; i < arraysize(levels); i++) {
17444 20 : i::MessageLocation location(script, 0, 0);
17445 : i::Handle<i::String> msg(i_isolate->factory()->InternalizeOneByteString(
17446 20 : i::StaticCharVector("test")));
17447 : i::Handle<i::JSMessageObject> message =
17448 : i::MessageHandler::MakeMessageObject(
17449 : i_isolate, i::MessageTemplate::kAsmJsInvalid, &location, msg,
17450 20 : i::Handle<i::FixedArray>::null());
17451 20 : message->set_error_level(levels[i]);
17452 20 : expected_error_level = levels[i];
17453 20 : i::MessageHandler::ReportMessage(i_isolate, &location, message);
17454 : }
17455 5 : isolate->RemoveMessageListeners(ErrorLevelListener);
17456 5 : DCHECK_EQ(arraysize(levels), error_level_message_count);
17457 5 : }
17458 :
17459 5 : static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
17460 : v8::Local<Value>) {
17461 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17462 5 : v8::Isolate* isolate = message->GetIsolate();
17463 5 : CHECK_EQ(5, stack_trace->GetFrameCount());
17464 : checkStackFrame("origin", "foo:0", 4, 7, false, false,
17465 5 : stack_trace->GetFrame(isolate, 0));
17466 : checkStackFrame("origin", "foo:1", 5, 27, false, false,
17467 5 : stack_trace->GetFrame(isolate, 1));
17468 : checkStackFrame("origin", "foo", 5, 27, false, false,
17469 5 : stack_trace->GetFrame(isolate, 2));
17470 : checkStackFrame("origin", "foo", 5, 27, false, false,
17471 5 : stack_trace->GetFrame(isolate, 3));
17472 : checkStackFrame("origin", "", 1, 14, false, false,
17473 5 : stack_trace->GetFrame(isolate, 4));
17474 5 : }
17475 :
17476 :
17477 28342 : TEST(GetStackTraceContainsFunctionsWithFunctionName) {
17478 5 : LocalContext env;
17479 5 : v8::Isolate* isolate = env->GetIsolate();
17480 10 : v8::HandleScope scope(isolate);
17481 :
17482 : CompileRunWithOrigin(
17483 : "function gen(name, counter) {\n"
17484 : " var f = function foo() {\n"
17485 : " if (counter === 0)\n"
17486 : " throw 1;\n"
17487 : " gen(name, counter - 1)();\n"
17488 : " };\n"
17489 : " if (counter == 3) {\n"
17490 : " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
17491 : " } else {\n"
17492 : " Object.defineProperty(f, 'name', {writable:true});\n"
17493 : " if (counter == 2)\n"
17494 : " f.name = 42;\n"
17495 : " else\n"
17496 : " f.name = name + ':' + counter;\n"
17497 : " }\n"
17498 : " return f;\n"
17499 : "};",
17500 : "origin");
17501 :
17502 5 : isolate->AddMessageListener(StackTraceFunctionNameListener);
17503 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17504 : CompileRunWithOrigin("gen('foo', 3)();", "origin");
17505 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17506 10 : isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
17507 5 : }
17508 :
17509 :
17510 5 : static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
17511 : v8::Local<v8::Value> data) {
17512 : // Use the frame where JavaScript is called from.
17513 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17514 5 : CHECK(!stack_trace.IsEmpty());
17515 5 : int frame_count = stack_trace->GetFrameCount();
17516 5 : CHECK_EQ(3, frame_count);
17517 5 : int line_number[] = {1, 2, 5};
17518 20 : for (int i = 0; i < frame_count; i++) {
17519 30 : CHECK_EQ(line_number[i],
17520 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
17521 : }
17522 5 : }
17523 :
17524 :
17525 : // Test that we only return the stack trace at the site where the exception
17526 : // is first thrown (not where it is rethrown).
17527 28342 : TEST(RethrowStackTrace) {
17528 5 : LocalContext env;
17529 5 : v8::Isolate* isolate = env->GetIsolate();
17530 10 : v8::HandleScope scope(isolate);
17531 : // We make sure that
17532 : // - the stack trace of the ReferenceError in g() is reported.
17533 : // - the stack trace is not overwritten when e1 is rethrown by t().
17534 : // - the stack trace of e2 does not overwrite that of e1.
17535 : const char* source =
17536 : "function g() { error; } \n"
17537 : "function f() { g(); } \n"
17538 : "function t(e) { throw e; } \n"
17539 : "try { \n"
17540 : " f(); \n"
17541 : "} catch (e1) { \n"
17542 : " try { \n"
17543 : " error; \n"
17544 : " } catch (e2) { \n"
17545 : " t(e1); \n"
17546 : " } \n"
17547 : "} \n";
17548 5 : isolate->AddMessageListener(RethrowStackTraceHandler);
17549 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17550 : CompileRun(source);
17551 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17552 10 : isolate->RemoveMessageListeners(RethrowStackTraceHandler);
17553 5 : }
17554 :
17555 :
17556 5 : static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
17557 : v8::Local<v8::Value> data) {
17558 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17559 5 : CHECK(!stack_trace.IsEmpty());
17560 5 : int frame_count = stack_trace->GetFrameCount();
17561 5 : CHECK_EQ(2, frame_count);
17562 5 : int line_number[] = {3, 7};
17563 15 : for (int i = 0; i < frame_count; i++) {
17564 20 : CHECK_EQ(line_number[i],
17565 : stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
17566 : }
17567 5 : }
17568 :
17569 :
17570 : // Test that we do not recognize identity for primitive exceptions.
17571 28342 : TEST(RethrowPrimitiveStackTrace) {
17572 5 : LocalContext env;
17573 5 : v8::Isolate* isolate = env->GetIsolate();
17574 10 : v8::HandleScope scope(isolate);
17575 : // We do not capture stack trace for non Error objects on creation time.
17576 : // Instead, we capture the stack trace on last throw.
17577 : const char* source =
17578 : "function g() { throw 404; } \n"
17579 : "function f() { g(); } \n"
17580 : "function t(e) { throw e; } \n"
17581 : "try { \n"
17582 : " f(); \n"
17583 : "} catch (e1) { \n"
17584 : " t(e1) \n"
17585 : "} \n";
17586 5 : isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
17587 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17588 : CompileRun(source);
17589 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17590 10 : isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17591 5 : }
17592 :
17593 :
17594 5 : static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
17595 : v8::Local<v8::Value> data) {
17596 : // Use the frame where JavaScript is called from.
17597 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17598 5 : CHECK(!stack_trace.IsEmpty());
17599 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
17600 10 : CHECK_EQ(1, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
17601 5 : }
17602 :
17603 :
17604 : // Test that the stack trace is captured when the error object is created and
17605 : // not where it is thrown.
17606 28342 : TEST(RethrowExistingStackTrace) {
17607 5 : LocalContext env;
17608 5 : v8::Isolate* isolate = env->GetIsolate();
17609 10 : v8::HandleScope scope(isolate);
17610 : const char* source =
17611 : "var e = new Error(); \n"
17612 : "throw e; \n";
17613 5 : isolate->AddMessageListener(RethrowExistingStackTraceHandler);
17614 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17615 : CompileRun(source);
17616 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17617 10 : isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
17618 5 : }
17619 :
17620 :
17621 5 : static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
17622 : v8::Local<v8::Value> data) {
17623 : // Use the frame where JavaScript is called from.
17624 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17625 5 : CHECK(!stack_trace.IsEmpty());
17626 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
17627 10 : CHECK_EQ(2, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
17628 5 : }
17629 :
17630 :
17631 : // Test that the stack trace is captured where the bogus Error object is thrown.
17632 28342 : TEST(RethrowBogusErrorStackTrace) {
17633 5 : LocalContext env;
17634 5 : v8::Isolate* isolate = env->GetIsolate();
17635 10 : v8::HandleScope scope(isolate);
17636 : const char* source =
17637 : "var e = {__proto__: new Error()} \n"
17638 : "throw e; \n";
17639 5 : isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
17640 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17641 : CompileRun(source);
17642 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17643 10 : isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17644 5 : }
17645 :
17646 :
17647 : v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17648 : int promise_reject_counter = 0;
17649 : int promise_revoke_counter = 0;
17650 : int promise_reject_after_resolved_counter = 0;
17651 : int promise_resolve_after_resolved_counter = 0;
17652 : int promise_reject_msg_line_number = -1;
17653 : int promise_reject_msg_column_number = -1;
17654 : int promise_reject_line_number = -1;
17655 : int promise_reject_column_number = -1;
17656 : int promise_reject_frame_count = -1;
17657 : bool promise_reject_is_shared_cross_origin = false;
17658 :
17659 140 : void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
17660 140 : v8::Local<v8::Object> global = CcTest::global();
17661 140 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17662 140 : CHECK_NE(v8::Promise::PromiseState::kPending,
17663 : reject_message.GetPromise()->State());
17664 140 : switch (reject_message.GetEvent()) {
17665 : case v8::kPromiseRejectWithNoHandler: {
17666 95 : promise_reject_counter++;
17667 190 : global->Set(context, v8_str("rejected"), reject_message.GetPromise())
17668 190 : .FromJust();
17669 190 : global->Set(context, v8_str("value"), reject_message.GetValue())
17670 190 : .FromJust();
17671 : v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17672 95 : CcTest::isolate(), reject_message.GetValue());
17673 95 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17674 :
17675 : promise_reject_msg_line_number =
17676 190 : message->GetLineNumber(context).FromJust();
17677 : promise_reject_msg_column_number =
17678 190 : message->GetStartColumn(context).FromJust() + 1;
17679 : promise_reject_is_shared_cross_origin =
17680 95 : message->IsSharedCrossOrigin();
17681 :
17682 95 : if (!stack_trace.IsEmpty()) {
17683 35 : promise_reject_frame_count = stack_trace->GetFrameCount();
17684 35 : if (promise_reject_frame_count > 0) {
17685 150 : CHECK(stack_trace->GetFrame(CcTest::isolate(), 0)
17686 : ->GetScriptName()
17687 : ->Equals(context, v8_str("pro"))
17688 : .FromJust());
17689 : promise_reject_line_number =
17690 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetLineNumber();
17691 : promise_reject_column_number =
17692 60 : stack_trace->GetFrame(CcTest::isolate(), 0)->GetColumn();
17693 : } else {
17694 5 : promise_reject_line_number = -1;
17695 5 : promise_reject_column_number = -1;
17696 : }
17697 : }
17698 : break;
17699 : }
17700 : case v8::kPromiseHandlerAddedAfterReject: {
17701 30 : promise_revoke_counter++;
17702 60 : global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17703 60 : .FromJust();
17704 30 : CHECK(reject_message.GetValue().IsEmpty());
17705 : break;
17706 : }
17707 : case v8::kPromiseRejectAfterResolved: {
17708 10 : promise_reject_after_resolved_counter++;
17709 10 : break;
17710 : }
17711 : case v8::kPromiseResolveAfterResolved: {
17712 5 : promise_resolve_after_resolved_counter++;
17713 5 : break;
17714 : }
17715 : }
17716 140 : }
17717 :
17718 :
17719 600 : v8::Local<v8::Promise> GetPromise(const char* name) {
17720 : return v8::Local<v8::Promise>::Cast(
17721 : CcTest::global()
17722 1800 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17723 1200 : .ToLocalChecked());
17724 : }
17725 :
17726 :
17727 35 : v8::Local<v8::Value> RejectValue() {
17728 : return CcTest::global()
17729 105 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17730 70 : .ToLocalChecked();
17731 : }
17732 :
17733 :
17734 70 : void ResetPromiseStates() {
17735 70 : promise_reject_counter = 0;
17736 70 : promise_revoke_counter = 0;
17737 70 : promise_reject_after_resolved_counter = 0;
17738 70 : promise_resolve_after_resolved_counter = 0;
17739 70 : promise_reject_msg_line_number = -1;
17740 70 : promise_reject_msg_column_number = -1;
17741 70 : promise_reject_line_number = -1;
17742 70 : promise_reject_column_number = -1;
17743 70 : promise_reject_frame_count = -1;
17744 :
17745 70 : v8::Local<v8::Object> global = CcTest::global();
17746 70 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17747 280 : global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17748 280 : global->Set(context, v8_str("value"), v8_str("")).FromJust();
17749 280 : global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17750 70 : }
17751 :
17752 :
17753 28342 : TEST(PromiseRejectCallback) {
17754 5 : LocalContext env;
17755 5 : v8::Isolate* isolate = env->GetIsolate();
17756 10 : v8::HandleScope scope(isolate);
17757 :
17758 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17759 :
17760 5 : ResetPromiseStates();
17761 :
17762 : // Create promise p0.
17763 : CompileRun(
17764 : "var reject; \n"
17765 : "var p0 = new Promise( \n"
17766 : " function(res, rej) { \n"
17767 : " reject = rej; \n"
17768 : " } \n"
17769 : "); \n");
17770 10 : CHECK(!GetPromise("p0")->HasHandler());
17771 5 : CHECK_EQ(0, promise_reject_counter);
17772 5 : CHECK_EQ(0, promise_revoke_counter);
17773 :
17774 : // Add resolve handler (and default reject handler) to p0.
17775 : CompileRun("var p1 = p0.then(function(){});");
17776 10 : CHECK(GetPromise("p0")->HasHandler());
17777 10 : CHECK(!GetPromise("p1")->HasHandler());
17778 5 : CHECK_EQ(0, promise_reject_counter);
17779 5 : CHECK_EQ(0, promise_revoke_counter);
17780 :
17781 : // Reject p0.
17782 : CompileRun("reject('ppp');");
17783 10 : CHECK(GetPromise("p0")->HasHandler());
17784 10 : CHECK(!GetPromise("p1")->HasHandler());
17785 5 : CHECK_EQ(1, promise_reject_counter);
17786 5 : CHECK_EQ(0, promise_revoke_counter);
17787 5 : CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17788 20 : CHECK(
17789 : GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17790 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17791 :
17792 : // Reject p0 again. Callback is not triggered again.
17793 : CompileRun("reject();");
17794 10 : CHECK(GetPromise("p0")->HasHandler());
17795 10 : CHECK(!GetPromise("p1")->HasHandler());
17796 5 : CHECK_EQ(1, promise_reject_counter);
17797 5 : CHECK_EQ(0, promise_revoke_counter);
17798 :
17799 : // Add resolve handler to p1.
17800 : CompileRun("var p2 = p1.then(function(){});");
17801 10 : CHECK(GetPromise("p0")->HasHandler());
17802 10 : CHECK(GetPromise("p1")->HasHandler());
17803 10 : CHECK(!GetPromise("p2")->HasHandler());
17804 5 : CHECK_EQ(2, promise_reject_counter);
17805 5 : CHECK_EQ(1, promise_revoke_counter);
17806 20 : CHECK(
17807 : GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17808 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17809 20 : CHECK(
17810 : GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17811 :
17812 5 : ResetPromiseStates();
17813 :
17814 : // Create promise q0.
17815 : CompileRun(
17816 : "var q0 = new Promise( \n"
17817 : " function(res, rej) { \n"
17818 : " reject = rej; \n"
17819 : " } \n"
17820 : "); \n");
17821 10 : CHECK(!GetPromise("q0")->HasHandler());
17822 5 : CHECK_EQ(0, promise_reject_counter);
17823 5 : CHECK_EQ(0, promise_revoke_counter);
17824 :
17825 : // Add reject handler to q0.
17826 : CompileRun("var q1 = q0.catch(function() {});");
17827 10 : CHECK(GetPromise("q0")->HasHandler());
17828 10 : CHECK(!GetPromise("q1")->HasHandler());
17829 5 : CHECK_EQ(0, promise_reject_counter);
17830 5 : CHECK_EQ(0, promise_revoke_counter);
17831 :
17832 : // Reject q0.
17833 : CompileRun("reject('qq')");
17834 10 : CHECK(GetPromise("q0")->HasHandler());
17835 10 : CHECK(!GetPromise("q1")->HasHandler());
17836 5 : CHECK_EQ(0, promise_reject_counter);
17837 5 : CHECK_EQ(0, promise_revoke_counter);
17838 :
17839 : // Add a new reject handler, which rejects by returning Promise.reject().
17840 : // The returned promise q_ triggers a reject callback at first, only to
17841 : // revoke it when returning it causes q2 to be rejected.
17842 : CompileRun(
17843 : "var q_;"
17844 : "var q2 = q0.catch( \n"
17845 : " function() { \n"
17846 : " q_ = Promise.reject('qqq'); \n"
17847 : " return q_; \n"
17848 : " } \n"
17849 : "); \n");
17850 10 : CHECK(GetPromise("q0")->HasHandler());
17851 10 : CHECK(!GetPromise("q1")->HasHandler());
17852 10 : CHECK(!GetPromise("q2")->HasHandler());
17853 10 : CHECK(GetPromise("q_")->HasHandler());
17854 5 : CHECK_EQ(2, promise_reject_counter);
17855 5 : CHECK_EQ(1, promise_revoke_counter);
17856 20 : CHECK(
17857 : GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17858 20 : CHECK(
17859 : GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17860 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17861 :
17862 : // Add a reject handler to the resolved q1, which rejects by throwing.
17863 : CompileRun(
17864 : "var q3 = q1.then( \n"
17865 : " function() { \n"
17866 : " throw 'qqqq'; \n"
17867 : " } \n"
17868 : "); \n");
17869 10 : CHECK(GetPromise("q0")->HasHandler());
17870 10 : CHECK(GetPromise("q1")->HasHandler());
17871 10 : CHECK(!GetPromise("q2")->HasHandler());
17872 10 : CHECK(!GetPromise("q3")->HasHandler());
17873 5 : CHECK_EQ(3, promise_reject_counter);
17874 5 : CHECK_EQ(1, promise_revoke_counter);
17875 20 : CHECK(
17876 : GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17877 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17878 :
17879 5 : ResetPromiseStates();
17880 :
17881 : // Create promise r0, which has three handlers, two of which handle rejects.
17882 : CompileRun(
17883 : "var r0 = new Promise( \n"
17884 : " function(res, rej) { \n"
17885 : " reject = rej; \n"
17886 : " } \n"
17887 : "); \n"
17888 : "var r1 = r0.catch(function() {}); \n"
17889 : "var r2 = r0.then(function() {}); \n"
17890 : "var r3 = r0.then(function() {}, \n"
17891 : " function() {}); \n");
17892 10 : CHECK(GetPromise("r0")->HasHandler());
17893 10 : CHECK(!GetPromise("r1")->HasHandler());
17894 10 : CHECK(!GetPromise("r2")->HasHandler());
17895 10 : CHECK(!GetPromise("r3")->HasHandler());
17896 5 : CHECK_EQ(0, promise_reject_counter);
17897 5 : CHECK_EQ(0, promise_revoke_counter);
17898 :
17899 : // Reject r0.
17900 : CompileRun("reject('rrr')");
17901 10 : CHECK(GetPromise("r0")->HasHandler());
17902 10 : CHECK(!GetPromise("r1")->HasHandler());
17903 10 : CHECK(!GetPromise("r2")->HasHandler());
17904 10 : CHECK(!GetPromise("r3")->HasHandler());
17905 5 : CHECK_EQ(1, promise_reject_counter);
17906 5 : CHECK_EQ(0, promise_revoke_counter);
17907 20 : CHECK(
17908 : GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17909 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17910 :
17911 : // Add reject handler to r2.
17912 : CompileRun("var r4 = r2.catch(function() {});");
17913 10 : CHECK(GetPromise("r0")->HasHandler());
17914 10 : CHECK(!GetPromise("r1")->HasHandler());
17915 10 : CHECK(GetPromise("r2")->HasHandler());
17916 10 : CHECK(!GetPromise("r3")->HasHandler());
17917 10 : CHECK(!GetPromise("r4")->HasHandler());
17918 5 : CHECK_EQ(1, promise_reject_counter);
17919 5 : CHECK_EQ(1, promise_revoke_counter);
17920 20 : CHECK(
17921 : GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17922 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17923 :
17924 : // Add reject handlers to r4.
17925 : CompileRun("var r5 = r4.then(function() {}, function() {});");
17926 10 : CHECK(GetPromise("r0")->HasHandler());
17927 10 : CHECK(!GetPromise("r1")->HasHandler());
17928 10 : CHECK(GetPromise("r2")->HasHandler());
17929 10 : CHECK(!GetPromise("r3")->HasHandler());
17930 10 : CHECK(GetPromise("r4")->HasHandler());
17931 10 : CHECK(!GetPromise("r5")->HasHandler());
17932 5 : CHECK_EQ(1, promise_reject_counter);
17933 5 : CHECK_EQ(1, promise_revoke_counter);
17934 :
17935 5 : ResetPromiseStates();
17936 :
17937 : // Create promise s0, which has three handlers, none of which handle rejects.
17938 : CompileRun(
17939 : "var s0 = new Promise( \n"
17940 : " function(res, rej) { \n"
17941 : " reject = rej; \n"
17942 : " } \n"
17943 : "); \n"
17944 : "var s1 = s0.then(function() {}); \n"
17945 : "var s2 = s0.then(function() {}); \n"
17946 : "var s3 = s0.then(function() {}); \n");
17947 10 : CHECK(GetPromise("s0")->HasHandler());
17948 10 : CHECK(!GetPromise("s1")->HasHandler());
17949 10 : CHECK(!GetPromise("s2")->HasHandler());
17950 10 : CHECK(!GetPromise("s3")->HasHandler());
17951 5 : CHECK_EQ(0, promise_reject_counter);
17952 5 : CHECK_EQ(0, promise_revoke_counter);
17953 :
17954 : // Reject s0.
17955 : CompileRun("reject('sss')");
17956 10 : CHECK(GetPromise("s0")->HasHandler());
17957 10 : CHECK(!GetPromise("s1")->HasHandler());
17958 10 : CHECK(!GetPromise("s2")->HasHandler());
17959 10 : CHECK(!GetPromise("s3")->HasHandler());
17960 5 : CHECK_EQ(3, promise_reject_counter);
17961 5 : CHECK_EQ(0, promise_revoke_counter);
17962 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17963 :
17964 5 : ResetPromiseStates();
17965 :
17966 : // Swallowed exceptions in the Promise constructor.
17967 : CompileRun(
17968 : "var v0 = new Promise(\n"
17969 : " function(res, rej) {\n"
17970 : " res(1);\n"
17971 : " throw new Error();\n"
17972 : " }\n"
17973 : ");\n");
17974 10 : CHECK(!GetPromise("v0")->HasHandler());
17975 5 : CHECK_EQ(0, promise_reject_counter);
17976 5 : CHECK_EQ(0, promise_revoke_counter);
17977 5 : CHECK_EQ(1, promise_reject_after_resolved_counter);
17978 5 : CHECK_EQ(0, promise_resolve_after_resolved_counter);
17979 :
17980 5 : ResetPromiseStates();
17981 :
17982 : // Duplication resolve.
17983 : CompileRun(
17984 : "var r;\n"
17985 : "var y0 = new Promise(\n"
17986 : " function(res, rej) {\n"
17987 : " r = res;\n"
17988 : " throw new Error();\n"
17989 : " }\n"
17990 : ");\n"
17991 : "r(1);\n");
17992 10 : CHECK(!GetPromise("y0")->HasHandler());
17993 5 : CHECK_EQ(1, promise_reject_counter);
17994 5 : CHECK_EQ(0, promise_revoke_counter);
17995 5 : CHECK_EQ(0, promise_reject_after_resolved_counter);
17996 5 : CHECK_EQ(1, promise_resolve_after_resolved_counter);
17997 :
17998 : // Test stack frames.
17999 5 : env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
18000 :
18001 5 : ResetPromiseStates();
18002 :
18003 : // Create promise t0, which is rejected in the constructor with an error.
18004 : CompileRunWithOrigin(
18005 : "var t0 = new Promise( \n"
18006 : " function(res, rej) { \n"
18007 : " reference_error; \n"
18008 : " } \n"
18009 : "); \n",
18010 5 : "pro", 0, 0);
18011 10 : CHECK(!GetPromise("t0")->HasHandler());
18012 5 : CHECK_EQ(1, promise_reject_counter);
18013 5 : CHECK_EQ(0, promise_revoke_counter);
18014 5 : CHECK_EQ(2, promise_reject_frame_count);
18015 5 : CHECK_EQ(3, promise_reject_line_number);
18016 5 : CHECK_EQ(5, promise_reject_column_number);
18017 5 : CHECK_EQ(3, promise_reject_msg_line_number);
18018 5 : CHECK_EQ(5, promise_reject_msg_column_number);
18019 :
18020 5 : ResetPromiseStates();
18021 :
18022 : // Create promise u0 and chain u1 to it, which is rejected via throw.
18023 : CompileRunWithOrigin(
18024 : "var u0 = Promise.resolve(); \n"
18025 : "var u1 = u0.then( \n"
18026 : " function() { \n"
18027 : " (function() { \n"
18028 : " throw new Error(); \n"
18029 : " })(); \n"
18030 : " } \n"
18031 : " ); \n",
18032 5 : "pro", 0, 0);
18033 10 : CHECK(GetPromise("u0")->HasHandler());
18034 10 : CHECK(!GetPromise("u1")->HasHandler());
18035 5 : CHECK_EQ(1, promise_reject_counter);
18036 5 : CHECK_EQ(0, promise_revoke_counter);
18037 5 : CHECK_EQ(2, promise_reject_frame_count);
18038 5 : CHECK_EQ(5, promise_reject_line_number);
18039 5 : CHECK_EQ(23, promise_reject_column_number);
18040 5 : CHECK_EQ(5, promise_reject_msg_line_number);
18041 5 : CHECK_EQ(23, promise_reject_msg_column_number);
18042 :
18043 : // Throw in u3, which handles u1's rejection.
18044 : CompileRunWithOrigin(
18045 : "function f() { \n"
18046 : " return (function() { \n"
18047 : " return new Error(); \n"
18048 : " })(); \n"
18049 : "} \n"
18050 : "var u2 = Promise.reject(f()); \n"
18051 : "var u3 = u1.catch( \n"
18052 : " function() { \n"
18053 : " return u2; \n"
18054 : " } \n"
18055 : " ); \n",
18056 5 : "pro", 0, 0);
18057 10 : CHECK(GetPromise("u0")->HasHandler());
18058 10 : CHECK(GetPromise("u1")->HasHandler());
18059 10 : CHECK(GetPromise("u2")->HasHandler());
18060 10 : CHECK(!GetPromise("u3")->HasHandler());
18061 5 : CHECK_EQ(3, promise_reject_counter);
18062 5 : CHECK_EQ(2, promise_revoke_counter);
18063 5 : CHECK_EQ(3, promise_reject_frame_count);
18064 5 : CHECK_EQ(3, promise_reject_line_number);
18065 5 : CHECK_EQ(12, promise_reject_column_number);
18066 5 : CHECK_EQ(3, promise_reject_msg_line_number);
18067 5 : CHECK_EQ(12, promise_reject_msg_column_number);
18068 :
18069 5 : ResetPromiseStates();
18070 :
18071 : // Create promise rejected promise v0, which is incorrectly handled by v1
18072 : // via chaining cycle.
18073 : CompileRunWithOrigin(
18074 : "var v0 = Promise.reject(); \n"
18075 : "var v1 = v0.catch( \n"
18076 : " function() { \n"
18077 : " return v1; \n"
18078 : " } \n"
18079 : " ); \n",
18080 5 : "pro", 0, 0);
18081 10 : CHECK(GetPromise("v0")->HasHandler());
18082 10 : CHECK(!GetPromise("v1")->HasHandler());
18083 5 : CHECK_EQ(2, promise_reject_counter);
18084 5 : CHECK_EQ(1, promise_revoke_counter);
18085 5 : CHECK_EQ(0, promise_reject_frame_count);
18086 5 : CHECK_EQ(-1, promise_reject_line_number);
18087 5 : CHECK_EQ(-1, promise_reject_column_number);
18088 :
18089 5 : ResetPromiseStates();
18090 :
18091 : // Create promise t1, which rejects by throwing syntax error from eval.
18092 : CompileRunWithOrigin(
18093 : "var t1 = new Promise( \n"
18094 : " function(res, rej) { \n"
18095 : " var content = '\\n\\\n"
18096 : " }'; \n"
18097 : " eval(content); \n"
18098 : " } \n"
18099 : "); \n",
18100 5 : "pro", 0, 0);
18101 10 : CHECK(!GetPromise("t1")->HasHandler());
18102 5 : CHECK_EQ(1, promise_reject_counter);
18103 5 : CHECK_EQ(0, promise_revoke_counter);
18104 5 : CHECK_EQ(2, promise_reject_frame_count);
18105 5 : CHECK_EQ(5, promise_reject_line_number);
18106 5 : CHECK_EQ(10, promise_reject_column_number);
18107 5 : CHECK_EQ(2, promise_reject_msg_line_number);
18108 10 : CHECK_EQ(7, promise_reject_msg_column_number);
18109 5 : }
18110 :
18111 28342 : TEST(PromiseRejectIsSharedCrossOrigin) {
18112 5 : LocalContext env;
18113 5 : v8::Isolate* isolate = env->GetIsolate();
18114 10 : v8::HandleScope scope(isolate);
18115 :
18116 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18117 :
18118 5 : ResetPromiseStates();
18119 :
18120 : // Create promise p0.
18121 : CompileRun(
18122 : "var reject; \n"
18123 : "var p0 = new Promise( \n"
18124 : " function(res, rej) { \n"
18125 : " reject = rej; \n"
18126 : " } \n"
18127 : "); \n");
18128 10 : CHECK(!GetPromise("p0")->HasHandler());
18129 5 : CHECK_EQ(0, promise_reject_counter);
18130 5 : CHECK_EQ(0, promise_revoke_counter);
18131 : // Not set because it's not yet rejected.
18132 5 : CHECK(!promise_reject_is_shared_cross_origin);
18133 :
18134 : // Reject p0.
18135 : CompileRun("reject('ppp');");
18136 5 : CHECK_EQ(1, promise_reject_counter);
18137 5 : CHECK_EQ(0, promise_revoke_counter);
18138 : // Not set because the ScriptOriginOptions is from the script.
18139 5 : CHECK(!promise_reject_is_shared_cross_origin);
18140 :
18141 5 : ResetPromiseStates();
18142 :
18143 : // Create promise p1
18144 : CompileRun(
18145 : "var reject; \n"
18146 : "var p1 = new Promise( \n"
18147 : " function(res, rej) { \n"
18148 : " reject = rej; \n"
18149 : " } \n"
18150 : "); \n");
18151 10 : CHECK(!GetPromise("p1")->HasHandler());
18152 5 : CHECK_EQ(0, promise_reject_counter);
18153 5 : CHECK_EQ(0, promise_revoke_counter);
18154 : // Not set because it's not yet rejected.
18155 5 : CHECK(!promise_reject_is_shared_cross_origin);
18156 :
18157 : // Add resolve handler (and default reject handler) to p1.
18158 : CompileRun("var p2 = p1.then(function(){});");
18159 10 : CHECK(GetPromise("p1")->HasHandler());
18160 10 : CHECK(!GetPromise("p2")->HasHandler());
18161 5 : CHECK_EQ(0, promise_reject_counter);
18162 5 : CHECK_EQ(0, promise_revoke_counter);
18163 :
18164 : // Reject p1.
18165 : CompileRun("reject('ppp');");
18166 5 : CHECK_EQ(1, promise_reject_counter);
18167 5 : CHECK_EQ(0, promise_revoke_counter);
18168 : // Set because the event is from an empty script.
18169 10 : CHECK(promise_reject_is_shared_cross_origin);
18170 5 : }
18171 :
18172 28342 : TEST(PromiseRejectMarkAsHandled) {
18173 5 : LocalContext env;
18174 5 : v8::Isolate* isolate = env->GetIsolate();
18175 10 : v8::HandleScope scope(isolate);
18176 :
18177 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18178 :
18179 5 : ResetPromiseStates();
18180 :
18181 : // Create promise p0.
18182 : CompileRun(
18183 : "var reject; \n"
18184 : "var p0 = new Promise( \n"
18185 : " function(res, rej) { \n"
18186 : " reject = rej; \n"
18187 : " } \n"
18188 : "); \n");
18189 10 : CHECK(!GetPromise("p0")->HasHandler());
18190 5 : CHECK_EQ(0, promise_reject_counter);
18191 5 : CHECK_EQ(0, promise_revoke_counter);
18192 10 : GetPromise("p0")->MarkAsHandled();
18193 :
18194 : // Reject p0. promise_reject_counter shouldn't be incremented because
18195 : // it's marked as handled.
18196 : CompileRun("reject('ppp');");
18197 5 : CHECK_EQ(0, promise_reject_counter);
18198 10 : CHECK_EQ(0, promise_revoke_counter);
18199 5 : }
18200 30 : void PromiseRejectCallbackConstructError(
18201 : v8::PromiseRejectMessage reject_message) {
18202 30 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
18203 30 : CHECK_EQ(v8::Promise::PromiseState::kRejected,
18204 : reject_message.GetPromise()->State());
18205 60 : USE(v8::Script::Compile(context, v8_str("new Error('test')"))
18206 : .ToLocalChecked()
18207 : ->Run(context));
18208 30 : }
18209 :
18210 28342 : TEST(PromiseRejectCallbackConstructError) {
18211 5 : i::FLAG_allow_natives_syntax = true;
18212 5 : LocalContext env;
18213 5 : v8::Isolate* isolate = env->GetIsolate();
18214 10 : v8::HandleScope scope(isolate);
18215 :
18216 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallbackConstructError);
18217 :
18218 5 : ResetPromiseStates();
18219 : CompileRun(
18220 : "function f(p) {"
18221 : " p.catch(() => {});"
18222 : "}"
18223 : "f(Promise.reject());"
18224 : "f(Promise.reject());"
18225 : "%OptimizeFunctionOnNextCall(f);"
18226 : "let p = Promise.reject();"
18227 5 : "f(p);");
18228 5 : }
18229 :
18230 10 : void AnalyzeStackOfEvalWithSourceURL(
18231 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18232 10 : v8::HandleScope scope(args.GetIsolate());
18233 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18234 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18235 10 : CHECK_EQ(5, stackTrace->GetFrameCount());
18236 10 : v8::Local<v8::String> url = v8_str("eval_url");
18237 40 : for (int i = 0; i < 3; i++) {
18238 : v8::Local<v8::String> name =
18239 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18240 30 : CHECK(!name.IsEmpty());
18241 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18242 10 : }
18243 10 : }
18244 :
18245 :
18246 28342 : TEST(SourceURLInStackTrace) {
18247 5 : v8::Isolate* isolate = CcTest::isolate();
18248 5 : v8::HandleScope scope(isolate);
18249 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18250 : templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18251 : v8::FunctionTemplate::New(isolate,
18252 15 : AnalyzeStackOfEvalWithSourceURL));
18253 10 : LocalContext context(nullptr, templ);
18254 :
18255 : const char *source =
18256 : "function outer() {\n"
18257 : "function bar() {\n"
18258 : " AnalyzeStackOfEvalWithSourceURL();\n"
18259 : "}\n"
18260 : "function foo() {\n"
18261 : "\n"
18262 : " bar();\n"
18263 : "}\n"
18264 : "foo();\n"
18265 : "}\n"
18266 : "eval('(' + outer +')()%s');";
18267 :
18268 : i::ScopedVector<char> code(1024);
18269 5 : i::SNPrintF(code, source, "//# sourceURL=eval_url");
18270 5 : CHECK(CompileRun(code.start())->IsUndefined());
18271 5 : i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18272 10 : CHECK(CompileRun(code.start())->IsUndefined());
18273 5 : }
18274 :
18275 :
18276 : static int scriptIdInStack[2];
18277 :
18278 5 : void AnalyzeScriptIdInStack(
18279 20 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18280 5 : v8::HandleScope scope(args.GetIsolate());
18281 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18282 5 : args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18283 5 : CHECK_EQ(2, stackTrace->GetFrameCount());
18284 10 : for (int i = 0; i < 2; i++) {
18285 : scriptIdInStack[i] =
18286 30 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptId();
18287 5 : }
18288 5 : }
18289 :
18290 :
18291 28342 : TEST(ScriptIdInStackTrace) {
18292 5 : v8::Isolate* isolate = CcTest::isolate();
18293 5 : v8::HandleScope scope(isolate);
18294 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18295 : templ->Set(v8_str("AnalyzeScriptIdInStack"),
18296 15 : v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18297 10 : LocalContext context(nullptr, templ);
18298 :
18299 : v8::Local<v8::String> scriptSource = v8_str(
18300 : "function foo() {\n"
18301 : " AnalyzeScriptIdInStack();"
18302 : "}\n"
18303 5 : "foo();\n");
18304 : v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18305 5 : script->Run(context.local()).ToLocalChecked();
18306 15 : for (int i = 0; i < 2; i++) {
18307 10 : CHECK_NE(scriptIdInStack[i], v8::Message::kNoScriptIdInfo);
18308 20 : CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18309 5 : }
18310 5 : }
18311 :
18312 :
18313 10 : void AnalyzeStackOfInlineScriptWithSourceURL(
18314 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18315 10 : v8::HandleScope scope(args.GetIsolate());
18316 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18317 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18318 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18319 10 : v8::Local<v8::String> url = v8_str("source_url");
18320 40 : for (int i = 0; i < 3; i++) {
18321 : v8::Local<v8::String> name =
18322 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18323 30 : CHECK(!name.IsEmpty());
18324 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18325 10 : }
18326 10 : }
18327 :
18328 :
18329 28342 : TEST(InlineScriptWithSourceURLInStackTrace) {
18330 5 : v8::Isolate* isolate = CcTest::isolate();
18331 5 : v8::HandleScope scope(isolate);
18332 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18333 : templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18334 : v8::FunctionTemplate::New(
18335 15 : CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18336 10 : LocalContext context(nullptr, templ);
18337 :
18338 : const char *source =
18339 : "function outer() {\n"
18340 : "function bar() {\n"
18341 : " AnalyzeStackOfInlineScriptWithSourceURL();\n"
18342 : "}\n"
18343 : "function foo() {\n"
18344 : "\n"
18345 : " bar();\n"
18346 : "}\n"
18347 : "foo();\n"
18348 : "}\n"
18349 : "outer()\n%s";
18350 :
18351 : i::ScopedVector<char> code(1024);
18352 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18353 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18354 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18355 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18356 5 : }
18357 :
18358 395 : void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
18359 : CcTest::global()
18360 1185 : ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
18361 790 : .FromJust();
18362 395 : }
18363 :
18364 5 : class PromiseHookData {
18365 : public:
18366 : int before_hook_count = 0;
18367 : int after_hook_count = 0;
18368 : int promise_hook_count = 0;
18369 : int parent_promise_count = 0;
18370 : bool check_value = true;
18371 : std::string promise_hook_value;
18372 :
18373 : void Reset() {
18374 50 : before_hook_count = 0;
18375 50 : after_hook_count = 0;
18376 50 : promise_hook_count = 0;
18377 50 : parent_promise_count = 0;
18378 50 : check_value = true;
18379 50 : promise_hook_value = "";
18380 : }
18381 : };
18382 :
18383 : PromiseHookData* promise_hook_data;
18384 :
18385 350 : void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
18386 : v8::Local<v8::Value> parentPromise) {
18387 350 : promise_hook_data->promise_hook_count++;
18388 350 : switch (type) {
18389 : case v8::PromiseHookType::kInit:
18390 125 : SetPromise("init", promise);
18391 :
18392 125 : if (!parentPromise->IsUndefined()) {
18393 45 : promise_hook_data->parent_promise_count++;
18394 45 : SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
18395 : }
18396 :
18397 : break;
18398 : case v8::PromiseHookType::kResolve:
18399 125 : SetPromise("resolve", promise);
18400 125 : break;
18401 : case v8::PromiseHookType::kBefore:
18402 50 : promise_hook_data->before_hook_count++;
18403 50 : CHECK(promise_hook_data->before_hook_count >
18404 : promise_hook_data->after_hook_count);
18405 300 : CHECK(CcTest::global()
18406 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18407 : .ToLocalChecked()
18408 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
18409 : .FromJust());
18410 50 : SetPromise("before", promise);
18411 50 : break;
18412 : case v8::PromiseHookType::kAfter:
18413 50 : promise_hook_data->after_hook_count++;
18414 50 : CHECK(promise_hook_data->after_hook_count <=
18415 : promise_hook_data->before_hook_count);
18416 50 : if (promise_hook_data->check_value) {
18417 180 : CHECK(
18418 : CcTest::global()
18419 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18420 : .ToLocalChecked()
18421 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18422 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18423 : .FromJust());
18424 : }
18425 50 : SetPromise("after", promise);
18426 50 : break;
18427 : }
18428 350 : }
18429 :
18430 28342 : TEST(PromiseHook) {
18431 5 : LocalContext env;
18432 5 : v8::Isolate* isolate = env->GetIsolate();
18433 10 : v8::HandleScope scope(isolate);
18434 :
18435 5 : v8::Local<v8::Object> global = CcTest::global();
18436 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
18437 :
18438 10 : promise_hook_data = new PromiseHookData();
18439 5 : isolate->SetPromiseHook(CustomPromiseHook);
18440 :
18441 : // Test that an initialized promise is passed to init. Other hooks
18442 : // can not have un initialized promise.
18443 5 : promise_hook_data->check_value = false;
18444 : CompileRun("var p = new Promise(() => {});");
18445 :
18446 15 : auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18447 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18448 : auto init_promise_obj = v8::Local<v8::Promise>::Cast(init_promise);
18449 5 : CHECK_EQ(init_promise_obj->State(), v8::Promise::PromiseState::kPending);
18450 5 : CHECK(!init_promise_obj->HasHandler());
18451 :
18452 5 : promise_hook_data->Reset();
18453 5 : promise_hook_data->promise_hook_value = "fulfilled";
18454 : const char* source =
18455 : "var resolve, value = ''; \n"
18456 : "var p = new Promise(r => resolve = r); \n";
18457 :
18458 : CompileRun(source);
18459 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18460 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18461 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18462 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18463 :
18464 : CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
18465 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18466 15 : auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18467 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18468 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18469 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18470 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18471 :
18472 : CompileRun("resolve(); \n");
18473 : auto resolve_promise =
18474 15 : global->Get(context, v8_str("resolve")).ToLocalChecked();
18475 15 : auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18476 15 : auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18477 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18478 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18479 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18480 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18481 :
18482 : CompileRun("value = ''; var p2 = p1.then(() => { value = 'fulfilled' }); \n");
18483 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18484 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18485 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18486 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18487 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18488 15 : CHECK(GetPromise("p2")->Equals(env.local(), init_promise).FromJust());
18489 15 : CHECK(GetPromise("p1")->Equals(env.local(), parent_promise).FromJust());
18490 15 : CHECK(GetPromise("p2")->Equals(env.local(), before_promise).FromJust());
18491 15 : CHECK(GetPromise("p2")->Equals(env.local(), after_promise).FromJust());
18492 15 : CHECK(GetPromise("p2")->Equals(env.local(), resolve_promise).FromJust());
18493 5 : CHECK_EQ(10, promise_hook_data->promise_hook_count);
18494 :
18495 : promise_hook_data->Reset();
18496 5 : promise_hook_data->promise_hook_value = "rejected";
18497 : source =
18498 : "var reject, value = ''; \n"
18499 : "var p = new Promise((_, r) => reject = r); \n";
18500 :
18501 : CompileRun(source);
18502 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18503 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18504 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18505 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18506 :
18507 : CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
18508 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18509 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18510 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18511 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18512 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18513 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18514 :
18515 : CompileRun("reject(); \n");
18516 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18517 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18518 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18519 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18520 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18521 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18522 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18523 :
18524 : promise_hook_data->Reset();
18525 5 : promise_hook_data->promise_hook_value = "Promise.resolve";
18526 : source =
18527 : "var value = ''; \n"
18528 : "var p = Promise.resolve('Promise.resolve'); \n";
18529 :
18530 : CompileRun(source);
18531 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18532 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18533 : // init hook and resolve hook
18534 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18535 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18536 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18537 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18538 :
18539 : CompileRun("var p1 = p.then((v) => { value = v; }); \n");
18540 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18541 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18542 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18543 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18544 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18545 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18546 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18547 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18548 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18549 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18550 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18551 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18552 :
18553 : promise_hook_data->Reset();
18554 : source =
18555 : "var resolve, value = ''; \n"
18556 : "var p = new Promise((_, r) => resolve = r); \n";
18557 :
18558 : CompileRun(source);
18559 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18560 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18561 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18562 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18563 :
18564 : CompileRun("resolve(); \n");
18565 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18566 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18567 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18568 :
18569 : promise_hook_data->Reset();
18570 : source =
18571 : "var reject, value = ''; \n"
18572 : "var p = new Promise((_, r) => reject = r); \n";
18573 :
18574 : CompileRun(source);
18575 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18576 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18577 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18578 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18579 :
18580 : CompileRun("reject(); \n");
18581 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18582 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18583 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18584 :
18585 : promise_hook_data->Reset();
18586 : // This test triggers after callbacks right after each other, so
18587 : // lets just check the value at the end.
18588 5 : promise_hook_data->check_value = false;
18589 5 : promise_hook_data->promise_hook_value = "Promise.all";
18590 : source =
18591 : "var resolve, value = ''; \n"
18592 : "var tempPromise = new Promise(r => resolve = r); \n"
18593 : "var p = Promise.all([tempPromise]);\n "
18594 : "var p1 = p.then(v => value = v[0]); \n";
18595 :
18596 : CompileRun(source);
18597 : // 1) init hook (tempPromise)
18598 : // 2) init hook (p)
18599 : // 3) init hook (throwaway Promise in Promise.all, p)
18600 : // 4) init hook (p1, p)
18601 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
18602 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
18603 :
18604 5 : promise_hook_data->promise_hook_value = "Promise.all";
18605 : CompileRun("resolve('Promise.all'); \n");
18606 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18607 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18608 : // 5) resolve hook (tempPromise)
18609 : // 6) resolve hook (throwaway Promise in Promise.all)
18610 : // 6) before hook (throwaway Promise in Promise.all)
18611 : // 7) after hook (throwaway Promise in Promise.all)
18612 : // 8) before hook (p)
18613 : // 9) after hook (p)
18614 : // 10) resolve hook (p1)
18615 : // 11) before hook (p1)
18616 : // 12) after hook (p1)
18617 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18618 30 : CHECK(CcTest::global()
18619 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18620 : .ToLocalChecked()
18621 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18622 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18623 : .FromJust());
18624 :
18625 5 : promise_hook_data->Reset();
18626 : // This test triggers after callbacks right after each other, so
18627 : // lets just check the value at the end.
18628 5 : promise_hook_data->check_value = false;
18629 5 : promise_hook_data->promise_hook_value = "Promise.race";
18630 : source =
18631 : "var resolve, value = ''; \n"
18632 : "var tempPromise = new Promise(r => resolve = r); \n"
18633 : "var p = Promise.race([tempPromise]);\n "
18634 : "var p1 = p.then(v => value = v); \n";
18635 :
18636 : CompileRun(source);
18637 : // 1) init hook (tempPromise)
18638 : // 2) init hook (p)
18639 : // 3) init hook (throwaway Promise in Promise.race, p)
18640 : // 4) init hook (p1, p)
18641 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
18642 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
18643 :
18644 5 : promise_hook_data->promise_hook_value = "Promise.race";
18645 : CompileRun("resolve('Promise.race'); \n");
18646 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18647 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18648 : // 5) resolve hook (tempPromise)
18649 : // 6) resolve hook (throwaway Promise in Promise.race)
18650 : // 6) before hook (throwaway Promise in Promise.race)
18651 : // 7) after hook (throwaway Promise in Promise.race)
18652 : // 8) before hook (p)
18653 : // 9) after hook (p)
18654 : // 10) resolve hook (p1)
18655 : // 11) before hook (p1)
18656 : // 12) after hook (p1)
18657 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18658 30 : CHECK(CcTest::global()
18659 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18660 : .ToLocalChecked()
18661 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18662 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18663 : .FromJust());
18664 :
18665 5 : promise_hook_data->Reset();
18666 5 : promise_hook_data->promise_hook_value = "subclass";
18667 : source =
18668 : "var resolve, value = '';\n"
18669 : "class MyPromise extends Promise { \n"
18670 : " then(onFulfilled, onRejected) { \n"
18671 : " return super.then(onFulfilled, onRejected); \n"
18672 : " };\n"
18673 : "};\n"
18674 : "var p = new MyPromise(r => resolve = r);\n";
18675 :
18676 : CompileRun(source);
18677 : // 1) init hook (p)
18678 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18679 :
18680 : CompileRun("var p1 = p.then(() => value = 'subclass');\n");
18681 : // 2) init hook (p1)
18682 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18683 :
18684 : CompileRun("resolve();\n");
18685 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18686 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18687 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18688 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18689 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18690 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18691 : // 3) resolve hook (p)
18692 : // 4) before hook (p)
18693 : // 5) after hook (p)
18694 : // 6) resolve hook (p1)
18695 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18696 :
18697 : promise_hook_data->Reset();
18698 : source =
18699 : "class X extends Promise {\n"
18700 : " static get [Symbol.species]() {\n"
18701 : " return Y;\n"
18702 : " }\n"
18703 : "}\n"
18704 : "class Y {\n"
18705 : " constructor(executor) {\n"
18706 : " return new Proxy(new Promise(executor), {});\n"
18707 : " }\n"
18708 : "}\n"
18709 : "var x = X.resolve().then(() => {});\n";
18710 :
18711 : CompileRun(source);
18712 :
18713 5 : promise_hook_data->Reset();
18714 : source =
18715 : "var resolve, value = '';\n"
18716 : "var p = new Promise(r => resolve = r);\n";
18717 :
18718 : CompileRun(source);
18719 10 : CHECK_EQ(v8::Promise::kPending, GetPromise("p")->State());
18720 : CompileRun("resolve(Promise.resolve(value));\n");
18721 10 : CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State());
18722 5 : CHECK_EQ(9, promise_hook_data->promise_hook_count);
18723 :
18724 10 : delete promise_hook_data;
18725 10 : isolate->SetPromiseHook(nullptr);
18726 5 : }
18727 :
18728 10 : void AnalyzeStackOfDynamicScriptWithSourceURL(
18729 80 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18730 10 : v8::HandleScope scope(args.GetIsolate());
18731 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18732 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18733 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18734 10 : v8::Local<v8::String> url = v8_str("source_url");
18735 40 : for (int i = 0; i < 3; i++) {
18736 : v8::Local<v8::String> name =
18737 90 : stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18738 30 : CHECK(!name.IsEmpty());
18739 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18740 10 : }
18741 10 : }
18742 :
18743 :
18744 28342 : TEST(DynamicWithSourceURLInStackTrace) {
18745 5 : v8::Isolate* isolate = CcTest::isolate();
18746 5 : v8::HandleScope scope(isolate);
18747 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18748 : templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18749 : v8::FunctionTemplate::New(
18750 15 : CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18751 10 : LocalContext context(nullptr, templ);
18752 :
18753 : const char *source =
18754 : "function outer() {\n"
18755 : "function bar() {\n"
18756 : " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18757 : "}\n"
18758 : "function foo() {\n"
18759 : "\n"
18760 : " bar();\n"
18761 : "}\n"
18762 : "foo();\n"
18763 : "}\n"
18764 : "outer()\n%s";
18765 :
18766 : i::ScopedVector<char> code(1024);
18767 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18768 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18769 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18770 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18771 5 : }
18772 :
18773 :
18774 28342 : TEST(DynamicWithSourceURLInStackTraceString) {
18775 5 : LocalContext context;
18776 10 : v8::HandleScope scope(context->GetIsolate());
18777 :
18778 : const char *source =
18779 : "function outer() {\n"
18780 : " function foo() {\n"
18781 : " FAIL.FAIL;\n"
18782 : " }\n"
18783 : " foo();\n"
18784 : "}\n"
18785 : "outer()\n%s";
18786 :
18787 : i::ScopedVector<char> code(1024);
18788 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18789 10 : v8::TryCatch try_catch(context->GetIsolate());
18790 5 : CompileRunWithOrigin(code.start(), "", 0, 0);
18791 5 : CHECK(try_catch.HasCaught());
18792 : v8::String::Utf8Value stack(
18793 : context->GetIsolate(),
18794 15 : try_catch.StackTrace(context.local()).ToLocalChecked());
18795 15 : CHECK_NOT_NULL(strstr(*stack, "at foo (source_url:3:5)"));
18796 5 : }
18797 :
18798 :
18799 28342 : TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18800 5 : LocalContext context;
18801 10 : v8::HandleScope scope(context->GetIsolate());
18802 :
18803 : const char *source =
18804 : "function outer() {\n"
18805 : " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18806 : " //# sourceURL=source_url\";\n"
18807 : " eval(scriptContents);\n"
18808 : " foo(); }\n"
18809 : "outer();\n"
18810 : "//# sourceURL=outer_url";
18811 :
18812 10 : v8::TryCatch try_catch(context->GetIsolate());
18813 : CompileRun(source);
18814 5 : CHECK(try_catch.HasCaught());
18815 :
18816 5 : Local<v8::Message> message = try_catch.Message();
18817 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18818 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18819 5 : "source_url"));
18820 5 : }
18821 :
18822 :
18823 28342 : TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18824 5 : LocalContext context;
18825 10 : v8::HandleScope scope(context->GetIsolate());
18826 :
18827 : const char *source =
18828 : "function outer() {\n"
18829 : " var scriptContents = \"function boo(){ boo(); }\\\n"
18830 : " //# sourceURL=source_url\";\n"
18831 : " eval(scriptContents);\n"
18832 : " boo(); }\n"
18833 : "outer();\n"
18834 : "//# sourceURL=outer_url";
18835 :
18836 10 : v8::TryCatch try_catch(context->GetIsolate());
18837 : CompileRun(source);
18838 5 : CHECK(try_catch.HasCaught());
18839 :
18840 5 : Local<v8::Message> message = try_catch.Message();
18841 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18842 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18843 5 : "source_url"));
18844 5 : }
18845 :
18846 :
18847 5 : static void CreateGarbageInOldSpace() {
18848 : i::Factory* factory = CcTest::i_isolate()->factory();
18849 5 : v8::HandleScope scope(CcTest::isolate());
18850 : i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18851 5005 : for (int i = 0; i < 1000; i++) {
18852 5000 : factory->NewFixedArray(1000, i::TENURED);
18853 5 : }
18854 5 : }
18855 :
18856 :
18857 : // Test that idle notification can be handled and eventually collects garbage.
18858 28342 : TEST(TestIdleNotification) {
18859 5 : if (!i::FLAG_incremental_marking) return;
18860 : ManualGCScope manual_gc_scope;
18861 : const intptr_t MB = 1024 * 1024;
18862 : const double IdlePauseInSeconds = 1.0;
18863 10 : LocalContext env;
18864 10 : v8::HandleScope scope(env->GetIsolate());
18865 5 : intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18866 5 : CreateGarbageInOldSpace();
18867 5 : intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18868 5 : CHECK_GT(size_with_garbage, initial_size + MB);
18869 : bool finished = false;
18870 10 : for (int i = 0; i < 200 && !finished; i++) {
18871 20 : if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
18872 : CcTest::heap()->StartIdleIncrementalMarking(
18873 5 : i::GarbageCollectionReason::kTesting);
18874 : }
18875 : finished = env->GetIsolate()->IdleNotificationDeadline(
18876 30 : (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
18877 : static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
18878 20 : IdlePauseInSeconds);
18879 20 : if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
18880 5 : CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
18881 : }
18882 : }
18883 5 : intptr_t final_size = CcTest::heap()->SizeOfObjects();
18884 5 : CHECK(finished);
18885 5 : CHECK_LT(final_size, initial_size + 1);
18886 : }
18887 :
18888 28342 : TEST(TestMemorySavingsMode) {
18889 5 : LocalContext context;
18890 5 : v8::Isolate* isolate = context->GetIsolate();
18891 15 : v8::internal::Isolate* i_isolate =
18892 : reinterpret_cast<v8::internal::Isolate*>(isolate);
18893 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18894 5 : isolate->EnableMemorySavingsMode();
18895 5 : CHECK(i_isolate->IsMemorySavingsModeActive());
18896 5 : isolate->DisableMemorySavingsMode();
18897 5 : CHECK(!i_isolate->IsMemorySavingsModeActive());
18898 5 : }
18899 :
18900 28342 : TEST(Regress2333) {
18901 5 : LocalContext env;
18902 20 : for (int i = 0; i < 3; i++) {
18903 15 : CcTest::CollectGarbage(i::NEW_SPACE);
18904 5 : }
18905 5 : }
18906 :
18907 : static uint32_t* stack_limit;
18908 :
18909 10 : static void GetStackLimitCallback(
18910 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18911 : stack_limit = reinterpret_cast<uint32_t*>(
18912 10 : CcTest::i_isolate()->stack_guard()->real_climit());
18913 10 : }
18914 :
18915 :
18916 : // Uses the address of a local variable to determine the stack top now.
18917 : // Given a size, returns an address that is that far from the current
18918 : // top of stack.
18919 : static uint32_t* ComputeStackLimit(uint32_t size) {
18920 : uint32_t* answer = &size - (size / sizeof(size));
18921 : // If the size is very large and the stack is very near the bottom of
18922 : // memory then the calculation above may wrap around and give an address
18923 : // that is above the (downwards-growing) stack. In that case we return
18924 : // a very low address.
18925 : if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18926 : return answer;
18927 : }
18928 :
18929 :
18930 : // We need at least 165kB for an x64 debug build with clang and ASAN.
18931 : static const int stack_breathing_room = 256 * i::KB;
18932 :
18933 :
18934 28342 : TEST(SetStackLimit) {
18935 : uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18936 :
18937 : // Set stack limit.
18938 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18939 :
18940 : // Execute a script.
18941 5 : LocalContext env;
18942 10 : v8::HandleScope scope(env->GetIsolate());
18943 : Local<v8::FunctionTemplate> fun_templ =
18944 5 : v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18945 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18946 25 : CHECK(env->Global()
18947 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18948 : .FromJust());
18949 : CompileRun("get_stack_limit();");
18950 :
18951 10 : CHECK(stack_limit == set_limit);
18952 5 : }
18953 :
18954 :
18955 28342 : TEST(SetStackLimitInThread) {
18956 : uint32_t* set_limit;
18957 : {
18958 5 : v8::Locker locker(CcTest::isolate());
18959 : set_limit = ComputeStackLimit(stack_breathing_room);
18960 :
18961 : // Set stack limit.
18962 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18963 :
18964 : // Execute a script.
18965 10 : v8::HandleScope scope(CcTest::isolate());
18966 10 : LocalContext env;
18967 : Local<v8::FunctionTemplate> fun_templ =
18968 5 : v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18969 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18970 25 : CHECK(env->Global()
18971 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18972 : .FromJust());
18973 : CompileRun("get_stack_limit();");
18974 :
18975 10 : CHECK(stack_limit == set_limit);
18976 : }
18977 : {
18978 5 : v8::Locker locker(CcTest::isolate());
18979 5 : CHECK(stack_limit == set_limit);
18980 : }
18981 5 : }
18982 :
18983 28343 : THREADED_TEST(GetHeapStatistics) {
18984 6 : LocalContext c1;
18985 12 : v8::HandleScope scope(c1->GetIsolate());
18986 6 : v8::HeapStatistics heap_statistics;
18987 6 : CHECK_EQ(0u, heap_statistics.total_heap_size());
18988 6 : CHECK_EQ(0u, heap_statistics.used_heap_size());
18989 6 : c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18990 6 : CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18991 12 : CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18992 6 : }
18993 :
18994 28342 : TEST(GetHeapSpaceStatistics) {
18995 5 : LocalContext c1;
18996 5 : v8::Isolate* isolate = c1->GetIsolate();
18997 10 : v8::HandleScope scope(isolate);
18998 5 : v8::HeapStatistics heap_statistics;
18999 :
19000 : // Force allocation in LO_SPACE so that every space has non-zero size.
19001 : v8::internal::Isolate* i_isolate =
19002 : reinterpret_cast<v8::internal::Isolate*>(isolate);
19003 5 : auto unused = i_isolate->factory()->TryNewFixedArray(512 * 1024, i::TENURED);
19004 : USE(unused);
19005 :
19006 5 : isolate->GetHeapStatistics(&heap_statistics);
19007 :
19008 : // Ensure that the sum of all the spaces matches the totals from
19009 : // GetHeapSpaceStatics.
19010 : size_t total_size = 0u;
19011 : size_t total_used_size = 0u;
19012 : size_t total_available_size = 0u;
19013 : size_t total_physical_size = 0u;
19014 45 : for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); ++i) {
19015 40 : v8::HeapSpaceStatistics space_statistics;
19016 40 : isolate->GetHeapSpaceStatistics(&space_statistics, i);
19017 40 : CHECK_NOT_NULL(space_statistics.space_name());
19018 75 : if (strcmp(space_statistics.space_name(), "new_large_object_space") == 0 ||
19019 35 : strcmp(space_statistics.space_name(), "code_large_object_space") == 0) {
19020 10 : continue;
19021 : }
19022 30 : CHECK_GT(space_statistics.space_size(), 0u);
19023 30 : total_size += space_statistics.space_size();
19024 30 : CHECK_GT(space_statistics.space_used_size(), 0u);
19025 30 : total_used_size += space_statistics.space_used_size();
19026 30 : total_available_size += space_statistics.space_available_size();
19027 30 : CHECK_GT(space_statistics.physical_space_size(), 0u);
19028 30 : total_physical_size += space_statistics.physical_space_size();
19029 : }
19030 10 : total_available_size += CcTest::heap()->memory_allocator()->Available();
19031 :
19032 5 : CHECK_EQ(total_size, heap_statistics.total_heap_size());
19033 5 : CHECK_EQ(total_used_size, heap_statistics.used_heap_size());
19034 5 : CHECK_EQ(total_available_size, heap_statistics.total_available_size());
19035 10 : CHECK_EQ(total_physical_size, heap_statistics.total_physical_size());
19036 5 : }
19037 :
19038 28342 : TEST(NumberOfNativeContexts) {
19039 : static const size_t kNumTestContexts = 10;
19040 : i::Isolate* isolate = CcTest::i_isolate();
19041 : i::HandleScope scope(isolate);
19042 110 : v8::Global<v8::Context> context[kNumTestContexts];
19043 5 : v8::HeapStatistics heap_statistics;
19044 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
19045 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19046 5 : CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
19047 55 : for (size_t i = 0; i < kNumTestContexts; i++) {
19048 : i::HandleScope inner(isolate);
19049 100 : context[i].Reset(CcTest::isolate(), v8::Context::New(CcTest::isolate()));
19050 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19051 50 : CHECK_EQ(i + 1, heap_statistics.number_of_native_contexts());
19052 : }
19053 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
19054 50 : context[i].Reset();
19055 50 : CcTest::PreciseCollectAllGarbage();
19056 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19057 50 : CHECK_EQ(kNumTestContexts - i - 1u,
19058 : heap_statistics.number_of_native_contexts());
19059 : }
19060 5 : }
19061 :
19062 28342 : TEST(NumberOfDetachedContexts) {
19063 : static const size_t kNumTestContexts = 10;
19064 : i::Isolate* isolate = CcTest::i_isolate();
19065 : i::HandleScope scope(isolate);
19066 110 : v8::Global<v8::Context> context[kNumTestContexts];
19067 5 : v8::HeapStatistics heap_statistics;
19068 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
19069 5 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19070 5 : CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
19071 55 : for (size_t i = 0; i < kNumTestContexts; i++) {
19072 : i::HandleScope inner(isolate);
19073 50 : v8::Local<v8::Context> local = v8::Context::New(CcTest::isolate());
19074 50 : context[i].Reset(CcTest::isolate(), local);
19075 50 : local->DetachGlobal();
19076 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19077 50 : CHECK_EQ(i + 1, heap_statistics.number_of_detached_contexts());
19078 : }
19079 50 : for (size_t i = 0; i < kNumTestContexts; i++) {
19080 50 : context[i].Reset();
19081 50 : CcTest::PreciseCollectAllGarbage();
19082 50 : CcTest::isolate()->GetHeapStatistics(&heap_statistics);
19083 50 : CHECK_EQ(kNumTestContexts - i - 1u,
19084 : heap_statistics.number_of_detached_contexts());
19085 : }
19086 5 : }
19087 :
19088 : class VisitorImpl : public v8::ExternalResourceVisitor {
19089 : public:
19090 5 : explicit VisitorImpl(TestResource** resource) {
19091 20 : for (int i = 0; i < 4; i++) {
19092 20 : resource_[i] = resource[i];
19093 20 : found_resource_[i] = false;
19094 : }
19095 : }
19096 5 : ~VisitorImpl() override = default;
19097 25 : void VisitExternalString(v8::Local<v8::String> string) override {
19098 25 : if (!string->IsExternal()) {
19099 5 : CHECK(string->IsExternalOneByte());
19100 25 : return;
19101 : }
19102 : v8::String::ExternalStringResource* resource =
19103 : string->GetExternalStringResource();
19104 20 : CHECK(resource);
19105 80 : for (int i = 0; i < 4; i++) {
19106 80 : if (resource_[i] == resource) {
19107 20 : CHECK(!found_resource_[i]);
19108 20 : found_resource_[i] = true;
19109 : }
19110 : }
19111 : }
19112 5 : void CheckVisitedResources() {
19113 25 : for (int i = 0; i < 4; i++) {
19114 20 : CHECK(found_resource_[i]);
19115 : }
19116 5 : }
19117 :
19118 : private:
19119 : v8::String::ExternalStringResource* resource_[4];
19120 : bool found_resource_[4];
19121 : };
19122 :
19123 :
19124 28342 : TEST(ExternalizeOldSpaceTwoByteCons) {
19125 5 : v8::Isolate* isolate = CcTest::isolate();
19126 5 : LocalContext env;
19127 10 : v8::HandleScope scope(isolate);
19128 : v8::Local<v8::String> cons =
19129 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
19130 5 : ->ToString(env.local())
19131 5 : .ToLocalChecked();
19132 10 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19133 5 : CcTest::CollectAllAvailableGarbage();
19134 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
19135 :
19136 : TestResource* resource = new TestResource(
19137 5 : AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
19138 5 : cons->MakeExternal(resource);
19139 :
19140 5 : CHECK(cons->IsExternal());
19141 5 : CHECK_EQ(resource, cons->GetExternalStringResource());
19142 : String::Encoding encoding;
19143 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19144 10 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
19145 5 : }
19146 :
19147 :
19148 28342 : TEST(ExternalizeOldSpaceOneByteCons) {
19149 5 : v8::Isolate* isolate = CcTest::isolate();
19150 5 : LocalContext env;
19151 10 : v8::HandleScope scope(isolate);
19152 : v8::Local<v8::String> cons =
19153 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
19154 5 : ->ToString(env.local())
19155 5 : .ToLocalChecked();
19156 10 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19157 5 : CcTest::CollectAllAvailableGarbage();
19158 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
19159 :
19160 : TestOneByteResource* resource =
19161 5 : new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
19162 5 : cons->MakeExternal(resource);
19163 :
19164 5 : CHECK(cons->IsExternalOneByte());
19165 5 : CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
19166 : String::Encoding encoding;
19167 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19168 10 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
19169 5 : }
19170 :
19171 :
19172 28342 : TEST(VisitExternalStrings) {
19173 5 : v8::Isolate* isolate = CcTest::isolate();
19174 5 : LocalContext env;
19175 10 : v8::HandleScope scope(isolate);
19176 : const char* string = "Some string";
19177 5 : uint16_t* two_byte_string = AsciiToTwoByteString(string);
19178 : TestResource* resource[4];
19179 10 : resource[0] = new TestResource(two_byte_string);
19180 : v8::Local<v8::String> string0 =
19181 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
19182 5 : .ToLocalChecked();
19183 10 : resource[1] = new TestResource(two_byte_string, nullptr, false);
19184 : v8::Local<v8::String> string1 =
19185 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
19186 5 : .ToLocalChecked();
19187 :
19188 : // Externalized symbol.
19189 10 : resource[2] = new TestResource(two_byte_string, nullptr, false);
19190 : v8::Local<v8::String> string2 =
19191 : v8::String::NewFromUtf8(env->GetIsolate(), string,
19192 5 : v8::NewStringType::kInternalized)
19193 5 : .ToLocalChecked();
19194 5 : CHECK(string2->MakeExternal(resource[2]));
19195 :
19196 : // Symbolized External.
19197 10 : resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
19198 : v8::Local<v8::String> string3 =
19199 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
19200 5 : .ToLocalChecked();
19201 5 : CcTest::CollectAllAvailableGarbage(); // Tenure string.
19202 : // Turn into a symbol.
19203 : i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
19204 10 : CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
19205 : string3_i).is_null());
19206 10 : CHECK(string3_i->IsInternalizedString());
19207 :
19208 : // We need to add usages for string* to avoid warnings in GCC 4.7
19209 5 : CHECK(string0->IsExternal());
19210 5 : CHECK(string1->IsExternal());
19211 5 : CHECK(string2->IsExternal());
19212 5 : CHECK(string3->IsExternal());
19213 :
19214 : VisitorImpl visitor(resource);
19215 5 : isolate->VisitExternalResources(&visitor);
19216 10 : visitor.CheckVisitedResources();
19217 5 : }
19218 :
19219 :
19220 28342 : TEST(ExternalStringCollectedAtTearDown) {
19221 5 : int destroyed = 0;
19222 : v8::Isolate::CreateParams create_params;
19223 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19224 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
19225 : { v8::Isolate::Scope isolate_scope(isolate);
19226 10 : v8::HandleScope handle_scope(isolate);
19227 : const char* s = "One string to test them all, one string to find them.";
19228 : TestOneByteResource* inscription =
19229 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
19230 : v8::Local<v8::String> ring =
19231 5 : v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
19232 : // Ring is still alive. Orcs are roaming freely across our lands.
19233 5 : CHECK_EQ(0, destroyed);
19234 : USE(ring);
19235 : }
19236 :
19237 5 : isolate->Dispose();
19238 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19239 5 : CHECK_EQ(1, destroyed);
19240 5 : }
19241 :
19242 :
19243 28342 : TEST(ExternalInternalizedStringCollectedAtTearDown) {
19244 5 : int destroyed = 0;
19245 : v8::Isolate::CreateParams create_params;
19246 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19247 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
19248 : { v8::Isolate::Scope isolate_scope(isolate);
19249 5 : LocalContext env(isolate);
19250 10 : v8::HandleScope handle_scope(isolate);
19251 : CompileRun("var ring = 'One string to test them all';");
19252 : const char* s = "One string to test them all";
19253 : TestOneByteResource* inscription =
19254 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
19255 : v8::Local<v8::String> ring =
19256 10 : CompileRun("ring")->ToString(env.local()).ToLocalChecked();
19257 10 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19258 5 : ring->MakeExternal(inscription);
19259 : // Ring is still alive. Orcs are roaming freely across our lands.
19260 5 : CHECK_EQ(0, destroyed);
19261 : USE(ring);
19262 : }
19263 :
19264 5 : isolate->Dispose();
19265 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19266 5 : CHECK_EQ(1, destroyed);
19267 5 : }
19268 :
19269 :
19270 28342 : TEST(ExternalInternalizedStringCollectedAtGC) {
19271 5 : int destroyed = 0;
19272 5 : { LocalContext env;
19273 10 : v8::HandleScope handle_scope(env->GetIsolate());
19274 : CompileRun("var ring = 'One string to test them all';");
19275 : const char* s = "One string to test them all";
19276 : TestOneByteResource* inscription =
19277 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
19278 : v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
19279 10 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19280 5 : ring->MakeExternal(inscription);
19281 : // Ring is still alive. Orcs are roaming freely across our lands.
19282 5 : CHECK_EQ(0, destroyed);
19283 5 : USE(ring);
19284 : }
19285 :
19286 : // Garbage collector deals swift blows to evil.
19287 5 : CcTest::i_isolate()->compilation_cache()->Clear();
19288 5 : CcTest::CollectAllAvailableGarbage();
19289 :
19290 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19291 5 : CHECK_EQ(1, destroyed);
19292 5 : }
19293 :
19294 :
19295 : static double DoubleFromBits(uint64_t value) {
19296 : double target;
19297 : i::MemCopy(&target, &value, sizeof(target));
19298 : return target;
19299 : }
19300 :
19301 :
19302 : static uint64_t DoubleToBits(double value) {
19303 : uint64_t target;
19304 : i::MemCopy(&target, &value, sizeof(target));
19305 : return target;
19306 : }
19307 :
19308 :
19309 120 : static double DoubleToDateTime(double input) {
19310 : double date_limit = 864e13;
19311 120 : if (std::isnan(input) || input < -date_limit || input > date_limit) {
19312 : return std::numeric_limits<double>::quiet_NaN();
19313 : }
19314 60 : return (input < 0) ? -(std::floor(-input)) : std::floor(input);
19315 : }
19316 :
19317 :
19318 : // We don't have a consistent way to write 64-bit constants syntactically, so we
19319 : // split them into two 32-bit constants and combine them programmatically.
19320 : static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
19321 : return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
19322 : }
19323 :
19324 :
19325 28343 : THREADED_TEST(QuietSignalingNaNs) {
19326 6 : LocalContext context;
19327 6 : v8::Isolate* isolate = context->GetIsolate();
19328 12 : v8::HandleScope scope(isolate);
19329 12 : v8::TryCatch try_catch(isolate);
19330 :
19331 : // Special double values.
19332 : double snan = DoubleFromBits(0x7FF00000, 0x00000001);
19333 : double qnan = DoubleFromBits(0x7FF80000, 0x00000000);
19334 : double infinity = DoubleFromBits(0x7FF00000, 0x00000000);
19335 : double max_normal = DoubleFromBits(0x7FEFFFFF, 0xFFFFFFFFu);
19336 : double min_normal = DoubleFromBits(0x00100000, 0x00000000);
19337 : double max_denormal = DoubleFromBits(0x000FFFFF, 0xFFFFFFFFu);
19338 : double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
19339 :
19340 : // Date values are capped at +/-100000000 days (times 864e5 ms per day)
19341 : // on either side of the epoch.
19342 : double date_limit = 864e13;
19343 :
19344 : double test_values[] = {
19345 : snan,
19346 : qnan,
19347 : infinity,
19348 : max_normal,
19349 : date_limit + 1,
19350 : date_limit,
19351 : min_normal,
19352 : max_denormal,
19353 : min_denormal,
19354 : 0,
19355 : -0,
19356 : -min_denormal,
19357 : -max_denormal,
19358 : -min_normal,
19359 : -date_limit,
19360 : -date_limit - 1,
19361 : -max_normal,
19362 : -infinity,
19363 : -qnan,
19364 : -snan
19365 6 : };
19366 : int num_test_values = 20;
19367 :
19368 126 : for (int i = 0; i < num_test_values; i++) {
19369 120 : double test_value = test_values[i];
19370 :
19371 : // Check that Number::New preserves non-NaNs and quiets SNaNs.
19372 120 : v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
19373 240 : double stored_number = number->NumberValue(context.local()).FromJust();
19374 120 : if (!std::isnan(test_value)) {
19375 96 : CHECK_EQ(test_value, stored_number);
19376 : } else {
19377 : uint64_t stored_bits = DoubleToBits(stored_number);
19378 : // Check if quiet nan (bits 51..62 all set).
19379 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19380 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
19381 : !defined(USE_SIMULATOR)
19382 : // Most significant fraction bit for quiet nan is set to 0
19383 : // on MIPS architecture. Allowed by IEEE-754.
19384 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
19385 : #else
19386 24 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
19387 : #endif
19388 : }
19389 :
19390 : // Check that Date::New preserves non-NaNs in the date range and
19391 : // quiets SNaNs.
19392 : v8::Local<v8::Value> date =
19393 120 : v8::Date::New(context.local(), test_value).ToLocalChecked();
19394 120 : double expected_stored_date = DoubleToDateTime(test_value);
19395 240 : double stored_date = date->NumberValue(context.local()).FromJust();
19396 120 : if (!std::isnan(expected_stored_date)) {
19397 60 : CHECK_EQ(expected_stored_date, stored_date);
19398 : } else {
19399 : uint64_t stored_bits = DoubleToBits(stored_date);
19400 : // Check if quiet nan (bits 51..62 all set).
19401 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19402 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
19403 : !defined(USE_SIMULATOR)
19404 : // Most significant fraction bit for quiet nan is set to 0
19405 : // on MIPS architecture. Allowed by IEEE-754.
19406 : CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
19407 : #else
19408 60 : CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
19409 : #endif
19410 : }
19411 6 : }
19412 6 : }
19413 :
19414 :
19415 66 : static void SpaghettiIncident(
19416 198 : const v8::FunctionCallbackInfo<v8::Value>& args) {
19417 66 : v8::HandleScope scope(args.GetIsolate());
19418 132 : v8::TryCatch tc(args.GetIsolate());
19419 : v8::MaybeLocal<v8::String> str(
19420 132 : args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
19421 : USE(str);
19422 66 : if (tc.HasCaught())
19423 132 : tc.ReThrow();
19424 66 : }
19425 :
19426 :
19427 : // Test that an exception can be propagated down through a spaghetti
19428 : // stack using ReThrow.
19429 28343 : THREADED_TEST(SpaghettiStackReThrow) {
19430 6 : v8::Isolate* isolate = CcTest::isolate();
19431 6 : v8::HandleScope scope(isolate);
19432 12 : LocalContext context;
19433 : context->Global()
19434 : ->Set(context.local(), v8_str("s"),
19435 6 : v8::FunctionTemplate::New(isolate, SpaghettiIncident)
19436 18 : ->GetFunction(context.local())
19437 30 : .ToLocalChecked())
19438 12 : .FromJust();
19439 12 : v8::TryCatch try_catch(isolate);
19440 : CompileRun(
19441 : "var i = 0;"
19442 : "var o = {"
19443 : " toString: function () {"
19444 : " if (i == 10) {"
19445 : " throw 'Hey!';"
19446 : " } else {"
19447 : " i++;"
19448 : " return s(o);"
19449 : " }"
19450 : " }"
19451 : "};"
19452 : "s(o);");
19453 6 : CHECK(try_catch.HasCaught());
19454 12 : v8::String::Utf8Value value(isolate, try_catch.Exception());
19455 12 : CHECK_EQ(0, strcmp(*value, "Hey!"));
19456 6 : }
19457 :
19458 :
19459 28342 : TEST(Regress528) {
19460 : ManualGCScope manual_gc_scope;
19461 5 : v8::V8::Initialize();
19462 5 : v8::Isolate* isolate = CcTest::isolate();
19463 5 : i::FLAG_retain_maps_for_n_gc = 0;
19464 10 : v8::HandleScope scope(isolate);
19465 : v8::Local<Context> other_context;
19466 : int gc_count;
19467 :
19468 : // Create a context used to keep the code from aging in the compilation
19469 : // cache.
19470 5 : other_context = Context::New(isolate);
19471 :
19472 : // Context-dependent context data creates reference from the compilation
19473 : // cache to the global object.
19474 : const char* source_simple = "1";
19475 : {
19476 5 : v8::HandleScope scope(isolate);
19477 5 : v8::Local<Context> context = Context::New(isolate);
19478 :
19479 5 : context->Enter();
19480 5 : Local<v8::String> obj = v8_str("");
19481 5 : context->SetEmbedderData(0, obj);
19482 : CompileRun(source_simple);
19483 5 : context->Exit();
19484 : }
19485 5 : isolate->ContextDisposedNotification();
19486 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19487 5 : other_context->Enter();
19488 : CompileRun(source_simple);
19489 5 : other_context->Exit();
19490 5 : CcTest::CollectAllGarbage();
19491 5 : if (GetGlobalObjectsCount() == 1) break;
19492 : }
19493 5 : CHECK_GE(2, gc_count);
19494 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19495 :
19496 : // Eval in a function creates reference from the compilation cache to the
19497 : // global object.
19498 : const char* source_eval = "function f(){eval('1')}; f()";
19499 : {
19500 5 : v8::HandleScope scope(isolate);
19501 5 : v8::Local<Context> context = Context::New(isolate);
19502 :
19503 5 : context->Enter();
19504 : CompileRun(source_eval);
19505 5 : context->Exit();
19506 : }
19507 5 : isolate->ContextDisposedNotification();
19508 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19509 5 : other_context->Enter();
19510 : CompileRun(source_eval);
19511 5 : other_context->Exit();
19512 5 : CcTest::CollectAllGarbage();
19513 5 : if (GetGlobalObjectsCount() == 1) break;
19514 : }
19515 5 : CHECK_GE(2, gc_count);
19516 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19517 :
19518 : // Looking up the line number for an exception creates reference from the
19519 : // compilation cache to the global object.
19520 : const char* source_exception = "function f(){throw 1;} f()";
19521 : {
19522 5 : v8::HandleScope scope(isolate);
19523 5 : v8::Local<Context> context = Context::New(isolate);
19524 :
19525 5 : context->Enter();
19526 10 : v8::TryCatch try_catch(isolate);
19527 : CompileRun(source_exception);
19528 5 : CHECK(try_catch.HasCaught());
19529 5 : v8::Local<v8::Message> message = try_catch.Message();
19530 5 : CHECK(!message.IsEmpty());
19531 10 : CHECK_EQ(1, message->GetLineNumber(context).FromJust());
19532 10 : context->Exit();
19533 : }
19534 5 : isolate->ContextDisposedNotification();
19535 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19536 5 : other_context->Enter();
19537 : CompileRun(source_exception);
19538 5 : other_context->Exit();
19539 5 : CcTest::CollectAllGarbage();
19540 5 : if (GetGlobalObjectsCount() == 1) break;
19541 : }
19542 5 : CHECK_GE(2, gc_count);
19543 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19544 :
19545 5 : isolate->ContextDisposedNotification();
19546 5 : }
19547 :
19548 :
19549 28343 : THREADED_TEST(ScriptOrigin) {
19550 6 : LocalContext env;
19551 6 : v8::Isolate* isolate = env->GetIsolate();
19552 12 : v8::HandleScope scope(isolate);
19553 6 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 1));
19554 6 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
19555 6 : array->Set(isolate, 0, symbol);
19556 :
19557 : v8::ScriptOrigin origin = v8::ScriptOrigin(
19558 : v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
19559 : v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
19560 : v8::Local<v8::Integer>(), v8_str("http://sourceMapUrl"),
19561 : v8::True(env->GetIsolate()), v8::False(env->GetIsolate()),
19562 42 : v8::False(env->GetIsolate()), array);
19563 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19564 6 : v8::Script::Compile(env.local(), script, &origin)
19565 6 : .ToLocalChecked()
19566 6 : ->Run(env.local())
19567 6 : .ToLocalChecked();
19568 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19569 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19570 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19571 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19572 :
19573 6 : v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19574 6 : CHECK_EQ(0, strcmp("test",
19575 : *v8::String::Utf8Value(env->GetIsolate(),
19576 : script_origin_f.ResourceName())));
19577 12 : CHECK_EQ(
19578 : 1,
19579 : script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
19580 6 : CHECK(script_origin_f.Options().IsSharedCrossOrigin());
19581 6 : CHECK(script_origin_f.Options().IsOpaque());
19582 6 : printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
19583 12 : CHECK(script_origin_f.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
19584 :
19585 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
19586 : *v8::String::Utf8Value(env->GetIsolate(),
19587 : script_origin_f.SourceMapUrl())));
19588 :
19589 6 : v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19590 6 : CHECK_EQ(0, strcmp("test",
19591 : *v8::String::Utf8Value(env->GetIsolate(),
19592 : script_origin_g.ResourceName())));
19593 12 : CHECK_EQ(
19594 : 1,
19595 : script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
19596 6 : CHECK(script_origin_g.Options().IsSharedCrossOrigin());
19597 6 : CHECK(script_origin_g.Options().IsOpaque());
19598 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
19599 : *v8::String::Utf8Value(env->GetIsolate(),
19600 : script_origin_g.SourceMapUrl())));
19601 18 : CHECK(script_origin_g.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
19602 6 : }
19603 :
19604 :
19605 28343 : THREADED_TEST(FunctionGetInferredName) {
19606 6 : LocalContext env;
19607 12 : v8::HandleScope scope(env->GetIsolate());
19608 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19609 : v8::Local<v8::String> script =
19610 6 : v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19611 6 : v8::Script::Compile(env.local(), script, &origin)
19612 6 : .ToLocalChecked()
19613 6 : ->Run(env.local())
19614 6 : .ToLocalChecked();
19615 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19616 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19617 12 : CHECK_EQ(0,
19618 : strcmp("foo.bar.baz", *v8::String::Utf8Value(env->GetIsolate(),
19619 6 : f->GetInferredName())));
19620 6 : }
19621 :
19622 :
19623 28343 : THREADED_TEST(FunctionGetDebugName) {
19624 6 : LocalContext env;
19625 6 : v8::Isolate* isolate = env->GetIsolate();
19626 12 : v8::HandleScope scope(isolate);
19627 : const char* code =
19628 : "var error = false;"
19629 : "function a() { this.x = 1; };"
19630 : "a.displayName = 'display_a';"
19631 : "var b = (function() {"
19632 : " var f = function() { this.x = 2; };"
19633 : " f.displayName = 'display_b';"
19634 : " return f;"
19635 : "})();"
19636 : "var c = function() {};"
19637 : "c.__defineGetter__('displayName', function() {"
19638 : " error = true;"
19639 : " throw new Error();"
19640 : "});"
19641 : "function d() {};"
19642 : "d.__defineGetter__('displayName', function() {"
19643 : " error = true;"
19644 : " return 'wrong_display_name';"
19645 : "});"
19646 : "function e() {};"
19647 : "e.displayName = 'wrong_display_name';"
19648 : "e.__defineSetter__('displayName', function() {"
19649 : " error = true;"
19650 : " throw new Error();"
19651 : "});"
19652 : "function f() {};"
19653 : "f.displayName = { 'foo': 6, toString: function() {"
19654 : " error = true;"
19655 : " return 'wrong_display_name';"
19656 : "}};"
19657 : "var g = function() {"
19658 : " arguments.callee.displayName = 'set_in_runtime';"
19659 : "}; g();"
19660 : "var h = function() {};"
19661 : "h.displayName = 'displayName';"
19662 : "Object.defineProperty(h, 'name', { value: 'function.name' });"
19663 : "var i = function() {};"
19664 : "i.displayName = 239;"
19665 : "Object.defineProperty(i, 'name', { value: 'function.name' });"
19666 : "var j = function() {};"
19667 : "Object.defineProperty(j, 'name', { value: 'function.name' });"
19668 : "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
19669 : "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
19670 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19671 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19672 6 : .ToLocalChecked()
19673 6 : ->Run(env.local())
19674 6 : .ToLocalChecked();
19675 : v8::Local<v8::Value> error =
19676 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19677 6 : CHECK(!error->BooleanValue(isolate));
19678 : const char* functions[] = {"a", "display_a",
19679 : "b", "display_b",
19680 : "c", "c",
19681 : "d", "d",
19682 : "e", "e",
19683 : "f", "f",
19684 : "g", "set_in_runtime",
19685 : "h", "displayName",
19686 : "i", "function.name",
19687 : "j", "function.name",
19688 : "k", "foo.bar.baz",
19689 6 : "l", "baz"};
19690 78 : for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
19691 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19692 : env->Global()
19693 : ->Get(env.local(),
19694 72 : v8::String::NewFromUtf8(isolate, functions[i * 2],
19695 72 : v8::NewStringType::kNormal)
19696 288 : .ToLocalChecked())
19697 72 : .ToLocalChecked());
19698 72 : CHECK_EQ(0, strcmp(functions[i * 2 + 1],
19699 : *v8::String::Utf8Value(isolate, f->GetDebugName())));
19700 6 : }
19701 6 : }
19702 :
19703 :
19704 28343 : THREADED_TEST(FunctionGetDisplayName) {
19705 6 : LocalContext env;
19706 6 : v8::Isolate* isolate = env->GetIsolate();
19707 12 : v8::HandleScope scope(isolate);
19708 : const char* code = "var error = false;"
19709 : "function a() { this.x = 1; };"
19710 : "a.displayName = 'display_a';"
19711 : "var b = (function() {"
19712 : " var f = function() { this.x = 2; };"
19713 : " f.displayName = 'display_b';"
19714 : " return f;"
19715 : "})();"
19716 : "var c = function() {};"
19717 : "c.__defineGetter__('displayName', function() {"
19718 : " error = true;"
19719 : " throw new Error();"
19720 : "});"
19721 : "function d() {};"
19722 : "d.__defineGetter__('displayName', function() {"
19723 : " error = true;"
19724 : " return 'wrong_display_name';"
19725 : "});"
19726 : "function e() {};"
19727 : "e.displayName = 'wrong_display_name';"
19728 : "e.__defineSetter__('displayName', function() {"
19729 : " error = true;"
19730 : " throw new Error();"
19731 : "});"
19732 : "function f() {};"
19733 : "f.displayName = { 'foo': 6, toString: function() {"
19734 : " error = true;"
19735 : " return 'wrong_display_name';"
19736 : "}};"
19737 : "var g = function() {"
19738 : " arguments.callee.displayName = 'set_in_runtime';"
19739 : "}; g();";
19740 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19741 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19742 6 : .ToLocalChecked()
19743 6 : ->Run(env.local())
19744 6 : .ToLocalChecked();
19745 : v8::Local<v8::Value> error =
19746 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19747 : v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19748 30 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
19749 : v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19750 30 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
19751 : v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19752 30 : env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
19753 : v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19754 30 : env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
19755 : v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19756 30 : env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
19757 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19758 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19759 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19760 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19761 6 : CHECK(!error->BooleanValue(isolate));
19762 6 : CHECK_EQ(0, strcmp("display_a",
19763 : *v8::String::Utf8Value(isolate, a->GetDisplayName())));
19764 6 : CHECK_EQ(0, strcmp("display_b",
19765 : *v8::String::Utf8Value(isolate, b->GetDisplayName())));
19766 12 : CHECK(c->GetDisplayName()->IsUndefined());
19767 12 : CHECK(d->GetDisplayName()->IsUndefined());
19768 12 : CHECK(e->GetDisplayName()->IsUndefined());
19769 12 : CHECK(f->GetDisplayName()->IsUndefined());
19770 6 : CHECK_EQ(0, strcmp("set_in_runtime",
19771 6 : *v8::String::Utf8Value(isolate, g->GetDisplayName())));
19772 6 : }
19773 :
19774 :
19775 28343 : THREADED_TEST(ScriptLineNumber) {
19776 6 : LocalContext env;
19777 12 : v8::HandleScope scope(env->GetIsolate());
19778 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19779 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19780 6 : v8::Script::Compile(env.local(), script, &origin)
19781 6 : .ToLocalChecked()
19782 6 : ->Run(env.local())
19783 6 : .ToLocalChecked();
19784 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19785 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19786 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19787 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19788 6 : CHECK_EQ(0, f->GetScriptLineNumber());
19789 12 : CHECK_EQ(2, g->GetScriptLineNumber());
19790 6 : }
19791 :
19792 :
19793 28343 : THREADED_TEST(ScriptColumnNumber) {
19794 6 : LocalContext env;
19795 6 : v8::Isolate* isolate = env->GetIsolate();
19796 12 : v8::HandleScope scope(isolate);
19797 : v8::ScriptOrigin origin =
19798 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19799 6 : v8::Integer::New(isolate, 2));
19800 : v8::Local<v8::String> script =
19801 6 : v8_str("function foo() {}\n\n function bar() {}");
19802 6 : v8::Script::Compile(env.local(), script, &origin)
19803 6 : .ToLocalChecked()
19804 6 : ->Run(env.local())
19805 6 : .ToLocalChecked();
19806 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19807 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19808 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19809 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19810 6 : CHECK_EQ(14, foo->GetScriptColumnNumber());
19811 12 : CHECK_EQ(17, bar->GetScriptColumnNumber());
19812 6 : }
19813 :
19814 :
19815 28343 : THREADED_TEST(FunctionGetScriptId) {
19816 6 : LocalContext env;
19817 6 : v8::Isolate* isolate = env->GetIsolate();
19818 12 : v8::HandleScope scope(isolate);
19819 : v8::ScriptOrigin origin =
19820 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19821 6 : v8::Integer::New(isolate, 2));
19822 : v8::Local<v8::String> scriptSource =
19823 6 : v8_str("function foo() {}\n\n function bar() {}");
19824 : v8::Local<v8::Script> script(
19825 6 : v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
19826 6 : script->Run(env.local()).ToLocalChecked();
19827 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19828 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19829 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19830 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19831 12 : CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19832 18 : CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19833 6 : }
19834 :
19835 :
19836 28343 : THREADED_TEST(FunctionGetBoundFunction) {
19837 6 : LocalContext env;
19838 12 : v8::HandleScope scope(env->GetIsolate());
19839 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19840 : v8::Local<v8::String> script = v8_str(
19841 : "var a = new Object();\n"
19842 : "a.x = 1;\n"
19843 : "function f () { return this.x };\n"
19844 : "var g = f.bind(a);\n"
19845 6 : "var b = g();");
19846 6 : v8::Script::Compile(env.local(), script, &origin)
19847 6 : .ToLocalChecked()
19848 6 : ->Run(env.local())
19849 6 : .ToLocalChecked();
19850 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19851 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19852 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19853 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19854 12 : CHECK(g->GetBoundFunction()->IsFunction());
19855 : Local<v8::Function> original_function = Local<v8::Function>::Cast(
19856 6 : g->GetBoundFunction());
19857 18 : CHECK(f->GetName()
19858 : ->Equals(env.local(), original_function->GetName())
19859 : .FromJust());
19860 6 : CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19861 6 : CHECK_EQ(f->GetScriptColumnNumber(),
19862 6 : original_function->GetScriptColumnNumber());
19863 6 : }
19864 :
19865 :
19866 330 : static void GetterWhichReturns42(
19867 : Local<String> name,
19868 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19869 660 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19870 660 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19871 330 : info.GetReturnValue().Set(v8_num(42));
19872 330 : }
19873 :
19874 :
19875 270 : static void SetterWhichSetsYOnThisTo23(
19876 : Local<String> name,
19877 : Local<Value> value,
19878 : const v8::PropertyCallbackInfo<void>& info) {
19879 540 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19880 540 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19881 : Local<Object>::Cast(info.This())
19882 810 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19883 540 : .FromJust();
19884 270 : }
19885 :
19886 :
19887 120 : void FooGetInterceptor(Local<Name> name,
19888 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19889 240 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19890 240 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19891 360 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19892 240 : .FromJust()) {
19893 120 : return;
19894 : }
19895 96 : info.GetReturnValue().Set(v8_num(42));
19896 : }
19897 :
19898 :
19899 336 : void FooSetInterceptor(Local<Name> name, Local<Value> value,
19900 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19901 672 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19902 672 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19903 1008 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19904 672 : .FromJust()) {
19905 336 : return;
19906 : }
19907 : Local<Object>::Cast(info.This())
19908 288 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19909 192 : .FromJust();
19910 96 : info.GetReturnValue().Set(v8_num(23));
19911 : }
19912 :
19913 :
19914 28342 : TEST(SetterOnConstructorPrototype) {
19915 5 : v8::Isolate* isolate = CcTest::isolate();
19916 5 : v8::HandleScope scope(isolate);
19917 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19918 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19919 5 : SetterWhichSetsYOnThisTo23);
19920 10 : LocalContext context;
19921 30 : CHECK(context->Global()
19922 : ->Set(context.local(), v8_str("P"),
19923 : templ->NewInstance(context.local()).ToLocalChecked())
19924 : .FromJust());
19925 : CompileRun("function C1() {"
19926 : " this.x = 23;"
19927 : "};"
19928 : "C1.prototype = P;"
19929 : "function C2() {"
19930 : " this.x = 23"
19931 : "};"
19932 : "C2.prototype = { };"
19933 : "C2.prototype.__proto__ = P;");
19934 :
19935 : v8::Local<v8::Script> script;
19936 : script = v8_compile("new C1();");
19937 55 : for (int i = 0; i < 10; i++) {
19938 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19939 50 : script->Run(context.local()).ToLocalChecked());
19940 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19941 : .ToLocalChecked()
19942 : ->Int32Value(context.local())
19943 : .FromJust());
19944 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19945 : .ToLocalChecked()
19946 : ->Int32Value(context.local())
19947 : .FromJust());
19948 : }
19949 :
19950 : script = v8_compile("new C2();");
19951 55 : for (int i = 0; i < 10; i++) {
19952 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19953 50 : script->Run(context.local()).ToLocalChecked());
19954 200 : CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
19955 : .ToLocalChecked()
19956 : ->Int32Value(context.local())
19957 : .FromJust());
19958 200 : CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
19959 : .ToLocalChecked()
19960 : ->Int32Value(context.local())
19961 : .FromJust());
19962 5 : }
19963 5 : }
19964 :
19965 :
19966 0 : static void NamedPropertySetterWhichSetsYOnThisTo23(
19967 : Local<Name> name, Local<Value> value,
19968 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19969 0 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
19970 0 : .FromJust()) {
19971 : Local<Object>::Cast(info.This())
19972 0 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19973 0 : .FromJust();
19974 : }
19975 0 : }
19976 :
19977 :
19978 28343 : THREADED_TEST(InterceptorOnConstructorPrototype) {
19979 6 : v8::Isolate* isolate = CcTest::isolate();
19980 6 : v8::HandleScope scope(isolate);
19981 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19982 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19983 : NamedPropertyGetterWhichReturns42,
19984 6 : NamedPropertySetterWhichSetsYOnThisTo23));
19985 12 : LocalContext context;
19986 36 : CHECK(context->Global()
19987 : ->Set(context.local(), v8_str("P"),
19988 : templ->NewInstance(context.local()).ToLocalChecked())
19989 : .FromJust());
19990 : CompileRun("function C1() {"
19991 : " this.x = 23;"
19992 : "};"
19993 : "C1.prototype = P;"
19994 : "function C2() {"
19995 : " this.x = 23"
19996 : "};"
19997 : "C2.prototype = { };"
19998 : "C2.prototype.__proto__ = P;");
19999 :
20000 : v8::Local<v8::Script> script;
20001 : script = v8_compile("new C1();");
20002 66 : for (int i = 0; i < 10; i++) {
20003 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
20004 60 : script->Run(context.local()).ToLocalChecked());
20005 240 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
20006 : .ToLocalChecked()
20007 : ->Int32Value(context.local())
20008 : .FromJust());
20009 240 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
20010 : .ToLocalChecked()
20011 : ->Int32Value(context.local())
20012 : .FromJust());
20013 : }
20014 :
20015 : script = v8_compile("new C2();");
20016 66 : for (int i = 0; i < 10; i++) {
20017 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
20018 60 : script->Run(context.local()).ToLocalChecked());
20019 240 : CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
20020 : .ToLocalChecked()
20021 : ->Int32Value(context.local())
20022 : .FromJust());
20023 240 : CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
20024 : .ToLocalChecked()
20025 : ->Int32Value(context.local())
20026 : .FromJust());
20027 6 : }
20028 6 : }
20029 :
20030 :
20031 28342 : TEST(Regress618) {
20032 : const char* source = "function C1() {"
20033 : " this.x = 23;"
20034 : "};"
20035 : "C1.prototype = P;";
20036 :
20037 5 : LocalContext context;
20038 5 : v8::Isolate* isolate = context->GetIsolate();
20039 10 : v8::HandleScope scope(isolate);
20040 : v8::Local<v8::Script> script;
20041 :
20042 : // Use a simple object as prototype.
20043 5 : v8::Local<v8::Object> prototype = v8::Object::New(isolate);
20044 20 : prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
20045 25 : CHECK(context->Global()
20046 : ->Set(context.local(), v8_str("P"), prototype)
20047 : .FromJust());
20048 :
20049 : // This compile will add the code to the compilation cache.
20050 : CompileRun(source);
20051 :
20052 : script = v8_compile("new C1();");
20053 : // Allow enough iterations for the inobject slack tracking logic
20054 : // to finalize instance size and install the fast construct stub.
20055 1285 : for (int i = 0; i < 256; i++) {
20056 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
20057 1280 : script->Run(context.local()).ToLocalChecked());
20058 5120 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
20059 : .ToLocalChecked()
20060 : ->Int32Value(context.local())
20061 : .FromJust());
20062 5120 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
20063 : .ToLocalChecked()
20064 : ->Int32Value(context.local())
20065 : .FromJust());
20066 : }
20067 :
20068 : // Use an API object with accessors as prototype.
20069 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20070 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
20071 5 : SetterWhichSetsYOnThisTo23);
20072 30 : CHECK(context->Global()
20073 : ->Set(context.local(), v8_str("P"),
20074 : templ->NewInstance(context.local()).ToLocalChecked())
20075 : .FromJust());
20076 :
20077 : // This compile will get the code from the compilation cache.
20078 : CompileRun(source);
20079 :
20080 : script = v8_compile("new C1();");
20081 55 : for (int i = 0; i < 10; i++) {
20082 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
20083 50 : script->Run(context.local()).ToLocalChecked());
20084 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
20085 : .ToLocalChecked()
20086 : ->Int32Value(context.local())
20087 : .FromJust());
20088 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
20089 : .ToLocalChecked()
20090 : ->Int32Value(context.local())
20091 : .FromJust());
20092 5 : }
20093 5 : }
20094 :
20095 : v8::Isolate* gc_callbacks_isolate = nullptr;
20096 : int prologue_call_count = 0;
20097 : int epilogue_call_count = 0;
20098 : int prologue_call_count_second = 0;
20099 : int epilogue_call_count_second = 0;
20100 : int prologue_call_count_alloc = 0;
20101 : int epilogue_call_count_alloc = 0;
20102 :
20103 20 : void PrologueCallback(v8::Isolate* isolate,
20104 : v8::GCType,
20105 : v8::GCCallbackFlags flags) {
20106 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20107 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20108 20 : ++prologue_call_count;
20109 20 : }
20110 :
20111 20 : void EpilogueCallback(v8::Isolate* isolate,
20112 : v8::GCType,
20113 : v8::GCCallbackFlags flags) {
20114 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20115 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20116 20 : ++epilogue_call_count;
20117 20 : }
20118 :
20119 :
20120 20 : void PrologueCallbackSecond(v8::Isolate* isolate,
20121 : v8::GCType,
20122 : v8::GCCallbackFlags flags) {
20123 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20124 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20125 20 : ++prologue_call_count_second;
20126 20 : }
20127 :
20128 :
20129 20 : void EpilogueCallbackSecond(v8::Isolate* isolate,
20130 : v8::GCType,
20131 : v8::GCCallbackFlags flags) {
20132 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20133 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20134 20 : ++epilogue_call_count_second;
20135 20 : }
20136 :
20137 20 : void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
20138 : v8::GCCallbackFlags flags, void* data) {
20139 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20140 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20141 20 : ++*static_cast<int*>(data);
20142 20 : }
20143 :
20144 20 : void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
20145 : v8::GCCallbackFlags flags, void* data) {
20146 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20147 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
20148 20 : ++*static_cast<int*>(data);
20149 20 : }
20150 :
20151 5 : void PrologueCallbackAlloc(v8::Isolate* isolate,
20152 : v8::GCType,
20153 : v8::GCCallbackFlags flags) {
20154 5 : v8::HandleScope scope(isolate);
20155 :
20156 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20157 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
20158 5 : ++prologue_call_count_alloc;
20159 :
20160 : // Simulate full heap to see if we will reenter this callback
20161 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
20162 :
20163 5 : Local<Object> obj = Object::New(isolate);
20164 5 : CHECK(!obj.IsEmpty());
20165 :
20166 5 : CcTest::PreciseCollectAllGarbage();
20167 5 : }
20168 :
20169 :
20170 5 : void EpilogueCallbackAlloc(v8::Isolate* isolate,
20171 : v8::GCType,
20172 : v8::GCCallbackFlags flags) {
20173 5 : v8::HandleScope scope(isolate);
20174 :
20175 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20176 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
20177 5 : ++epilogue_call_count_alloc;
20178 :
20179 : // Simulate full heap to see if we will reenter this callback
20180 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
20181 :
20182 5 : Local<Object> obj = Object::New(isolate);
20183 5 : CHECK(!obj.IsEmpty());
20184 :
20185 5 : CcTest::PreciseCollectAllGarbage();
20186 5 : }
20187 :
20188 :
20189 28342 : TEST(GCCallbacksOld) {
20190 5 : LocalContext context;
20191 :
20192 5 : gc_callbacks_isolate = context->GetIsolate();
20193 :
20194 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
20195 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
20196 5 : CHECK_EQ(0, prologue_call_count);
20197 5 : CHECK_EQ(0, epilogue_call_count);
20198 5 : CcTest::CollectAllGarbage();
20199 5 : CHECK_EQ(1, prologue_call_count);
20200 5 : CHECK_EQ(1, epilogue_call_count);
20201 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
20202 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
20203 5 : CcTest::CollectAllGarbage();
20204 5 : CHECK_EQ(2, prologue_call_count);
20205 5 : CHECK_EQ(2, epilogue_call_count);
20206 5 : CHECK_EQ(1, prologue_call_count_second);
20207 5 : CHECK_EQ(1, epilogue_call_count_second);
20208 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
20209 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
20210 5 : CcTest::CollectAllGarbage();
20211 5 : CHECK_EQ(2, prologue_call_count);
20212 5 : CHECK_EQ(2, epilogue_call_count);
20213 5 : CHECK_EQ(2, prologue_call_count_second);
20214 5 : CHECK_EQ(2, epilogue_call_count_second);
20215 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
20216 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20217 5 : CcTest::CollectAllGarbage();
20218 5 : CHECK_EQ(2, prologue_call_count);
20219 5 : CHECK_EQ(2, epilogue_call_count);
20220 5 : CHECK_EQ(2, prologue_call_count_second);
20221 5 : CHECK_EQ(2, epilogue_call_count_second);
20222 5 : }
20223 :
20224 28342 : TEST(GCCallbacksWithData) {
20225 5 : LocalContext context;
20226 :
20227 5 : gc_callbacks_isolate = context->GetIsolate();
20228 5 : int prologue1 = 0;
20229 5 : int epilogue1 = 0;
20230 5 : int prologue2 = 0;
20231 5 : int epilogue2 = 0;
20232 :
20233 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
20234 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
20235 5 : CHECK_EQ(0, prologue1);
20236 5 : CHECK_EQ(0, epilogue1);
20237 5 : CHECK_EQ(0, prologue2);
20238 5 : CHECK_EQ(0, epilogue2);
20239 5 : CcTest::CollectAllGarbage();
20240 5 : CHECK_EQ(1, prologue1);
20241 5 : CHECK_EQ(1, epilogue1);
20242 5 : CHECK_EQ(0, prologue2);
20243 5 : CHECK_EQ(0, epilogue2);
20244 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
20245 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
20246 5 : CcTest::CollectAllGarbage();
20247 5 : CHECK_EQ(2, prologue1);
20248 5 : CHECK_EQ(2, epilogue1);
20249 5 : CHECK_EQ(1, prologue2);
20250 5 : CHECK_EQ(1, epilogue2);
20251 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
20252 5 : &prologue1);
20253 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
20254 5 : &epilogue1);
20255 5 : CcTest::CollectAllGarbage();
20256 5 : CHECK_EQ(2, prologue1);
20257 5 : CHECK_EQ(2, epilogue1);
20258 5 : CHECK_EQ(2, prologue2);
20259 5 : CHECK_EQ(2, epilogue2);
20260 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
20261 5 : &prologue2);
20262 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
20263 5 : &epilogue2);
20264 5 : CcTest::CollectAllGarbage();
20265 5 : CHECK_EQ(2, prologue1);
20266 5 : CHECK_EQ(2, epilogue1);
20267 5 : CHECK_EQ(2, prologue2);
20268 5 : CHECK_EQ(2, epilogue2);
20269 5 : }
20270 :
20271 28342 : TEST(GCCallbacks) {
20272 5 : LocalContext context;
20273 5 : v8::Isolate* isolate = context->GetIsolate();
20274 5 : gc_callbacks_isolate = isolate;
20275 5 : isolate->AddGCPrologueCallback(PrologueCallback);
20276 5 : isolate->AddGCEpilogueCallback(EpilogueCallback);
20277 5 : CHECK_EQ(0, prologue_call_count);
20278 5 : CHECK_EQ(0, epilogue_call_count);
20279 5 : CcTest::CollectAllGarbage();
20280 5 : CHECK_EQ(1, prologue_call_count);
20281 5 : CHECK_EQ(1, epilogue_call_count);
20282 5 : isolate->AddGCPrologueCallback(PrologueCallbackSecond);
20283 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
20284 5 : CcTest::CollectAllGarbage();
20285 5 : CHECK_EQ(2, prologue_call_count);
20286 5 : CHECK_EQ(2, epilogue_call_count);
20287 5 : CHECK_EQ(1, prologue_call_count_second);
20288 5 : CHECK_EQ(1, epilogue_call_count_second);
20289 5 : isolate->RemoveGCPrologueCallback(PrologueCallback);
20290 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallback);
20291 5 : CcTest::CollectAllGarbage();
20292 5 : CHECK_EQ(2, prologue_call_count);
20293 5 : CHECK_EQ(2, epilogue_call_count);
20294 5 : CHECK_EQ(2, prologue_call_count_second);
20295 5 : CHECK_EQ(2, epilogue_call_count_second);
20296 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
20297 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20298 5 : CcTest::CollectAllGarbage();
20299 5 : CHECK_EQ(2, prologue_call_count);
20300 5 : CHECK_EQ(2, epilogue_call_count);
20301 5 : CHECK_EQ(2, prologue_call_count_second);
20302 5 : CHECK_EQ(2, epilogue_call_count_second);
20303 :
20304 5 : CHECK_EQ(0, prologue_call_count_alloc);
20305 5 : CHECK_EQ(0, epilogue_call_count_alloc);
20306 5 : isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
20307 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
20308 5 : CcTest::PreciseCollectAllGarbage();
20309 5 : CHECK_EQ(1, prologue_call_count_alloc);
20310 5 : CHECK_EQ(1, epilogue_call_count_alloc);
20311 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
20312 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
20313 5 : }
20314 :
20315 :
20316 28343 : THREADED_TEST(TwoByteStringInOneByteCons) {
20317 : // See Chromium issue 47824.
20318 6 : LocalContext context;
20319 12 : v8::HandleScope scope(context->GetIsolate());
20320 :
20321 : const char* init_code =
20322 : "var str1 = 'abelspendabel';"
20323 : "var str2 = str1 + str1 + str1;"
20324 : "str2;";
20325 : Local<Value> result = CompileRun(init_code);
20326 :
20327 6 : Local<Value> indexof = CompileRun("str2.indexOf('els')");
20328 6 : Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
20329 :
20330 6 : CHECK(result->IsString());
20331 : i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
20332 : int length = string->length();
20333 6 : CHECK(string->IsOneByteRepresentation());
20334 :
20335 6 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
20336 6 : i::Handle<i::String> flat_string = i::String::Flatten(i_isolate, string);
20337 :
20338 6 : CHECK(string->IsOneByteRepresentation());
20339 6 : CHECK(flat_string->IsOneByteRepresentation());
20340 :
20341 : // Create external resource.
20342 6 : uint16_t* uc16_buffer = new uint16_t[length + 1];
20343 :
20344 6 : i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
20345 6 : uc16_buffer[length] = 0;
20346 :
20347 6 : TestResource resource(uc16_buffer);
20348 :
20349 6 : flat_string->MakeExternal(&resource);
20350 :
20351 6 : CHECK(flat_string->IsTwoByteRepresentation());
20352 :
20353 : // If the cons string has been short-circuited, skip the following checks.
20354 6 : if (!string.is_identical_to(flat_string)) {
20355 : // At this point, we should have a Cons string which is flat and one-byte,
20356 : // with a first half that is a two-byte string (although it only contains
20357 : // one-byte characters). This is a valid sequence of steps, and it can
20358 : // happen in real pages.
20359 6 : CHECK(string->IsOneByteRepresentation());
20360 6 : i::ConsString cons = i::ConsString::cast(*string);
20361 12 : CHECK_EQ(0, cons->second()->length());
20362 6 : CHECK(cons->first()->IsTwoByteRepresentation());
20363 : }
20364 :
20365 : // Check that some string operations work.
20366 :
20367 : // Atom RegExp.
20368 : Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
20369 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
20370 :
20371 : // Nonatom RegExp.
20372 : reresult = CompileRun("str2.match(/abe./g).length;");
20373 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
20374 :
20375 : reresult = CompileRun("str2.search(/bel/g);");
20376 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
20377 :
20378 : reresult = CompileRun("str2.search(/be./g);");
20379 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
20380 :
20381 : ExpectTrue("/bel/g.test(str2);");
20382 :
20383 : ExpectTrue("/be./g.test(str2);");
20384 :
20385 : reresult = CompileRun("/bel/g.exec(str2);");
20386 6 : CHECK(!reresult->IsNull());
20387 :
20388 : reresult = CompileRun("/be./g.exec(str2);");
20389 6 : CHECK(!reresult->IsNull());
20390 :
20391 6 : ExpectString("str2.substring(2, 10);", "elspenda");
20392 :
20393 6 : ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
20394 :
20395 6 : ExpectString("str2.charAt(2);", "e");
20396 :
20397 6 : ExpectObject("str2.indexOf('els');", indexof);
20398 :
20399 6 : ExpectObject("str2.lastIndexOf('dab');", lastindexof);
20400 :
20401 : reresult = CompileRun("str2.charCodeAt(2);");
20402 12 : CHECK_EQ(static_cast<int32_t>('e'),
20403 : reresult->Int32Value(context.local()).FromJust());
20404 : // This avoids the GC from trying to free stack allocated resources.
20405 : i::Handle<i::ExternalTwoByteString>::cast(flat_string)
20406 18 : ->SetResource(i_isolate, nullptr);
20407 6 : }
20408 :
20409 :
20410 28342 : TEST(ContainsOnlyOneByte) {
20411 5 : v8::V8::Initialize();
20412 5 : v8::Isolate* isolate = CcTest::isolate();
20413 5 : v8::HandleScope scope(isolate);
20414 : // Make a buffer long enough that it won't automatically be converted.
20415 : const int length = 512;
20416 : // Ensure word aligned assignment.
20417 : const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
20418 5 : std::unique_ptr<uintptr_t[]> aligned_contents(new uintptr_t[aligned_length]);
20419 : uint16_t* string_contents =
20420 : reinterpret_cast<uint16_t*>(aligned_contents.get());
20421 : // Set to contain only one byte.
20422 2560 : for (int i = 0; i < length-1; i++) {
20423 2555 : string_contents[i] = 0x41;
20424 : }
20425 5 : string_contents[length-1] = 0;
20426 : // Simple case.
20427 : Local<String> string =
20428 : String::NewExternalTwoByte(
20429 5 : isolate, new TestResource(string_contents, nullptr, false))
20430 5 : .ToLocalChecked();
20431 5 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20432 : // Counter example.
20433 : string = String::NewFromTwoByte(isolate, string_contents,
20434 : v8::NewStringType::kNormal)
20435 5 : .ToLocalChecked();
20436 5 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20437 : // Test left right and balanced cons strings.
20438 5 : Local<String> base = v8_str("a");
20439 5 : Local<String> left = base;
20440 5 : Local<String> right = base;
20441 5005 : for (int i = 0; i < 1000; i++) {
20442 5000 : left = String::Concat(isolate, base, left);
20443 5000 : right = String::Concat(isolate, right, base);
20444 : }
20445 5 : Local<String> balanced = String::Concat(isolate, left, base);
20446 5 : balanced = String::Concat(isolate, balanced, right);
20447 5 : Local<String> cons_strings[] = {left, balanced, right};
20448 : Local<String> two_byte =
20449 : String::NewExternalTwoByte(
20450 5 : isolate, new TestResource(string_contents, nullptr, false))
20451 10 : .ToLocalChecked();
20452 : USE(two_byte); USE(cons_strings);
20453 20 : for (size_t i = 0; i < arraysize(cons_strings); i++) {
20454 : // Base assumptions.
20455 15 : string = cons_strings[i];
20456 15 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20457 : // Test left and right concatentation.
20458 15 : string = String::Concat(isolate, two_byte, cons_strings[i]);
20459 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20460 15 : string = String::Concat(isolate, cons_strings[i], two_byte);
20461 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20462 : }
20463 : // Set bits in different positions
20464 : // for strings of different lengths and alignments.
20465 35 : for (int alignment = 0; alignment < 7; alignment++) {
20466 280 : for (int size = 2; alignment + size < length; size *= 2) {
20467 : int zero_offset = size + alignment;
20468 280 : string_contents[zero_offset] = 0;
20469 18130 : for (int i = 0; i < size; i++) {
20470 17850 : int shift = 8 + (i % 7);
20471 17850 : string_contents[alignment + i] = 1 << shift;
20472 : string = String::NewExternalTwoByte(
20473 : isolate, new TestResource(string_contents + alignment,
20474 17850 : nullptr, false))
20475 17850 : .ToLocalChecked();
20476 17850 : CHECK_EQ(size, string->Length());
20477 17850 : CHECK(!string->ContainsOnlyOneByte());
20478 17850 : string_contents[alignment + i] = 0x41;
20479 : }
20480 280 : string_contents[zero_offset] = 0x41;
20481 : }
20482 5 : }
20483 5 : }
20484 :
20485 :
20486 : // Failed access check callback that performs a GC on each invocation.
20487 75 : void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20488 : v8::AccessType type,
20489 : Local<v8::Value> data) {
20490 75 : CcTest::CollectAllGarbage();
20491 : CcTest::isolate()->ThrowException(
20492 75 : v8::Exception::Error(v8_str("cross context")));
20493 75 : }
20494 :
20495 :
20496 28342 : TEST(GCInFailedAccessCheckCallback) {
20497 : // Install a failed access check callback that performs a GC on each
20498 : // invocation. Then force the callback to be called from va
20499 :
20500 5 : v8::V8::Initialize();
20501 5 : v8::Isolate* isolate = CcTest::isolate();
20502 :
20503 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20504 :
20505 5 : v8::HandleScope scope(isolate);
20506 :
20507 : // Create an ObjectTemplate for global objects and install access
20508 : // check callbacks that will block access.
20509 : v8::Local<v8::ObjectTemplate> global_template =
20510 5 : v8::ObjectTemplate::New(isolate);
20511 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
20512 :
20513 : // Create a context and set an x property on it's global object.
20514 10 : LocalContext context0(nullptr, global_template);
20515 25 : CHECK(context0->Global()
20516 : ->Set(context0.local(), v8_str("x"), v8_num(42))
20517 : .FromJust());
20518 5 : v8::Local<v8::Object> global0 = context0->Global();
20519 :
20520 : // Create a context with a different security token so that the
20521 : // failed access check callback will be called on each access.
20522 10 : LocalContext context1(nullptr, global_template);
20523 25 : CHECK(context1->Global()
20524 : ->Set(context1.local(), v8_str("other"), global0)
20525 : .FromJust());
20526 :
20527 10 : v8::TryCatch try_catch(isolate);
20528 :
20529 : // Get property with failed access check.
20530 5 : CHECK(CompileRun("other.x").IsEmpty());
20531 5 : CHECK(try_catch.HasCaught());
20532 5 : try_catch.Reset();
20533 :
20534 : // Get element with failed access check.
20535 5 : CHECK(CompileRun("other[0]").IsEmpty());
20536 5 : CHECK(try_catch.HasCaught());
20537 5 : try_catch.Reset();
20538 :
20539 : // Set property with failed access check.
20540 5 : CHECK(CompileRun("other.x = new Object()").IsEmpty());
20541 5 : CHECK(try_catch.HasCaught());
20542 5 : try_catch.Reset();
20543 :
20544 : // Set element with failed access check.
20545 5 : CHECK(CompileRun("other[0] = new Object()").IsEmpty());
20546 5 : CHECK(try_catch.HasCaught());
20547 5 : try_catch.Reset();
20548 :
20549 : // Get property attribute with failed access check.
20550 5 : CHECK(CompileRun("\'x\' in other").IsEmpty());
20551 5 : CHECK(try_catch.HasCaught());
20552 5 : try_catch.Reset();
20553 :
20554 : // Get property attribute for element with failed access check.
20555 5 : CHECK(CompileRun("0 in other").IsEmpty());
20556 5 : CHECK(try_catch.HasCaught());
20557 5 : try_catch.Reset();
20558 :
20559 : // Delete property.
20560 5 : CHECK(CompileRun("delete other.x").IsEmpty());
20561 5 : CHECK(try_catch.HasCaught());
20562 5 : try_catch.Reset();
20563 :
20564 : // Delete element.
20565 10 : CHECK(global0->Delete(context1.local(), 0).IsNothing());
20566 5 : CHECK(try_catch.HasCaught());
20567 5 : try_catch.Reset();
20568 :
20569 : // DefineAccessor.
20570 20 : CHECK(global0
20571 : ->SetAccessor(context1.local(), v8_str("x"), GetXValue, nullptr,
20572 : v8_str("x"))
20573 : .IsNothing());
20574 5 : CHECK(try_catch.HasCaught());
20575 5 : try_catch.Reset();
20576 :
20577 : // Define JavaScript accessor.
20578 5 : CHECK(CompileRun(
20579 : "Object.prototype.__defineGetter__.call("
20580 : " other, \'x\', function() { return 42; })").IsEmpty());
20581 5 : CHECK(try_catch.HasCaught());
20582 5 : try_catch.Reset();
20583 :
20584 : // LookupAccessor.
20585 5 : CHECK(CompileRun(
20586 : "Object.prototype.__lookupGetter__.call("
20587 : " other, \'x\')").IsEmpty());
20588 5 : CHECK(try_catch.HasCaught());
20589 5 : try_catch.Reset();
20590 :
20591 : // HasOwnElement.
20592 5 : CHECK(CompileRun(
20593 : "Object.prototype.hasOwnProperty.call("
20594 : "other, \'0\')").IsEmpty());
20595 5 : CHECK(try_catch.HasCaught());
20596 5 : try_catch.Reset();
20597 :
20598 10 : CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
20599 5 : CHECK(try_catch.HasCaught());
20600 5 : try_catch.Reset();
20601 :
20602 15 : CHECK(
20603 : global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
20604 5 : CHECK(try_catch.HasCaught());
20605 5 : try_catch.Reset();
20606 :
20607 15 : CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
20608 : .IsNothing());
20609 5 : CHECK(try_catch.HasCaught());
20610 5 : try_catch.Reset();
20611 :
20612 : // Reset the failed access check callback so it does not influence
20613 : // the other tests.
20614 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
20615 5 : }
20616 :
20617 :
20618 28342 : TEST(IsolateNewDispose) {
20619 5 : v8::Isolate* current_isolate = CcTest::isolate();
20620 : v8::Isolate::CreateParams create_params;
20621 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20622 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20623 5 : CHECK_NOT_NULL(isolate);
20624 5 : CHECK(current_isolate != isolate);
20625 5 : CHECK(current_isolate == CcTest::isolate());
20626 :
20627 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20628 5 : last_location = last_message = nullptr;
20629 5 : isolate->Dispose();
20630 5 : CHECK(!last_location);
20631 5 : CHECK(!last_message);
20632 5 : }
20633 :
20634 :
20635 28342 : UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20636 : v8::Isolate::CreateParams create_params;
20637 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20638 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20639 : {
20640 : v8::Isolate::Scope i_scope(isolate);
20641 10 : v8::HandleScope scope(isolate);
20642 5 : LocalContext context(isolate);
20643 : // Run something in this isolate.
20644 : ExpectTrue("true");
20645 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20646 5 : last_location = last_message = nullptr;
20647 : // Still entered, should fail.
20648 5 : isolate->Dispose();
20649 5 : CHECK(last_location);
20650 5 : CHECK(last_message);
20651 : }
20652 5 : isolate->Dispose();
20653 5 : }
20654 :
20655 :
20656 40 : static void BreakArrayGuarantees(const char* script) {
20657 : v8::Isolate::CreateParams create_params;
20658 40 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20659 40 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20660 40 : isolate1->Enter();
20661 : v8::Persistent<v8::Context> context1;
20662 : {
20663 40 : v8::HandleScope scope(isolate1);
20664 80 : context1.Reset(isolate1, Context::New(isolate1));
20665 : }
20666 :
20667 : {
20668 40 : v8::HandleScope scope(isolate1);
20669 : v8::Local<v8::Context> context =
20670 : v8::Local<v8::Context>::New(isolate1, context1);
20671 : v8::Context::Scope context_scope(context);
20672 : v8::internal::Isolate* i_isolate =
20673 : reinterpret_cast<v8::internal::Isolate*>(isolate1);
20674 40 : CHECK(i_isolate->IsNoElementsProtectorIntact());
20675 : // Run something in new isolate.
20676 : CompileRun(script);
20677 80 : CHECK(!i_isolate->IsNoElementsProtectorIntact());
20678 : }
20679 40 : isolate1->Exit();
20680 40 : isolate1->Dispose();
20681 40 : }
20682 :
20683 :
20684 28342 : TEST(VerifyArrayPrototypeGuarantees) {
20685 : // Break fast array hole handling by element changes.
20686 5 : BreakArrayGuarantees("[].__proto__[1] = 3;");
20687 5 : BreakArrayGuarantees("Object.prototype[3] = 'three';");
20688 5 : BreakArrayGuarantees("Array.prototype.push(1);");
20689 5 : BreakArrayGuarantees("Array.prototype.unshift(1);");
20690 : // Break fast array hole handling by changing length.
20691 5 : BreakArrayGuarantees("Array.prototype.length = 30;");
20692 : // Break fast array hole handling by prototype structure changes.
20693 5 : BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
20694 : // By sending elements to dictionary mode.
20695 : BreakArrayGuarantees(
20696 : "Object.defineProperty(Array.prototype, 0, {"
20697 5 : " get: function() { return 3; }});");
20698 : BreakArrayGuarantees(
20699 : "Object.defineProperty(Object.prototype, 0, {"
20700 5 : " get: function() { return 3; }});");
20701 5 : }
20702 :
20703 :
20704 28342 : TEST(RunTwoIsolatesOnSingleThread) {
20705 : // Run isolate 1.
20706 : v8::Isolate::CreateParams create_params;
20707 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20708 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20709 5 : isolate1->Enter();
20710 : v8::Persistent<v8::Context> context1;
20711 : {
20712 5 : v8::HandleScope scope(isolate1);
20713 10 : context1.Reset(isolate1, Context::New(isolate1));
20714 : }
20715 :
20716 : {
20717 5 : v8::HandleScope scope(isolate1);
20718 : v8::Local<v8::Context> context =
20719 : v8::Local<v8::Context>::New(isolate1, context1);
20720 : v8::Context::Scope context_scope(context);
20721 : // Run something in new isolate.
20722 : CompileRun("var foo = 'isolate 1';");
20723 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20724 : }
20725 :
20726 : // Run isolate 2.
20727 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
20728 : v8::Persistent<v8::Context> context2;
20729 :
20730 : {
20731 : v8::Isolate::Scope iscope(isolate2);
20732 10 : v8::HandleScope scope(isolate2);
20733 10 : context2.Reset(isolate2, Context::New(isolate2));
20734 : v8::Local<v8::Context> context =
20735 : v8::Local<v8::Context>::New(isolate2, context2);
20736 : v8::Context::Scope context_scope(context);
20737 :
20738 : // Run something in new isolate.
20739 : CompileRun("var foo = 'isolate 2';");
20740 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20741 : }
20742 :
20743 : {
20744 5 : v8::HandleScope scope(isolate1);
20745 : v8::Local<v8::Context> context =
20746 : v8::Local<v8::Context>::New(isolate1, context1);
20747 : v8::Context::Scope context_scope(context);
20748 : // Now again in isolate 1
20749 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20750 : }
20751 :
20752 5 : isolate1->Exit();
20753 :
20754 : // Run some stuff in default isolate.
20755 : v8::Persistent<v8::Context> context_default;
20756 : {
20757 5 : v8::Isolate* isolate = CcTest::isolate();
20758 : v8::Isolate::Scope iscope(isolate);
20759 10 : v8::HandleScope scope(isolate);
20760 10 : context_default.Reset(isolate, Context::New(isolate));
20761 : }
20762 :
20763 : {
20764 5 : v8::HandleScope scope(CcTest::isolate());
20765 : v8::Local<v8::Context> context =
20766 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20767 : v8::Context::Scope context_scope(context);
20768 : // Variables in other isolates should be not available, verify there
20769 : // is an exception.
20770 : ExpectTrue("function f() {"
20771 : " try {"
20772 : " foo;"
20773 : " return false;"
20774 : " } catch(e) {"
20775 : " return true;"
20776 : " }"
20777 : "};"
20778 : "var isDefaultIsolate = true;"
20779 5 : "f()");
20780 : }
20781 :
20782 5 : isolate1->Enter();
20783 :
20784 : {
20785 : v8::Isolate::Scope iscope(isolate2);
20786 10 : v8::HandleScope scope(isolate2);
20787 : v8::Local<v8::Context> context =
20788 : v8::Local<v8::Context>::New(isolate2, context2);
20789 : v8::Context::Scope context_scope(context);
20790 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20791 : }
20792 :
20793 : {
20794 5 : v8::HandleScope scope(v8::Isolate::GetCurrent());
20795 : v8::Local<v8::Context> context =
20796 5 : v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20797 : v8::Context::Scope context_scope(context);
20798 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20799 : }
20800 :
20801 : {
20802 : v8::Isolate::Scope iscope(isolate2);
20803 : context2.Reset();
20804 : }
20805 :
20806 : context1.Reset();
20807 5 : isolate1->Exit();
20808 :
20809 5 : isolate2->SetFatalErrorHandler(StoringErrorCallback);
20810 5 : last_location = last_message = nullptr;
20811 :
20812 5 : isolate1->Dispose();
20813 5 : CHECK(!last_location);
20814 5 : CHECK(!last_message);
20815 :
20816 5 : isolate2->Dispose();
20817 5 : CHECK(!last_location);
20818 5 : CHECK(!last_message);
20819 :
20820 : // Check that default isolate still runs.
20821 : {
20822 5 : v8::HandleScope scope(CcTest::isolate());
20823 : v8::Local<v8::Context> context =
20824 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20825 : v8::Context::Scope context_scope(context);
20826 5 : ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20827 : }
20828 5 : }
20829 :
20830 :
20831 20 : static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20832 : v8::Isolate::Scope isolate_scope(isolate);
20833 40 : v8::HandleScope scope(isolate);
20834 20 : LocalContext context(isolate);
20835 : i::ScopedVector<char> code(1024);
20836 : i::SNPrintF(code, "function fib(n) {"
20837 : " if (n <= 2) return 1;"
20838 : " return fib(n-1) + fib(n-2);"
20839 : "}"
20840 20 : "fib(%d)", limit);
20841 : Local<Value> value = CompileRun(code.start());
20842 20 : CHECK(value->IsNumber());
20843 60 : return static_cast<int>(value->NumberValue(context.local()).FromJust());
20844 : }
20845 :
20846 5 : class IsolateThread : public v8::base::Thread {
20847 : public:
20848 : explicit IsolateThread(int fib_limit)
20849 10 : : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20850 :
20851 10 : void Run() override {
20852 : v8::Isolate::CreateParams create_params;
20853 10 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20854 10 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20855 10 : result_ = CalcFibonacci(isolate, fib_limit_);
20856 10 : isolate->Dispose();
20857 10 : }
20858 :
20859 : int result() { return result_; }
20860 :
20861 : private:
20862 : int fib_limit_;
20863 : int result_;
20864 : };
20865 :
20866 :
20867 28342 : TEST(MultipleIsolatesOnIndividualThreads) {
20868 : IsolateThread thread1(21);
20869 : IsolateThread thread2(12);
20870 :
20871 : // Compute some fibonacci numbers on 3 threads in 3 isolates.
20872 5 : thread1.Start();
20873 5 : thread2.Start();
20874 :
20875 5 : int result1 = CalcFibonacci(CcTest::isolate(), 21);
20876 5 : int result2 = CalcFibonacci(CcTest::isolate(), 12);
20877 :
20878 5 : thread1.Join();
20879 5 : thread2.Join();
20880 :
20881 : // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20882 : // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20883 5 : CHECK_EQ(result1, 10946);
20884 5 : CHECK_EQ(result2, 144);
20885 5 : CHECK_EQ(result1, thread1.result());
20886 5 : CHECK_EQ(result2, thread2.result());
20887 5 : }
20888 :
20889 :
20890 28342 : TEST(IsolateDifferentContexts) {
20891 : v8::Isolate::CreateParams create_params;
20892 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20893 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20894 : Local<v8::Context> context;
20895 : {
20896 : v8::Isolate::Scope isolate_scope(isolate);
20897 10 : v8::HandleScope handle_scope(isolate);
20898 5 : context = v8::Context::New(isolate);
20899 : v8::Context::Scope context_scope(context);
20900 : Local<Value> v = CompileRun("2");
20901 5 : CHECK(v->IsNumber());
20902 10 : CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
20903 : }
20904 : {
20905 : v8::Isolate::Scope isolate_scope(isolate);
20906 10 : v8::HandleScope handle_scope(isolate);
20907 5 : context = v8::Context::New(isolate);
20908 : v8::Context::Scope context_scope(context);
20909 : Local<Value> v = CompileRun("22");
20910 5 : CHECK(v->IsNumber());
20911 10 : CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
20912 : }
20913 5 : isolate->Dispose();
20914 5 : }
20915 :
20916 20 : class InitDefaultIsolateThread : public v8::base::Thread {
20917 : public:
20918 : enum TestCase {
20919 : SetFatalHandler,
20920 : SetCounterFunction,
20921 : SetCreateHistogramFunction,
20922 : SetAddHistogramSampleFunction
20923 : };
20924 :
20925 : explicit InitDefaultIsolateThread(TestCase testCase)
20926 : : Thread(Options("InitDefaultIsolateThread")),
20927 : testCase_(testCase),
20928 20 : result_(false) {}
20929 :
20930 20 : void Run() override {
20931 : v8::Isolate::CreateParams create_params;
20932 20 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20933 20 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20934 20 : isolate->Enter();
20935 20 : switch (testCase_) {
20936 : case SetFatalHandler:
20937 5 : isolate->SetFatalErrorHandler(nullptr);
20938 5 : break;
20939 :
20940 : case SetCounterFunction:
20941 5 : CcTest::isolate()->SetCounterFunction(nullptr);
20942 5 : break;
20943 :
20944 : case SetCreateHistogramFunction:
20945 5 : CcTest::isolate()->SetCreateHistogramFunction(nullptr);
20946 5 : break;
20947 :
20948 : case SetAddHistogramSampleFunction:
20949 5 : CcTest::isolate()->SetAddHistogramSampleFunction(nullptr);
20950 5 : break;
20951 : }
20952 20 : isolate->Exit();
20953 20 : isolate->Dispose();
20954 20 : result_ = true;
20955 20 : }
20956 :
20957 : bool result() { return result_; }
20958 :
20959 : private:
20960 : TestCase testCase_;
20961 : bool result_;
20962 : };
20963 :
20964 :
20965 20 : static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20966 : InitDefaultIsolateThread thread(testCase);
20967 20 : thread.Start();
20968 20 : thread.Join();
20969 20 : CHECK(thread.result());
20970 20 : }
20971 :
20972 28342 : TEST(InitializeDefaultIsolateOnSecondaryThread_FatalHandler) {
20973 5 : InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20974 5 : }
20975 :
20976 28342 : TEST(InitializeDefaultIsolateOnSecondaryThread_CounterFunction) {
20977 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20978 5 : }
20979 :
20980 28342 : TEST(InitializeDefaultIsolateOnSecondaryThread_CreateHistogramFunction) {
20981 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20982 5 : }
20983 :
20984 28342 : TEST(InitializeDefaultIsolateOnSecondaryThread_AddHistogramSampleFunction) {
20985 5 : InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20986 5 : }
20987 :
20988 :
20989 28342 : TEST(StringCheckMultipleContexts) {
20990 : const char* code =
20991 : "(function() { return \"a\".charAt(0); })()";
20992 :
20993 : {
20994 : // Run the code twice in the first context to initialize the call IC.
20995 5 : LocalContext context1;
20996 10 : v8::HandleScope scope(context1->GetIsolate());
20997 5 : ExpectString(code, "a");
20998 10 : ExpectString(code, "a");
20999 : }
21000 :
21001 : {
21002 : // Change the String.prototype in the second context and check
21003 : // that the right function gets called.
21004 5 : LocalContext context2;
21005 10 : v8::HandleScope scope(context2->GetIsolate());
21006 : CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
21007 10 : ExpectString(code, "not a");
21008 : }
21009 5 : }
21010 :
21011 :
21012 28342 : TEST(NumberCheckMultipleContexts) {
21013 : const char* code =
21014 : "(function() { return (42).toString(); })()";
21015 :
21016 : {
21017 : // Run the code twice in the first context to initialize the call IC.
21018 5 : LocalContext context1;
21019 10 : v8::HandleScope scope(context1->GetIsolate());
21020 5 : ExpectString(code, "42");
21021 10 : ExpectString(code, "42");
21022 : }
21023 :
21024 : {
21025 : // Change the Number.prototype in the second context and check
21026 : // that the right function gets called.
21027 5 : LocalContext context2;
21028 10 : v8::HandleScope scope(context2->GetIsolate());
21029 : CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
21030 10 : ExpectString(code, "not 42");
21031 : }
21032 5 : }
21033 :
21034 :
21035 28342 : TEST(BooleanCheckMultipleContexts) {
21036 : const char* code =
21037 : "(function() { return true.toString(); })()";
21038 :
21039 : {
21040 : // Run the code twice in the first context to initialize the call IC.
21041 5 : LocalContext context1;
21042 10 : v8::HandleScope scope(context1->GetIsolate());
21043 5 : ExpectString(code, "true");
21044 10 : ExpectString(code, "true");
21045 : }
21046 :
21047 : {
21048 : // Change the Boolean.prototype in the second context and check
21049 : // that the right function gets called.
21050 5 : LocalContext context2;
21051 10 : v8::HandleScope scope(context2->GetIsolate());
21052 : CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
21053 10 : ExpectString(code, "");
21054 : }
21055 5 : }
21056 :
21057 :
21058 28342 : TEST(DontDeleteCellLoadIC) {
21059 : const char* function_code =
21060 : "function readCell() { while (true) { return cell; } }";
21061 :
21062 : {
21063 : // Run the code twice in the first context to initialize the load
21064 : // IC for a don't delete cell.
21065 5 : LocalContext context1;
21066 10 : v8::HandleScope scope(context1->GetIsolate());
21067 : CompileRun("var cell = \"first\";");
21068 5 : ExpectBoolean("delete cell", false);
21069 : CompileRun(function_code);
21070 5 : ExpectString("readCell()", "first");
21071 10 : ExpectString("readCell()", "first");
21072 : }
21073 :
21074 : {
21075 : // Use a deletable cell in the second context.
21076 5 : LocalContext context2;
21077 10 : v8::HandleScope scope(context2->GetIsolate());
21078 : CompileRun("cell = \"second\";");
21079 : CompileRun(function_code);
21080 5 : ExpectString("readCell()", "second");
21081 5 : ExpectBoolean("delete cell", true);
21082 : ExpectString("(function() {"
21083 : " try {"
21084 : " return readCell();"
21085 : " } catch(e) {"
21086 : " return e.toString();"
21087 : " }"
21088 : "})()",
21089 5 : "ReferenceError: cell is not defined");
21090 : CompileRun("cell = \"new_second\";");
21091 5 : CcTest::CollectAllGarbage();
21092 5 : ExpectString("readCell()", "new_second");
21093 10 : ExpectString("readCell()", "new_second");
21094 : }
21095 5 : }
21096 :
21097 :
21098 10 : class Visitor42 : public v8::PersistentHandleVisitor {
21099 : public:
21100 : explicit Visitor42(v8::Persistent<v8::Object>* object)
21101 10 : : counter_(0), object_(object) { }
21102 :
21103 10 : void VisitPersistentHandle(Persistent<Value>* value,
21104 : uint16_t class_id) override {
21105 10 : if (class_id != 42) return;
21106 10 : CHECK_EQ(42, value->WrapperClassId());
21107 10 : v8::Isolate* isolate = CcTest::isolate();
21108 10 : v8::HandleScope handle_scope(isolate);
21109 : v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
21110 10 : v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
21111 10 : CHECK(handle->IsObject());
21112 20 : CHECK(Local<Object>::Cast(handle)
21113 : ->Equals(isolate->GetCurrentContext(), object)
21114 : .FromJust());
21115 10 : ++counter_;
21116 : }
21117 :
21118 : int counter_;
21119 : v8::Persistent<v8::Object>* object_;
21120 : };
21121 :
21122 :
21123 28342 : TEST(PersistentHandleVisitor) {
21124 5 : LocalContext context;
21125 5 : v8::Isolate* isolate = context->GetIsolate();
21126 10 : v8::HandleScope scope(isolate);
21127 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
21128 5 : CHECK_EQ(0, object.WrapperClassId());
21129 : object.SetWrapperClassId(42);
21130 5 : CHECK_EQ(42, object.WrapperClassId());
21131 :
21132 : Visitor42 visitor(&object);
21133 5 : isolate->VisitHandlesWithClassIds(&visitor);
21134 5 : CHECK_EQ(1, visitor.counter_);
21135 :
21136 5 : object.Reset();
21137 5 : }
21138 :
21139 :
21140 28342 : TEST(WrapperClassId) {
21141 5 : LocalContext context;
21142 5 : v8::Isolate* isolate = context->GetIsolate();
21143 10 : v8::HandleScope scope(isolate);
21144 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
21145 5 : CHECK_EQ(0, object.WrapperClassId());
21146 : object.SetWrapperClassId(65535);
21147 5 : CHECK_EQ(65535, object.WrapperClassId());
21148 5 : object.Reset();
21149 5 : }
21150 :
21151 :
21152 28342 : TEST(PersistentHandleInNewSpaceVisitor) {
21153 5 : LocalContext context;
21154 5 : v8::Isolate* isolate = context->GetIsolate();
21155 10 : v8::HandleScope scope(isolate);
21156 5 : v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
21157 5 : CHECK_EQ(0, object1.WrapperClassId());
21158 : object1.SetWrapperClassId(42);
21159 5 : CHECK_EQ(42, object1.WrapperClassId());
21160 :
21161 5 : CcTest::CollectAllGarbage();
21162 5 : CcTest::CollectAllGarbage();
21163 :
21164 5 : v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
21165 5 : CHECK_EQ(0, object2.WrapperClassId());
21166 : object2.SetWrapperClassId(42);
21167 5 : CHECK_EQ(42, object2.WrapperClassId());
21168 :
21169 : Visitor42 visitor(&object2);
21170 5 : isolate->VisitHandlesForPartialDependence(&visitor);
21171 5 : CHECK_EQ(1, visitor.counter_);
21172 :
21173 : object1.Reset();
21174 5 : object2.Reset();
21175 5 : }
21176 :
21177 :
21178 28342 : TEST(RegExp) {
21179 5 : LocalContext context;
21180 10 : v8::HandleScope scope(context->GetIsolate());
21181 :
21182 : v8::Local<v8::RegExp> re =
21183 5 : v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
21184 5 : .ToLocalChecked();
21185 5 : CHECK(re->IsRegExp());
21186 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
21187 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21188 :
21189 : re = v8::RegExp::New(context.local(), v8_str("bar"),
21190 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21191 5 : v8::RegExp::kGlobal))
21192 5 : .ToLocalChecked();
21193 5 : CHECK(re->IsRegExp());
21194 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
21195 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
21196 : static_cast<int>(re->GetFlags()));
21197 :
21198 : re = v8::RegExp::New(context.local(), v8_str("baz"),
21199 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21200 5 : v8::RegExp::kMultiline))
21201 5 : .ToLocalChecked();
21202 5 : CHECK(re->IsRegExp());
21203 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
21204 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21205 : static_cast<int>(re->GetFlags()));
21206 :
21207 : re = v8::RegExp::New(context.local(), v8_str("baz"),
21208 : static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
21209 5 : v8::RegExp::kSticky))
21210 5 : .ToLocalChecked();
21211 5 : CHECK(re->IsRegExp());
21212 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
21213 5 : CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
21214 : static_cast<int>(re->GetFlags()));
21215 :
21216 : re = CompileRun("/quux/").As<v8::RegExp>();
21217 5 : CHECK(re->IsRegExp());
21218 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
21219 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21220 :
21221 : re = CompileRun("/quux/gm").As<v8::RegExp>();
21222 5 : CHECK(re->IsRegExp());
21223 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
21224 5 : CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
21225 : static_cast<int>(re->GetFlags()));
21226 :
21227 : // Override the RegExp constructor and check the API constructor
21228 : // still works.
21229 : CompileRun("RegExp = function() {}");
21230 :
21231 5 : re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
21232 5 : .ToLocalChecked();
21233 5 : CHECK(re->IsRegExp());
21234 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
21235 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21236 :
21237 : re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
21238 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21239 5 : v8::RegExp::kMultiline))
21240 5 : .ToLocalChecked();
21241 5 : CHECK(re->IsRegExp());
21242 20 : CHECK(
21243 : re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
21244 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21245 : static_cast<int>(re->GetFlags()));
21246 :
21247 25 : CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
21248 : ExpectTrue("re.test('FoobarbaZ')");
21249 :
21250 : // RegExps are objects on which you can set properties.
21251 : re->Set(context.local(), v8_str("property"),
21252 20 : v8::Integer::New(context->GetIsolate(), 32))
21253 10 : .FromJust();
21254 : v8::Local<v8::Value> value(CompileRun("re.property"));
21255 10 : CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
21256 :
21257 10 : v8::TryCatch try_catch(context->GetIsolate());
21258 10 : CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
21259 : .IsEmpty());
21260 5 : CHECK(try_catch.HasCaught());
21261 25 : CHECK(context->Global()
21262 : ->Set(context.local(), v8_str("ex"), try_catch.Exception())
21263 : .FromJust());
21264 5 : ExpectTrue("ex instanceof SyntaxError");
21265 5 : }
21266 :
21267 :
21268 28343 : THREADED_TEST(Equals) {
21269 6 : LocalContext localContext;
21270 12 : v8::HandleScope handleScope(localContext->GetIsolate());
21271 :
21272 6 : v8::Local<v8::Object> globalProxy = localContext->Global();
21273 6 : v8::Local<Value> global = globalProxy->GetPrototype();
21274 :
21275 6 : CHECK(global->StrictEquals(global));
21276 6 : CHECK(!global->StrictEquals(globalProxy));
21277 6 : CHECK(!globalProxy->StrictEquals(global));
21278 6 : CHECK(globalProxy->StrictEquals(globalProxy));
21279 :
21280 12 : CHECK(global->Equals(localContext.local(), global).FromJust());
21281 12 : CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
21282 12 : CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
21283 18 : CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
21284 6 : }
21285 :
21286 :
21287 5 : static void Getter(v8::Local<v8::Name> property,
21288 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21289 5 : info.GetReturnValue().Set(v8_str("42!"));
21290 5 : }
21291 :
21292 :
21293 5 : static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
21294 5 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
21295 : result->Set(info.GetIsolate()->GetCurrentContext(), 0,
21296 15 : v8_str("universalAnswer"))
21297 10 : .FromJust();
21298 : info.GetReturnValue().Set(result);
21299 5 : }
21300 :
21301 :
21302 28342 : TEST(NamedEnumeratorAndForIn) {
21303 5 : LocalContext context;
21304 5 : v8::Isolate* isolate = context->GetIsolate();
21305 10 : v8::HandleScope handle_scope(isolate);
21306 5 : v8::Context::Scope context_scope(context.local());
21307 :
21308 5 : v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
21309 : tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
21310 5 : Getter, nullptr, nullptr, nullptr, Enumerator));
21311 30 : CHECK(context->Global()
21312 : ->Set(context.local(), v8_str("o"),
21313 : tmpl->NewInstance(context.local()).ToLocalChecked())
21314 : .FromJust());
21315 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
21316 : CompileRun("var result = []; for (var k in o) result.push(k); result"));
21317 5 : CHECK_EQ(1u, result->Length());
21318 20 : CHECK(v8_str("universalAnswer")
21319 : ->Equals(context.local(),
21320 : result->Get(context.local(), 0).ToLocalChecked())
21321 5 : .FromJust());
21322 5 : }
21323 :
21324 :
21325 28342 : TEST(DefinePropertyPostDetach) {
21326 5 : LocalContext context;
21327 10 : v8::HandleScope scope(context->GetIsolate());
21328 5 : v8::Local<v8::Object> proxy = context->Global();
21329 : v8::Local<v8::Function> define_property =
21330 : CompileRun(
21331 : "(function() {"
21332 : " Object.defineProperty("
21333 : " this,"
21334 : " 1,"
21335 : " { configurable: true, enumerable: true, value: 3 });"
21336 : "})")
21337 : .As<Function>();
21338 5 : context->DetachGlobal();
21339 15 : CHECK(define_property->Call(context.local(), proxy, 0, nullptr).IsEmpty());
21340 5 : }
21341 :
21342 :
21343 36 : static void InstallContextId(v8::Local<Context> context, int id) {
21344 : Context::Scope scope(context);
21345 144 : CHECK(CompileRun("Object.prototype")
21346 : .As<Object>()
21347 : ->Set(context, v8_str("context_id"),
21348 : v8::Integer::New(context->GetIsolate(), id))
21349 : .FromJust());
21350 36 : }
21351 :
21352 :
21353 126 : static void CheckContextId(v8::Local<Object> object, int expected) {
21354 126 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
21355 504 : CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
21356 : .ToLocalChecked()
21357 : ->Int32Value(context)
21358 : .FromJust());
21359 126 : }
21360 :
21361 :
21362 28343 : THREADED_TEST(CreationContext) {
21363 6 : v8::Isolate* isolate = CcTest::isolate();
21364 6 : HandleScope handle_scope(isolate);
21365 6 : Local<Context> context1 = Context::New(isolate);
21366 6 : InstallContextId(context1, 1);
21367 6 : Local<Context> context2 = Context::New(isolate);
21368 6 : InstallContextId(context2, 2);
21369 6 : Local<Context> context3 = Context::New(isolate);
21370 6 : InstallContextId(context3, 3);
21371 :
21372 6 : Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
21373 :
21374 : Local<Object> object1;
21375 : Local<Function> func1;
21376 : {
21377 : Context::Scope scope(context1);
21378 6 : object1 = Object::New(isolate);
21379 6 : func1 = tmpl->GetFunction(context1).ToLocalChecked();
21380 : }
21381 :
21382 : Local<Object> object2;
21383 : Local<Function> func2;
21384 : {
21385 : Context::Scope scope(context2);
21386 6 : object2 = Object::New(isolate);
21387 6 : func2 = tmpl->GetFunction(context2).ToLocalChecked();
21388 : }
21389 :
21390 : Local<Object> instance1;
21391 : Local<Object> instance2;
21392 :
21393 : {
21394 : Context::Scope scope(context3);
21395 : instance1 = func1->NewInstance(context3).ToLocalChecked();
21396 : instance2 = func2->NewInstance(context3).ToLocalChecked();
21397 : }
21398 :
21399 : {
21400 6 : Local<Context> other_context = Context::New(isolate);
21401 : Context::Scope scope(other_context);
21402 12 : CHECK(object1->CreationContext() == context1);
21403 6 : CheckContextId(object1, 1);
21404 12 : CHECK(func1->CreationContext() == context1);
21405 6 : CheckContextId(func1, 1);
21406 12 : CHECK(instance1->CreationContext() == context1);
21407 6 : CheckContextId(instance1, 1);
21408 12 : CHECK(object2->CreationContext() == context2);
21409 6 : CheckContextId(object2, 2);
21410 12 : CHECK(func2->CreationContext() == context2);
21411 6 : CheckContextId(func2, 2);
21412 12 : CHECK(instance2->CreationContext() == context2);
21413 6 : CheckContextId(instance2, 2);
21414 : }
21415 :
21416 : {
21417 : Context::Scope scope(context1);
21418 12 : CHECK(object1->CreationContext() == context1);
21419 6 : CheckContextId(object1, 1);
21420 12 : CHECK(func1->CreationContext() == context1);
21421 6 : CheckContextId(func1, 1);
21422 12 : CHECK(instance1->CreationContext() == context1);
21423 6 : CheckContextId(instance1, 1);
21424 12 : CHECK(object2->CreationContext() == context2);
21425 6 : CheckContextId(object2, 2);
21426 12 : CHECK(func2->CreationContext() == context2);
21427 6 : CheckContextId(func2, 2);
21428 12 : CHECK(instance2->CreationContext() == context2);
21429 6 : CheckContextId(instance2, 2);
21430 : }
21431 :
21432 : {
21433 : Context::Scope scope(context2);
21434 12 : CHECK(object1->CreationContext() == context1);
21435 6 : CheckContextId(object1, 1);
21436 12 : CHECK(func1->CreationContext() == context1);
21437 6 : CheckContextId(func1, 1);
21438 12 : CHECK(instance1->CreationContext() == context1);
21439 6 : CheckContextId(instance1, 1);
21440 12 : CHECK(object2->CreationContext() == context2);
21441 6 : CheckContextId(object2, 2);
21442 12 : CHECK(func2->CreationContext() == context2);
21443 6 : CheckContextId(func2, 2);
21444 12 : CHECK(instance2->CreationContext() == context2);
21445 6 : CheckContextId(instance2, 2);
21446 6 : }
21447 6 : }
21448 :
21449 :
21450 28343 : THREADED_TEST(CreationContextOfJsFunction) {
21451 6 : HandleScope handle_scope(CcTest::isolate());
21452 6 : Local<Context> context = Context::New(CcTest::isolate());
21453 6 : InstallContextId(context, 1);
21454 :
21455 : Local<Object> function;
21456 : {
21457 : Context::Scope scope(context);
21458 : function = CompileRun("function foo() {}; foo").As<Object>();
21459 : }
21460 :
21461 6 : Local<Context> other_context = Context::New(CcTest::isolate());
21462 : Context::Scope scope(other_context);
21463 12 : CHECK(function->CreationContext() == context);
21464 12 : CheckContextId(function, 1);
21465 6 : }
21466 :
21467 :
21468 28343 : THREADED_TEST(CreationContextOfJsBoundFunction) {
21469 6 : HandleScope handle_scope(CcTest::isolate());
21470 6 : Local<Context> context1 = Context::New(CcTest::isolate());
21471 6 : InstallContextId(context1, 1);
21472 6 : Local<Context> context2 = Context::New(CcTest::isolate());
21473 6 : InstallContextId(context2, 2);
21474 :
21475 : Local<Function> target_function;
21476 : {
21477 : Context::Scope scope(context1);
21478 : target_function = CompileRun("function foo() {}; foo").As<Function>();
21479 : }
21480 :
21481 : Local<Function> bound_function1, bound_function2;
21482 : {
21483 : Context::Scope scope(context2);
21484 24 : CHECK(context2->Global()
21485 : ->Set(context2, v8_str("foo"), target_function)
21486 : .FromJust());
21487 : bound_function1 = CompileRun("foo.bind(1)").As<Function>();
21488 : bound_function2 =
21489 : CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
21490 : }
21491 :
21492 6 : Local<Context> other_context = Context::New(CcTest::isolate());
21493 : Context::Scope scope(other_context);
21494 12 : CHECK(bound_function1->CreationContext() == context1);
21495 6 : CheckContextId(bound_function1, 1);
21496 12 : CHECK(bound_function2->CreationContext() == context1);
21497 12 : CheckContextId(bound_function2, 1);
21498 6 : }
21499 :
21500 :
21501 20 : void HasOwnPropertyIndexedPropertyGetter(
21502 : uint32_t index,
21503 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21504 20 : if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
21505 20 : }
21506 :
21507 :
21508 10 : void HasOwnPropertyNamedPropertyGetter(
21509 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21510 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21511 20 : .FromJust()) {
21512 5 : info.GetReturnValue().Set(v8_str("yes"));
21513 : }
21514 10 : }
21515 :
21516 :
21517 50 : void HasOwnPropertyIndexedPropertyQuery(
21518 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21519 50 : if (index == 42) info.GetReturnValue().Set(1);
21520 50 : }
21521 :
21522 :
21523 10 : void HasOwnPropertyNamedPropertyQuery(
21524 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21525 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21526 20 : .FromJust()) {
21527 : info.GetReturnValue().Set(1);
21528 : }
21529 10 : }
21530 :
21531 :
21532 10 : void HasOwnPropertyNamedPropertyQuery2(
21533 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21534 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
21535 20 : .FromJust()) {
21536 : info.GetReturnValue().Set(1);
21537 : }
21538 10 : }
21539 :
21540 0 : void HasOwnPropertyAccessorGetter(
21541 : Local<String> property,
21542 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21543 0 : info.GetReturnValue().Set(v8_str("yes"));
21544 0 : }
21545 :
21546 5 : void HasOwnPropertyAccessorNameGetter(
21547 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21548 5 : info.GetReturnValue().Set(v8_str("yes"));
21549 5 : }
21550 :
21551 28342 : TEST(HasOwnProperty) {
21552 5 : LocalContext env;
21553 5 : v8::Isolate* isolate = env->GetIsolate();
21554 10 : v8::HandleScope scope(isolate);
21555 : { // Check normal properties and defined getters.
21556 : Local<Value> value = CompileRun(
21557 : "function Foo() {"
21558 : " this.foo = 11;"
21559 : " this.__defineGetter__('baz', function() { return 1; });"
21560 : "};"
21561 : "function Bar() { "
21562 : " this.bar = 13;"
21563 : " this.__defineGetter__('bla', function() { return 2; });"
21564 : "};"
21565 : "Bar.prototype = new Foo();"
21566 : "new Bar();");
21567 5 : CHECK(value->IsObject());
21568 5 : Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
21569 15 : CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
21570 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21571 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21572 15 : CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
21573 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
21574 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
21575 : }
21576 : { // Check named getter interceptors.
21577 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21578 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21579 5 : HasOwnPropertyNamedPropertyGetter));
21580 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21581 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21582 10 : CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
21583 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21584 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21585 : }
21586 : { // Check indexed getter interceptors.
21587 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21588 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21589 5 : HasOwnPropertyIndexedPropertyGetter));
21590 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21591 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21592 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
21593 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
21594 10 : CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
21595 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21596 : }
21597 : { // Check named query interceptors.
21598 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21599 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21600 5 : nullptr, nullptr, HasOwnPropertyNamedPropertyQuery));
21601 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21602 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21603 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21604 : }
21605 : { // Check indexed query interceptors.
21606 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21607 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21608 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
21609 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21610 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21611 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
21612 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
21613 10 : CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
21614 : }
21615 : { // Check callbacks.
21616 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21617 5 : templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21618 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21619 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21620 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21621 : }
21622 : { // Check that query wins on disagreement.
21623 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21624 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21625 : HasOwnPropertyNamedPropertyGetter, nullptr,
21626 5 : HasOwnPropertyNamedPropertyQuery2));
21627 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21628 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21629 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21630 : }
21631 : { // Check that non-internalized keys are handled correctly.
21632 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21633 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21634 5 : HasOwnPropertyAccessorNameGetter));
21635 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21636 25 : env->Global()->Set(env.local(), v8_str("obj"), instance).FromJust();
21637 : const char* src =
21638 : "var dyn_string = 'this string ';"
21639 : "dyn_string += 'does not exist elsewhere';"
21640 : "({}).hasOwnProperty.call(obj, dyn_string)";
21641 5 : CHECK(CompileRun(src)->BooleanValue(isolate));
21642 5 : }
21643 5 : }
21644 :
21645 :
21646 28342 : TEST(IndexedInterceptorWithStringProto) {
21647 5 : v8::Isolate* isolate = CcTest::isolate();
21648 5 : v8::HandleScope scope(isolate);
21649 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21650 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21651 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
21652 10 : LocalContext context;
21653 30 : CHECK(context->Global()
21654 : ->Set(context.local(), v8_str("obj"),
21655 : templ->NewInstance(context.local()).ToLocalChecked())
21656 : .FromJust());
21657 : CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21658 : // These should be intercepted.
21659 5 : CHECK(CompileRun("42 in obj")->BooleanValue(isolate));
21660 5 : CHECK(CompileRun("'42' in obj")->BooleanValue(isolate));
21661 : // These should fall through to the String prototype.
21662 5 : CHECK(CompileRun("0 in obj")->BooleanValue(isolate));
21663 5 : CHECK(CompileRun("'0' in obj")->BooleanValue(isolate));
21664 : // And these should both fail.
21665 5 : CHECK(!CompileRun("32 in obj")->BooleanValue(isolate));
21666 10 : CHECK(!CompileRun("'32' in obj")->BooleanValue(isolate));
21667 5 : }
21668 :
21669 :
21670 18 : void CheckCodeGenerationAllowed() {
21671 18 : Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
21672 : Local<Value> result = CompileRun("eval('42')");
21673 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21674 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21675 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21676 : result = CompileRun("var f = new Function('return 42'); f()");
21677 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21678 18 : }
21679 :
21680 :
21681 12 : void CheckCodeGenerationDisallowed() {
21682 12 : TryCatch try_catch(CcTest::isolate());
21683 :
21684 : Local<Value> result = CompileRun("eval('42')");
21685 12 : CHECK(result.IsEmpty());
21686 12 : CHECK(try_catch.HasCaught());
21687 12 : try_catch.Reset();
21688 :
21689 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21690 12 : CHECK(result.IsEmpty());
21691 12 : CHECK(try_catch.HasCaught());
21692 12 : try_catch.Reset();
21693 :
21694 : result = CompileRun("var f = new Function('return 42'); f()");
21695 12 : CHECK(result.IsEmpty());
21696 12 : CHECK(try_catch.HasCaught());
21697 12 : }
21698 :
21699 : char first_fourty_bytes[41];
21700 :
21701 23 : bool CodeGenerationAllowed(Local<Context> context, Local<String> source) {
21702 23 : String::Utf8Value str(CcTest::isolate(), source);
21703 : size_t len = std::min(sizeof(first_fourty_bytes) - 1,
21704 46 : static_cast<size_t>(str.length()));
21705 23 : strncpy(first_fourty_bytes, *str, len);
21706 23 : first_fourty_bytes[len] = 0;
21707 23 : ApiTestFuzzer::Fuzz();
21708 23 : return true;
21709 : }
21710 :
21711 23 : bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) {
21712 23 : ApiTestFuzzer::Fuzz();
21713 23 : return false;
21714 : }
21715 :
21716 :
21717 28343 : THREADED_TEST(AllowCodeGenFromStrings) {
21718 6 : LocalContext context;
21719 12 : v8::HandleScope scope(context->GetIsolate());
21720 :
21721 : // eval and the Function constructor allowed by default.
21722 6 : CHECK(context->IsCodeGenerationFromStringsAllowed());
21723 6 : CheckCodeGenerationAllowed();
21724 :
21725 : // Disallow eval and the Function constructor.
21726 6 : context->AllowCodeGenerationFromStrings(false);
21727 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21728 6 : CheckCodeGenerationDisallowed();
21729 :
21730 : // Allow again.
21731 6 : context->AllowCodeGenerationFromStrings(true);
21732 6 : CheckCodeGenerationAllowed();
21733 :
21734 : // Disallow but setting a global callback that will allow the calls.
21735 6 : context->AllowCodeGenerationFromStrings(false);
21736 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21737 6 : &CodeGenerationAllowed);
21738 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21739 6 : CheckCodeGenerationAllowed();
21740 :
21741 : // Set a callback that disallows the code generation.
21742 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21743 6 : &CodeGenerationDisallowed);
21744 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21745 12 : CheckCodeGenerationDisallowed();
21746 6 : }
21747 :
21748 :
21749 28342 : TEST(SetErrorMessageForCodeGenFromStrings) {
21750 5 : LocalContext context;
21751 10 : v8::HandleScope scope(context->GetIsolate());
21752 10 : TryCatch try_catch(context->GetIsolate());
21753 :
21754 5 : Local<String> message = v8_str("Message");
21755 5 : Local<String> expected_message = v8_str("Uncaught EvalError: Message");
21756 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21757 5 : &CodeGenerationDisallowed);
21758 5 : context->AllowCodeGenerationFromStrings(false);
21759 5 : context->SetErrorMessageForCodeGenerationFromStrings(message);
21760 : Local<Value> result = CompileRun("eval('42')");
21761 5 : CHECK(result.IsEmpty());
21762 5 : CHECK(try_catch.HasCaught());
21763 10 : Local<String> actual_message = try_catch.Message()->Get();
21764 20 : CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
21765 5 : }
21766 :
21767 28342 : TEST(CaptureSourceForCodeGenFromStrings) {
21768 5 : LocalContext context;
21769 10 : v8::HandleScope scope(context->GetIsolate());
21770 10 : TryCatch try_catch(context->GetIsolate());
21771 :
21772 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21773 5 : &CodeGenerationAllowed);
21774 5 : context->AllowCodeGenerationFromStrings(false);
21775 : CompileRun("eval('42')");
21776 10 : CHECK(!strcmp(first_fourty_bytes, "42"));
21777 5 : }
21778 :
21779 6 : static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21780 6 : }
21781 :
21782 :
21783 28343 : THREADED_TEST(CallAPIFunctionOnNonObject) {
21784 6 : LocalContext context;
21785 6 : v8::Isolate* isolate = context->GetIsolate();
21786 12 : v8::HandleScope scope(isolate);
21787 : Local<FunctionTemplate> templ =
21788 6 : v8::FunctionTemplate::New(isolate, NonObjectThis);
21789 : Local<Function> function =
21790 12 : templ->GetFunction(context.local()).ToLocalChecked();
21791 30 : CHECK(context->Global()
21792 : ->Set(context.local(), v8_str("f"), function)
21793 : .FromJust());
21794 12 : TryCatch try_catch(isolate);
21795 6 : CompileRun("f.call(2)");
21796 6 : }
21797 :
21798 :
21799 : // Regression test for issue 1470.
21800 28343 : THREADED_TEST(ReadOnlyIndexedProperties) {
21801 6 : v8::Isolate* isolate = CcTest::isolate();
21802 6 : v8::HandleScope scope(isolate);
21803 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21804 :
21805 12 : LocalContext context;
21806 12 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
21807 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
21808 : obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
21809 24 : v8::ReadOnly)
21810 12 : .FromJust();
21811 24 : obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
21812 30 : CHECK(v8_str("DONT_CHANGE")
21813 : ->Equals(context.local(),
21814 : obj->Get(context.local(), v8_str("1")).ToLocalChecked())
21815 : .FromJust());
21816 : obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
21817 24 : v8::ReadOnly)
21818 12 : .FromJust();
21819 18 : obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
21820 24 : CHECK(v8_str("DONT_CHANGE")
21821 : ->Equals(context.local(),
21822 : obj->Get(context.local(), v8_num(2)).ToLocalChecked())
21823 : .FromJust());
21824 :
21825 : // Test non-smi case.
21826 : obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
21827 24 : v8_str("DONT_CHANGE"), v8::ReadOnly)
21828 12 : .FromJust();
21829 24 : obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
21830 30 : CHECK(v8_str("DONT_CHANGE")
21831 : ->Equals(context.local(),
21832 : obj->Get(context.local(), v8_str("2000000000"))
21833 : .ToLocalChecked())
21834 6 : .FromJust());
21835 6 : }
21836 :
21837 12 : static int CountLiveMapsInMapCache(i::Context context) {
21838 24 : i::WeakFixedArray map_cache = i::WeakFixedArray::cast(context->map_cache());
21839 : int length = map_cache->length();
21840 : int count = 0;
21841 1548 : for (int i = 0; i < length; i++) {
21842 3072 : if (map_cache->Get(i)->IsWeak()) count++;
21843 : }
21844 12 : return count;
21845 : }
21846 :
21847 :
21848 28343 : THREADED_TEST(Regress1516) {
21849 6 : LocalContext context;
21850 12 : v8::HandleScope scope(context->GetIsolate());
21851 :
21852 : // Object with 20 properties is not a common case, so it should be removed
21853 : // from the cache after GC.
21854 6 : { v8::HandleScope temp_scope(context->GetIsolate());
21855 : CompileRun(
21856 : "({"
21857 : "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21858 : "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21859 : "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21860 : "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21861 6 : "})");
21862 : }
21863 :
21864 6 : int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21865 6 : CHECK_LE(1, elements);
21866 :
21867 : // We have to abort incremental marking here to abandon black pages.
21868 6 : CcTest::PreciseCollectAllGarbage();
21869 :
21870 12 : CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21871 6 : }
21872 :
21873 :
21874 28343 : THREADED_TEST(Regress93759) {
21875 6 : v8::Isolate* isolate = CcTest::isolate();
21876 6 : HandleScope scope(isolate);
21877 :
21878 : // Template for object with security check.
21879 6 : Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21880 6 : no_proto_template->SetAccessCheckCallback(AccessAlwaysBlocked);
21881 :
21882 : // Templates for objects with hidden prototypes and possibly security check.
21883 : Local<FunctionTemplate> hidden_proto_template =
21884 6 : v8::FunctionTemplate::New(isolate);
21885 6 : hidden_proto_template->SetHiddenPrototype(true);
21886 :
21887 : Local<FunctionTemplate> protected_hidden_proto_template =
21888 6 : v8::FunctionTemplate::New(isolate);
21889 : protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallback(
21890 12 : AccessAlwaysBlocked);
21891 6 : protected_hidden_proto_template->SetHiddenPrototype(true);
21892 :
21893 : // Context for "foreign" objects used in test.
21894 6 : Local<Context> context = v8::Context::New(isolate);
21895 6 : context->Enter();
21896 :
21897 : // Plain object, no security check.
21898 6 : Local<Object> simple_object = Object::New(isolate);
21899 :
21900 : // Object with explicit security check.
21901 : Local<Object> protected_object =
21902 6 : no_proto_template->NewInstance(context).ToLocalChecked();
21903 :
21904 : // JSGlobalProxy object, always have security check.
21905 6 : Local<Object> proxy_object = context->Global();
21906 :
21907 : // Global object, the prototype of proxy_object. No security checks.
21908 : Local<Object> global_object =
21909 18 : proxy_object->GetPrototype()->ToObject(context).ToLocalChecked();
21910 :
21911 : // Hidden prototype without security check.
21912 : Local<Object> hidden_prototype = hidden_proto_template->GetFunction(context)
21913 6 : .ToLocalChecked()
21914 : ->NewInstance(context)
21915 : .ToLocalChecked();
21916 : Local<Object> object_with_hidden =
21917 6 : Object::New(isolate);
21918 12 : object_with_hidden->SetPrototype(context, hidden_prototype).FromJust();
21919 :
21920 6 : context->Exit();
21921 :
21922 12 : LocalContext context2;
21923 6 : v8::Local<v8::Object> global = context2->Global();
21924 :
21925 : // Setup global variables.
21926 18 : CHECK(global->Set(context2.local(), v8_str("simple"), simple_object)
21927 : .FromJust());
21928 18 : CHECK(global->Set(context2.local(), v8_str("protected"), protected_object)
21929 : .FromJust());
21930 18 : CHECK(global->Set(context2.local(), v8_str("global"), global_object)
21931 : .FromJust());
21932 18 : CHECK(
21933 : global->Set(context2.local(), v8_str("proxy"), proxy_object).FromJust());
21934 18 : CHECK(global->Set(context2.local(), v8_str("hidden"), object_with_hidden)
21935 : .FromJust());
21936 :
21937 : Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21938 12 : CHECK(result1->Equals(context2.local(), simple_object->GetPrototype())
21939 : .FromJust());
21940 :
21941 : Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21942 6 : CHECK(result2->IsNull());
21943 :
21944 : Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21945 12 : CHECK(result3->Equals(context2.local(), global_object->GetPrototype())
21946 : .FromJust());
21947 :
21948 : Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21949 6 : CHECK(result4->IsNull());
21950 :
21951 : Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21952 24 : CHECK(result5->Equals(context2.local(), object_with_hidden->GetPrototype()
21953 : ->ToObject(context2.local())
21954 : .ToLocalChecked()
21955 : ->GetPrototype())
21956 6 : .FromJust());
21957 6 : }
21958 :
21959 :
21960 84 : static void TestReceiver(Local<Value> expected_result,
21961 : Local<Value> expected_receiver,
21962 : const char* code) {
21963 : Local<Value> result = CompileRun(code);
21964 84 : Local<Context> context = CcTest::isolate()->GetCurrentContext();
21965 84 : CHECK(result->IsObject());
21966 252 : CHECK(expected_receiver
21967 : ->Equals(context,
21968 : result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
21969 : .FromJust());
21970 252 : CHECK(expected_result
21971 : ->Equals(context,
21972 : result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
21973 : .FromJust());
21974 84 : }
21975 :
21976 :
21977 28343 : THREADED_TEST(ForeignFunctionReceiver) {
21978 6 : v8::Isolate* isolate = CcTest::isolate();
21979 6 : HandleScope scope(isolate);
21980 :
21981 : // Create two contexts with different "id" properties ('i' and 'o').
21982 : // Call a function both from its own context and from a the foreign
21983 : // context, and see what "this" is bound to (returning both "this"
21984 : // and "this.id" for comparison).
21985 :
21986 6 : Local<Context> foreign_context = v8::Context::New(isolate);
21987 6 : foreign_context->Enter();
21988 : Local<Value> foreign_function =
21989 : CompileRun("function func() { return { 0: this.id, "
21990 : " 1: this, "
21991 : " toString: function() { "
21992 : " return this[0];"
21993 : " }"
21994 : " };"
21995 : "}"
21996 : "var id = 'i';"
21997 : "func;");
21998 6 : CHECK(foreign_function->IsFunction());
21999 6 : foreign_context->Exit();
22000 :
22001 12 : LocalContext context;
22002 :
22003 6 : Local<String> password = v8_str("Password");
22004 : // Don't get hit by security checks when accessing foreign_context's
22005 : // global receiver (aka. global proxy).
22006 6 : context->SetSecurityToken(password);
22007 6 : foreign_context->SetSecurityToken(password);
22008 :
22009 6 : Local<String> i = v8_str("i");
22010 6 : Local<String> o = v8_str("o");
22011 6 : Local<String> id = v8_str("id");
22012 :
22013 : CompileRun("function ownfunc() { return { 0: this.id, "
22014 : " 1: this, "
22015 : " toString: function() { "
22016 : " return this[0];"
22017 : " }"
22018 : " };"
22019 : "}"
22020 : "var id = 'o';"
22021 : "ownfunc");
22022 30 : CHECK(context->Global()
22023 : ->Set(context.local(), v8_str("func"), foreign_function)
22024 : .FromJust());
22025 :
22026 : // Sanity check the contexts.
22027 24 : CHECK(
22028 : i->Equals(
22029 : context.local(),
22030 : foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
22031 : .FromJust());
22032 30 : CHECK(o->Equals(context.local(),
22033 : context->Global()->Get(context.local(), id).ToLocalChecked())
22034 : .FromJust());
22035 :
22036 : // Checking local function's receiver.
22037 : // Calling function using its call/apply methods.
22038 12 : TestReceiver(o, context->Global(), "ownfunc.call()");
22039 12 : TestReceiver(o, context->Global(), "ownfunc.apply()");
22040 : // Making calls through built-in functions.
22041 12 : TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
22042 12 : CHECK(
22043 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
22044 : .FromJust());
22045 12 : CHECK(
22046 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
22047 : .FromJust());
22048 12 : CHECK(
22049 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
22050 : .FromJust());
22051 : // Calling with environment record as base.
22052 12 : TestReceiver(o, context->Global(), "ownfunc()");
22053 : // Calling with no base.
22054 12 : TestReceiver(o, context->Global(), "(1,ownfunc)()");
22055 :
22056 : // Checking foreign function return value.
22057 : // Calling function using its call/apply methods.
22058 12 : TestReceiver(i, foreign_context->Global(), "func.call()");
22059 12 : TestReceiver(i, foreign_context->Global(), "func.apply()");
22060 : // Calling function using another context's call/apply methods.
22061 : TestReceiver(i, foreign_context->Global(),
22062 12 : "Function.prototype.call.call(func)");
22063 : TestReceiver(i, foreign_context->Global(),
22064 12 : "Function.prototype.call.apply(func)");
22065 : TestReceiver(i, foreign_context->Global(),
22066 12 : "Function.prototype.apply.call(func)");
22067 : TestReceiver(i, foreign_context->Global(),
22068 12 : "Function.prototype.apply.apply(func)");
22069 : // Making calls through built-in functions.
22070 12 : TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
22071 : // ToString(func()) is func()[0], i.e., the returned this.id.
22072 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
22073 : .FromJust());
22074 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
22075 : .FromJust());
22076 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
22077 : .FromJust());
22078 :
22079 : // Calling with environment record as base.
22080 12 : TestReceiver(i, foreign_context->Global(), "func()");
22081 : // Calling with no base.
22082 18 : TestReceiver(i, foreign_context->Global(), "(1,func)()");
22083 6 : }
22084 :
22085 :
22086 : uint8_t callback_fired = 0;
22087 : uint8_t before_call_entered_callback_count1 = 0;
22088 : uint8_t before_call_entered_callback_count2 = 0;
22089 :
22090 :
22091 5 : void CallCompletedCallback1(v8::Isolate*) {
22092 5 : v8::base::OS::Print("Firing callback 1.\n");
22093 5 : callback_fired ^= 1; // Toggle first bit.
22094 5 : }
22095 :
22096 :
22097 15 : void CallCompletedCallback2(v8::Isolate*) {
22098 15 : v8::base::OS::Print("Firing callback 2.\n");
22099 15 : callback_fired ^= 2; // Toggle second bit.
22100 15 : }
22101 :
22102 :
22103 20 : void BeforeCallEnteredCallback1(v8::Isolate*) {
22104 20 : v8::base::OS::Print("Firing before call entered callback 1.\n");
22105 20 : before_call_entered_callback_count1++;
22106 20 : }
22107 :
22108 :
22109 60 : void BeforeCallEnteredCallback2(v8::Isolate*) {
22110 60 : v8::base::OS::Print("Firing before call entered callback 2.\n");
22111 60 : before_call_entered_callback_count2++;
22112 60 : }
22113 :
22114 :
22115 60 : void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
22116 : int32_t level =
22117 180 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
22118 60 : if (level < 3) {
22119 45 : level++;
22120 45 : v8::base::OS::Print("Entering recursion level %d.\n", level);
22121 : char script[64];
22122 : i::Vector<char> script_vector(script, sizeof(script));
22123 45 : i::SNPrintF(script_vector, "recursion(%d)", level);
22124 : CompileRun(script_vector.start());
22125 45 : v8::base::OS::Print("Leaving recursion level %d.\n", level);
22126 90 : CHECK_EQ(0, callback_fired);
22127 : } else {
22128 15 : v8::base::OS::Print("Recursion ends.\n");
22129 30 : CHECK_EQ(0, callback_fired);
22130 : }
22131 60 : }
22132 :
22133 :
22134 28342 : TEST(CallCompletedCallback) {
22135 5 : LocalContext env;
22136 10 : v8::HandleScope scope(env->GetIsolate());
22137 : v8::Local<v8::FunctionTemplate> recursive_runtime =
22138 5 : v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
22139 : env->Global()
22140 : ->Set(env.local(), v8_str("recursion"),
22141 30 : recursive_runtime->GetFunction(env.local()).ToLocalChecked())
22142 10 : .FromJust();
22143 : // Adding the same callback a second time has no effect.
22144 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
22145 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
22146 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
22147 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
22148 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
22149 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
22150 5 : v8::base::OS::Print("--- Script (1) ---\n");
22151 5 : callback_fired = 0;
22152 5 : before_call_entered_callback_count1 = 0;
22153 5 : before_call_entered_callback_count2 = 0;
22154 : Local<Script> script =
22155 5 : v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
22156 5 : script->Run(env.local()).ToLocalChecked();
22157 10 : CHECK_EQ(3, callback_fired);
22158 10 : CHECK_EQ(4, before_call_entered_callback_count1);
22159 10 : CHECK_EQ(4, before_call_entered_callback_count2);
22160 :
22161 5 : v8::base::OS::Print("\n--- Script (2) ---\n");
22162 5 : callback_fired = 0;
22163 5 : before_call_entered_callback_count1 = 0;
22164 5 : before_call_entered_callback_count2 = 0;
22165 5 : env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
22166 : env->GetIsolate()->RemoveBeforeCallEnteredCallback(
22167 5 : BeforeCallEnteredCallback1);
22168 5 : script->Run(env.local()).ToLocalChecked();
22169 10 : CHECK_EQ(2, callback_fired);
22170 10 : CHECK_EQ(0, before_call_entered_callback_count1);
22171 10 : CHECK_EQ(4, before_call_entered_callback_count2);
22172 :
22173 5 : v8::base::OS::Print("\n--- Function ---\n");
22174 5 : callback_fired = 0;
22175 5 : before_call_entered_callback_count1 = 0;
22176 5 : before_call_entered_callback_count2 = 0;
22177 : Local<Function> recursive_function = Local<Function>::Cast(
22178 25 : env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
22179 5 : v8::Local<Value> args[] = {v8_num(0)};
22180 15 : recursive_function->Call(env.local(), env->Global(), 1, args)
22181 5 : .ToLocalChecked();
22182 10 : CHECK_EQ(2, callback_fired);
22183 10 : CHECK_EQ(0, before_call_entered_callback_count1);
22184 15 : CHECK_EQ(4, before_call_entered_callback_count2);
22185 5 : }
22186 :
22187 :
22188 5 : void CallCompletedCallbackNoException(v8::Isolate*) {
22189 5 : v8::HandleScope scope(CcTest::isolate());
22190 5 : CompileRun("1+1;");
22191 5 : }
22192 :
22193 :
22194 5 : void CallCompletedCallbackException(v8::Isolate*) {
22195 5 : v8::HandleScope scope(CcTest::isolate());
22196 5 : CompileRun("throw 'second exception';");
22197 5 : }
22198 :
22199 :
22200 28342 : TEST(CallCompletedCallbackOneException) {
22201 5 : LocalContext env;
22202 10 : v8::HandleScope scope(env->GetIsolate());
22203 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
22204 5 : CompileRun("throw 'exception';");
22205 5 : }
22206 :
22207 :
22208 28342 : TEST(CallCompletedCallbackTwoExceptions) {
22209 5 : LocalContext env;
22210 10 : v8::HandleScope scope(env->GetIsolate());
22211 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
22212 5 : CompileRun("throw 'first exception';");
22213 5 : }
22214 :
22215 :
22216 135 : static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
22217 45 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
22218 45 : v8::HandleScope scope(info.GetIsolate());
22219 : v8::MicrotasksScope microtasks(info.GetIsolate(),
22220 90 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22221 45 : CompileRun("ext1Calls++;");
22222 45 : }
22223 :
22224 :
22225 150 : static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
22226 50 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
22227 50 : v8::HandleScope scope(info.GetIsolate());
22228 : v8::MicrotasksScope microtasks(info.GetIsolate(),
22229 100 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22230 50 : CompileRun("ext2Calls++;");
22231 50 : }
22232 :
22233 : void* g_passed_to_three = nullptr;
22234 :
22235 10 : static void MicrotaskThree(void* data) {
22236 10 : g_passed_to_three = data;
22237 10 : }
22238 :
22239 :
22240 28342 : TEST(EnqueueMicrotask) {
22241 5 : LocalContext env;
22242 10 : v8::HandleScope scope(env->GetIsolate());
22243 5 : CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
22244 : CompileRun(
22245 : "var ext1Calls = 0;"
22246 : "var ext2Calls = 0;");
22247 : CompileRun("1+1;");
22248 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22249 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22250 :
22251 : env->GetIsolate()->EnqueueMicrotask(
22252 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22253 : CompileRun("1+1;");
22254 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22255 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22256 :
22257 : env->GetIsolate()->EnqueueMicrotask(
22258 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22259 : env->GetIsolate()->EnqueueMicrotask(
22260 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22261 : CompileRun("1+1;");
22262 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22263 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22264 :
22265 : env->GetIsolate()->EnqueueMicrotask(
22266 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22267 : CompileRun("1+1;");
22268 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22269 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22270 :
22271 : CompileRun("1+1;");
22272 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22273 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22274 :
22275 5 : g_passed_to_three = nullptr;
22276 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
22277 : CompileRun("1+1;");
22278 5 : CHECK(!g_passed_to_three);
22279 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22280 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22281 :
22282 : int dummy;
22283 : env->GetIsolate()->EnqueueMicrotask(
22284 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22285 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
22286 : env->GetIsolate()->EnqueueMicrotask(
22287 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22288 : CompileRun("1+1;");
22289 5 : CHECK_EQ(&dummy, g_passed_to_three);
22290 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22291 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22292 10 : g_passed_to_three = nullptr;
22293 5 : }
22294 :
22295 :
22296 5 : static void MicrotaskExceptionOne(
22297 10 : const v8::FunctionCallbackInfo<Value>& info) {
22298 5 : v8::HandleScope scope(info.GetIsolate());
22299 : CompileRun("exception1Calls++;");
22300 : info.GetIsolate()->ThrowException(
22301 10 : v8::Exception::Error(v8_str("first")));
22302 5 : }
22303 :
22304 :
22305 5 : static void MicrotaskExceptionTwo(
22306 10 : const v8::FunctionCallbackInfo<Value>& info) {
22307 5 : v8::HandleScope scope(info.GetIsolate());
22308 : CompileRun("exception2Calls++;");
22309 : info.GetIsolate()->ThrowException(
22310 10 : v8::Exception::Error(v8_str("second")));
22311 5 : }
22312 :
22313 :
22314 28342 : TEST(RunMicrotasksIgnoresThrownExceptions) {
22315 5 : LocalContext env;
22316 5 : v8::Isolate* isolate = env->GetIsolate();
22317 10 : v8::HandleScope scope(isolate);
22318 : CompileRun(
22319 : "var exception1Calls = 0;"
22320 : "var exception2Calls = 0;");
22321 : isolate->EnqueueMicrotask(
22322 10 : Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
22323 : isolate->EnqueueMicrotask(
22324 10 : Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
22325 10 : TryCatch try_catch(isolate);
22326 : CompileRun("1+1;");
22327 5 : CHECK(!try_catch.HasCaught());
22328 15 : CHECK_EQ(1,
22329 : CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
22330 15 : CHECK_EQ(1,
22331 5 : CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
22332 5 : }
22333 :
22334 5 : static void ThrowExceptionMicrotask(void* data) {
22335 10 : CcTest::isolate()->ThrowException(v8_str("exception"));
22336 5 : }
22337 :
22338 : int microtask_callback_count = 0;
22339 :
22340 5 : static void IncrementCounterMicrotask(void* data) {
22341 5 : microtask_callback_count++;
22342 5 : }
22343 :
22344 28342 : TEST(RunMicrotasksIgnoresThrownExceptionsFromApi) {
22345 5 : LocalContext env;
22346 5 : v8::Isolate* isolate = CcTest::isolate();
22347 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
22348 10 : v8::HandleScope scope(isolate);
22349 10 : v8::TryCatch try_catch(isolate);
22350 : {
22351 5 : CHECK(!isolate->IsExecutionTerminating());
22352 5 : isolate->EnqueueMicrotask(ThrowExceptionMicrotask);
22353 5 : isolate->EnqueueMicrotask(IncrementCounterMicrotask);
22354 5 : isolate->RunMicrotasks();
22355 5 : CHECK_EQ(1, microtask_callback_count);
22356 5 : CHECK(!try_catch.HasCaught());
22357 5 : }
22358 5 : }
22359 :
22360 : uint8_t microtasks_completed_callback_count = 0;
22361 :
22362 :
22363 25 : static void MicrotasksCompletedCallback(v8::Isolate* isolate) {
22364 25 : ++microtasks_completed_callback_count;
22365 25 : }
22366 :
22367 :
22368 28342 : TEST(SetAutorunMicrotasks) {
22369 5 : LocalContext env;
22370 10 : v8::HandleScope scope(env->GetIsolate());
22371 : env->GetIsolate()->AddMicrotasksCompletedCallback(
22372 5 : &MicrotasksCompletedCallback);
22373 : CompileRun(
22374 : "var ext1Calls = 0;"
22375 : "var ext2Calls = 0;");
22376 : CompileRun("1+1;");
22377 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22378 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22379 5 : CHECK_EQ(0u, microtasks_completed_callback_count);
22380 :
22381 : env->GetIsolate()->EnqueueMicrotask(
22382 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22383 : CompileRun("1+1;");
22384 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22385 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22386 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
22387 :
22388 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
22389 : env->GetIsolate()->EnqueueMicrotask(
22390 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22391 : env->GetIsolate()->EnqueueMicrotask(
22392 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22393 : CompileRun("1+1;");
22394 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22395 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22396 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
22397 :
22398 5 : env->GetIsolate()->RunMicrotasks();
22399 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22400 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22401 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
22402 :
22403 : env->GetIsolate()->EnqueueMicrotask(
22404 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22405 : CompileRun("1+1;");
22406 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22407 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22408 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
22409 :
22410 5 : env->GetIsolate()->RunMicrotasks();
22411 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22412 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22413 5 : CHECK_EQ(3u, microtasks_completed_callback_count);
22414 :
22415 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22416 : env->GetIsolate()->EnqueueMicrotask(
22417 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22418 : CompileRun("1+1;");
22419 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22420 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22421 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
22422 :
22423 : env->GetIsolate()->EnqueueMicrotask(
22424 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22425 : {
22426 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
22427 : CompileRun("1+1;");
22428 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22429 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22430 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
22431 : }
22432 :
22433 : CompileRun("1+1;");
22434 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22435 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22436 5 : CHECK_EQ(5u, microtasks_completed_callback_count);
22437 :
22438 : env->GetIsolate()->RemoveMicrotasksCompletedCallback(
22439 5 : &MicrotasksCompletedCallback);
22440 : env->GetIsolate()->EnqueueMicrotask(
22441 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22442 : CompileRun("1+1;");
22443 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22444 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22445 10 : CHECK_EQ(5u, microtasks_completed_callback_count);
22446 5 : }
22447 :
22448 :
22449 28342 : TEST(RunMicrotasksWithoutEnteringContext) {
22450 5 : v8::Isolate* isolate = CcTest::isolate();
22451 5 : HandleScope handle_scope(isolate);
22452 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
22453 5 : Local<Context> context = Context::New(isolate);
22454 : {
22455 : Context::Scope context_scope(context);
22456 : CompileRun("var ext1Calls = 0;");
22457 : isolate->EnqueueMicrotask(
22458 10 : Function::New(context, MicrotaskOne).ToLocalChecked());
22459 : }
22460 5 : isolate->RunMicrotasks();
22461 : {
22462 : Context::Scope context_scope(context);
22463 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
22464 : }
22465 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22466 5 : }
22467 :
22468 6 : static void Regress808911_MicrotaskCallback(void* data) {
22469 : // So here we expect "current context" to be context1 and
22470 : // "entered or microtask context" to be context2.
22471 : v8::Isolate* isolate = static_cast<v8::Isolate*>(data);
22472 12 : CHECK(isolate->GetCurrentContext() !=
22473 : isolate->GetEnteredOrMicrotaskContext());
22474 6 : }
22475 :
22476 6 : static void Regress808911_CurrentContextWrapper(
22477 6 : const v8::FunctionCallbackInfo<Value>& info) {
22478 : // So here we expect "current context" to be context1 and
22479 : // "entered or microtask context" to be context2.
22480 : v8::Isolate* isolate = info.GetIsolate();
22481 12 : CHECK(isolate->GetCurrentContext() !=
22482 : isolate->GetEnteredOrMicrotaskContext());
22483 6 : isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
22484 6 : isolate->RunMicrotasks();
22485 6 : }
22486 :
22487 28343 : THREADED_TEST(Regress808911) {
22488 6 : v8::Isolate* isolate = CcTest::isolate();
22489 6 : HandleScope handle_scope(isolate);
22490 6 : Local<Context> context1 = Context::New(isolate);
22491 : Local<Function> function;
22492 : {
22493 : Context::Scope context_scope(context1);
22494 6 : function = Function::New(context1, Regress808911_CurrentContextWrapper)
22495 6 : .ToLocalChecked();
22496 : }
22497 6 : Local<Context> context2 = Context::New(isolate);
22498 : Context::Scope context_scope(context2);
22499 6 : function->CallAsFunction(context2, v8::Undefined(isolate), 0, nullptr)
22500 12 : .ToLocalChecked();
22501 6 : }
22502 :
22503 28342 : TEST(ScopedMicrotasks) {
22504 5 : LocalContext env;
22505 10 : v8::HandleScope handles(env->GetIsolate());
22506 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
22507 : {
22508 : v8::MicrotasksScope scope1(env->GetIsolate(),
22509 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22510 : env->GetIsolate()->EnqueueMicrotask(
22511 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22512 : CompileRun(
22513 : "var ext1Calls = 0;"
22514 : "var ext2Calls = 0;");
22515 : CompileRun("1+1;");
22516 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22517 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22518 : {
22519 : v8::MicrotasksScope scope2(env->GetIsolate(),
22520 5 : v8::MicrotasksScope::kRunMicrotasks);
22521 : CompileRun("1+1;");
22522 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22523 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22524 : {
22525 : v8::MicrotasksScope scope3(env->GetIsolate(),
22526 5 : v8::MicrotasksScope::kRunMicrotasks);
22527 : CompileRun("1+1;");
22528 15 : CHECK_EQ(0,
22529 : CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22530 15 : CHECK_EQ(0,
22531 5 : CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22532 : }
22533 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22534 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22535 : }
22536 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22537 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22538 : env->GetIsolate()->EnqueueMicrotask(
22539 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22540 : }
22541 :
22542 : {
22543 : v8::MicrotasksScope scope(env->GetIsolate(),
22544 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22545 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22546 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22547 : }
22548 :
22549 : {
22550 : v8::MicrotasksScope scope1(env->GetIsolate(),
22551 5 : v8::MicrotasksScope::kRunMicrotasks);
22552 : CompileRun("1+1;");
22553 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22554 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22555 : {
22556 : v8::MicrotasksScope scope2(env->GetIsolate(),
22557 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22558 : }
22559 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22560 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22561 : }
22562 :
22563 : {
22564 : v8::MicrotasksScope scope(env->GetIsolate(),
22565 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22566 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22567 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22568 : env->GetIsolate()->EnqueueMicrotask(
22569 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22570 : }
22571 :
22572 : {
22573 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
22574 : {
22575 : v8::MicrotasksScope scope2(env->GetIsolate(),
22576 5 : v8::MicrotasksScope::kRunMicrotasks);
22577 : }
22578 : v8::MicrotasksScope scope3(env->GetIsolate(),
22579 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22580 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22581 20 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22582 : }
22583 :
22584 : {
22585 : v8::MicrotasksScope scope1(env->GetIsolate(),
22586 5 : v8::MicrotasksScope::kRunMicrotasks);
22587 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22588 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22589 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22590 : }
22591 :
22592 : {
22593 : v8::MicrotasksScope scope(env->GetIsolate(),
22594 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22595 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22596 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22597 : }
22598 :
22599 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22600 :
22601 : {
22602 : v8::MicrotasksScope scope(env->GetIsolate(),
22603 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22604 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22605 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22606 : env->GetIsolate()->EnqueueMicrotask(
22607 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22608 : }
22609 :
22610 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22611 :
22612 : {
22613 : v8::MicrotasksScope scope(env->GetIsolate(),
22614 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22615 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22616 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22617 : }
22618 :
22619 : env->GetIsolate()->EnqueueMicrotask(
22620 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22621 : {
22622 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
22623 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22624 : v8::MicrotasksScope scope2(env->GetIsolate(),
22625 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22626 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22627 20 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22628 : }
22629 :
22630 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22631 :
22632 : {
22633 : v8::MicrotasksScope scope(env->GetIsolate(),
22634 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22635 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22636 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22637 : }
22638 :
22639 10 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22640 5 : }
22641 :
22642 : namespace {
22643 :
22644 35 : void AssertCowElements(bool expected, const char* source) {
22645 : Local<Value> object = CompileRun(source);
22646 : i::Handle<i::JSObject> array =
22647 35 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*object.As<Object>()));
22648 35 : CHECK_EQ(expected, array->elements()->IsCowArray());
22649 35 : }
22650 :
22651 : } // namespace
22652 :
22653 28342 : TEST(CheckCOWArraysCreatedRuntimeCounter) {
22654 5 : LocalContext env;
22655 10 : v8::HandleScope scope(env->GetIsolate());
22656 5 : AssertCowElements(true, "[1, 2, 3]");
22657 5 : AssertCowElements(false, "[[1], 2, 3]");
22658 5 : AssertCowElements(true, "[[1], 2, 3][0]");
22659 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.foo)");
22660 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.bar)");
22661 5 : AssertCowElements(false, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo)");
22662 10 : AssertCowElements(true, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo[3])");
22663 5 : }
22664 :
22665 :
22666 28342 : TEST(StaticGetters) {
22667 5 : LocalContext context;
22668 : i::Factory* factory = CcTest::i_isolate()->factory();
22669 5 : v8::Isolate* isolate = CcTest::isolate();
22670 10 : v8::HandleScope scope(isolate);
22671 : i::Handle<i::Object> undefined_value = factory->undefined_value();
22672 5 : CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
22673 : i::Handle<i::Object> null_value = factory->null_value();
22674 5 : CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
22675 : i::Handle<i::Object> true_value = factory->true_value();
22676 5 : CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
22677 : i::Handle<i::Object> false_value = factory->false_value();
22678 10 : CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
22679 5 : }
22680 :
22681 :
22682 28342 : UNINITIALIZED_TEST(IsolateEmbedderData) {
22683 5 : CcTest::DisableAutomaticDispose();
22684 : v8::Isolate::CreateParams create_params;
22685 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
22686 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
22687 5 : isolate->Enter();
22688 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22689 25 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22690 20 : CHECK(!isolate->GetData(slot));
22691 20 : CHECK(!i_isolate->GetData(slot));
22692 : }
22693 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22694 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
22695 : isolate->SetData(slot, data);
22696 : }
22697 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22698 20 : void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
22699 20 : CHECK_EQ(data, isolate->GetData(slot));
22700 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22701 : }
22702 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22703 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
22704 : isolate->SetData(slot, data);
22705 : }
22706 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22707 20 : void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
22708 20 : CHECK_EQ(data, isolate->GetData(slot));
22709 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22710 : }
22711 5 : isolate->Exit();
22712 5 : isolate->Dispose();
22713 5 : }
22714 :
22715 :
22716 28342 : TEST(StringEmpty) {
22717 5 : LocalContext context;
22718 : i::Factory* factory = CcTest::i_isolate()->factory();
22719 5 : v8::Isolate* isolate = CcTest::isolate();
22720 10 : v8::HandleScope scope(isolate);
22721 : i::Handle<i::Object> empty_string = factory->empty_string();
22722 10 : CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22723 5 : }
22724 :
22725 :
22726 : static int instance_checked_getter_count = 0;
22727 120 : static void InstanceCheckedGetter(
22728 : Local<String> name,
22729 : const v8::PropertyCallbackInfo<v8::Value>& info) {
22730 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22731 : .FromJust());
22732 120 : instance_checked_getter_count++;
22733 120 : info.GetReturnValue().Set(v8_num(11));
22734 120 : }
22735 :
22736 :
22737 : static int instance_checked_setter_count = 0;
22738 120 : static void InstanceCheckedSetter(Local<String> name,
22739 : Local<Value> value,
22740 : const v8::PropertyCallbackInfo<void>& info) {
22741 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22742 : .FromJust());
22743 480 : CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
22744 : .FromJust());
22745 120 : instance_checked_setter_count++;
22746 120 : }
22747 :
22748 :
22749 420 : static void CheckInstanceCheckedResult(int getters, int setters,
22750 : bool expects_callbacks,
22751 : TryCatch* try_catch) {
22752 420 : if (expects_callbacks) {
22753 240 : CHECK(!try_catch->HasCaught());
22754 240 : CHECK_EQ(getters, instance_checked_getter_count);
22755 240 : CHECK_EQ(setters, instance_checked_setter_count);
22756 : } else {
22757 180 : CHECK(try_catch->HasCaught());
22758 180 : CHECK_EQ(0, instance_checked_getter_count);
22759 180 : CHECK_EQ(0, instance_checked_setter_count);
22760 : }
22761 420 : try_catch->Reset();
22762 420 : }
22763 :
22764 :
22765 42 : static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22766 42 : instance_checked_getter_count = 0;
22767 42 : instance_checked_setter_count = 0;
22768 42 : TryCatch try_catch(CcTest::isolate());
22769 :
22770 : // Test path through generic runtime code.
22771 : CompileRun("obj.foo");
22772 42 : CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22773 : CompileRun("obj.foo = 23");
22774 42 : CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22775 :
22776 : // Test path through generated LoadIC and StoredIC.
22777 : CompileRun("function test_get(o) { o.foo; }"
22778 : "test_get(obj);");
22779 42 : CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22780 : CompileRun("test_get(obj);");
22781 42 : CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22782 : CompileRun("test_get(obj);");
22783 42 : CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22784 : CompileRun("function test_set(o) { o.foo = 23; }"
22785 : "test_set(obj);");
22786 42 : CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22787 : CompileRun("test_set(obj);");
22788 42 : CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22789 : CompileRun("test_set(obj);");
22790 42 : CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22791 :
22792 : // Test path through optimized code.
22793 : CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22794 : "test_get(obj);");
22795 42 : CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22796 : CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22797 : "test_set(obj);");
22798 42 : CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22799 :
22800 : // Cleanup so that closures start out fresh in next check.
22801 : CompileRun(
22802 : "%DeoptimizeFunction(test_get);"
22803 : "%ClearFunctionFeedback(test_get);"
22804 : "%DeoptimizeFunction(test_set);"
22805 42 : "%ClearFunctionFeedback(test_set);");
22806 42 : }
22807 :
22808 :
22809 28343 : THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22810 6 : v8::internal::FLAG_allow_natives_syntax = true;
22811 6 : LocalContext context;
22812 12 : v8::HandleScope scope(context->GetIsolate());
22813 :
22814 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22815 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22816 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22817 : Local<Value>(), v8::DEFAULT, v8::None,
22818 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22819 36 : CHECK(context->Global()
22820 : ->Set(context.local(), v8_str("f"),
22821 : templ->GetFunction(context.local()).ToLocalChecked())
22822 : .FromJust());
22823 :
22824 : printf("Testing positive ...\n");
22825 : CompileRun("var obj = new f();");
22826 30 : CHECK(templ->HasInstance(
22827 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22828 6 : CheckInstanceCheckedAccessors(true);
22829 :
22830 : printf("Testing negative ...\n");
22831 : CompileRun("var obj = {};"
22832 : "obj.__proto__ = new f();");
22833 30 : CHECK(!templ->HasInstance(
22834 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22835 12 : CheckInstanceCheckedAccessors(false);
22836 6 : }
22837 :
22838 90 : static void EmptyInterceptorGetter(
22839 90 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22840 :
22841 30 : static void EmptyInterceptorSetter(
22842 : Local<Name> name, Local<Value> value,
22843 30 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
22844 :
22845 28343 : THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22846 6 : v8::internal::FLAG_allow_natives_syntax = true;
22847 6 : LocalContext context;
22848 12 : v8::HandleScope scope(context->GetIsolate());
22849 :
22850 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22851 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22852 : templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
22853 12 : EmptyInterceptorGetter, EmptyInterceptorSetter));
22854 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22855 : Local<Value>(), v8::DEFAULT, v8::None,
22856 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22857 36 : CHECK(context->Global()
22858 : ->Set(context.local(), v8_str("f"),
22859 : templ->GetFunction(context.local()).ToLocalChecked())
22860 : .FromJust());
22861 :
22862 : printf("Testing positive ...\n");
22863 : CompileRun("var obj = new f();");
22864 30 : CHECK(templ->HasInstance(
22865 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22866 6 : CheckInstanceCheckedAccessors(true);
22867 :
22868 : printf("Testing negative ...\n");
22869 : CompileRun("var obj = {};"
22870 : "obj.__proto__ = new f();");
22871 30 : CHECK(!templ->HasInstance(
22872 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22873 12 : CheckInstanceCheckedAccessors(false);
22874 6 : }
22875 :
22876 :
22877 28343 : THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22878 6 : v8::internal::FLAG_allow_natives_syntax = true;
22879 6 : LocalContext context;
22880 12 : v8::HandleScope scope(context->GetIsolate());
22881 :
22882 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22883 6 : Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22884 : proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22885 : InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
22886 : v8::None,
22887 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22888 36 : CHECK(context->Global()
22889 : ->Set(context.local(), v8_str("f"),
22890 : templ->GetFunction(context.local()).ToLocalChecked())
22891 : .FromJust());
22892 :
22893 : printf("Testing positive ...\n");
22894 : CompileRun("var obj = new f();");
22895 30 : CHECK(templ->HasInstance(
22896 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22897 6 : CheckInstanceCheckedAccessors(true);
22898 :
22899 : printf("Testing negative ...\n");
22900 : CompileRun("var obj = {};"
22901 : "obj.__proto__ = new f();");
22902 30 : CHECK(!templ->HasInstance(
22903 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22904 6 : CheckInstanceCheckedAccessors(false);
22905 :
22906 : printf("Testing positive with modified prototype chain ...\n");
22907 : CompileRun("var obj = new f();"
22908 : "var pro = {};"
22909 : "pro.__proto__ = obj.__proto__;"
22910 : "obj.__proto__ = pro;");
22911 30 : CHECK(templ->HasInstance(
22912 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22913 12 : CheckInstanceCheckedAccessors(true);
22914 6 : }
22915 :
22916 :
22917 28342 : TEST(TryFinallyMessage) {
22918 5 : LocalContext context;
22919 10 : v8::HandleScope scope(context->GetIsolate());
22920 : {
22921 : // Test that the original error message is not lost if there is a
22922 : // recursive call into Javascript is done in the finally block, e.g. to
22923 : // initialize an IC. (crbug.com/129171)
22924 5 : TryCatch try_catch(context->GetIsolate());
22925 : const char* trigger_ic =
22926 : "try { \n"
22927 : " throw new Error('test'); \n"
22928 : "} finally { \n"
22929 : " var x = 0; \n"
22930 : " x++; \n" // Trigger an IC initialization here.
22931 : "} \n";
22932 : CompileRun(trigger_ic);
22933 5 : CHECK(try_catch.HasCaught());
22934 5 : Local<Message> message = try_catch.Message();
22935 5 : CHECK(!message.IsEmpty());
22936 10 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
22937 : }
22938 :
22939 : {
22940 : // Test that the original exception message is indeed overwritten if
22941 : // a new error is thrown in the finally block.
22942 5 : TryCatch try_catch(context->GetIsolate());
22943 : const char* throw_again =
22944 : "try { \n"
22945 : " throw new Error('test'); \n"
22946 : "} finally { \n"
22947 : " var x = 0; \n"
22948 : " x++; \n"
22949 : " throw new Error('again'); \n" // This is the new uncaught error.
22950 : "} \n";
22951 : CompileRun(throw_again);
22952 5 : CHECK(try_catch.HasCaught());
22953 5 : Local<Message> message = try_catch.Message();
22954 5 : CHECK(!message.IsEmpty());
22955 10 : CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
22956 5 : }
22957 5 : }
22958 :
22959 :
22960 96 : static void Helper137002(bool do_store,
22961 : bool polymorphic,
22962 : bool remove_accessor,
22963 : bool interceptor) {
22964 96 : LocalContext context;
22965 96 : Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22966 96 : if (interceptor) {
22967 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22968 48 : FooSetInterceptor));
22969 : } else {
22970 : templ->SetAccessor(v8_str("foo"),
22971 : GetterWhichReturns42,
22972 48 : SetterWhichSetsYOnThisTo23);
22973 : }
22974 576 : CHECK(context->Global()
22975 : ->Set(context.local(), v8_str("obj"),
22976 : templ->NewInstance(context.local()).ToLocalChecked())
22977 : .FromJust());
22978 :
22979 : // Turn monomorphic on slow object with native accessor, then turn
22980 : // polymorphic, finally optimize to create negative lookup and fail.
22981 : CompileRun(do_store ?
22982 : "function f(x) { x.foo = void 0; }" :
22983 96 : "function f(x) { return x.foo; }");
22984 : CompileRun("obj.y = void 0;");
22985 96 : if (!interceptor) {
22986 : CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22987 : }
22988 : CompileRun("obj.__proto__ = null;"
22989 : "f(obj); f(obj); f(obj);");
22990 96 : if (polymorphic) {
22991 : CompileRun("f({});");
22992 : }
22993 : CompileRun("obj.y = void 0;"
22994 : "%OptimizeFunctionOnNextCall(f);");
22995 96 : if (remove_accessor) {
22996 : CompileRun("delete obj.foo;");
22997 : }
22998 : CompileRun("var result = f(obj);");
22999 96 : if (do_store) {
23000 : CompileRun("result = obj.y;");
23001 : }
23002 96 : if (remove_accessor && !interceptor) {
23003 120 : CHECK(context->Global()
23004 : ->Get(context.local(), v8_str("result"))
23005 : .ToLocalChecked()
23006 : ->IsUndefined());
23007 : } else {
23008 432 : CHECK_EQ(do_store ? 23 : 42, context->Global()
23009 : ->Get(context.local(), v8_str("result"))
23010 : .ToLocalChecked()
23011 : ->Int32Value(context.local())
23012 : .FromJust());
23013 96 : }
23014 96 : }
23015 :
23016 :
23017 28343 : THREADED_TEST(Regress137002a) {
23018 6 : i::FLAG_allow_natives_syntax = true;
23019 6 : i::FLAG_compilation_cache = false;
23020 6 : v8::HandleScope scope(CcTest::isolate());
23021 102 : for (int i = 0; i < 16; i++) {
23022 96 : Helper137002(i & 8, i & 4, i & 2, i & 1);
23023 6 : }
23024 6 : }
23025 :
23026 :
23027 28343 : THREADED_TEST(Regress137002b) {
23028 6 : i::FLAG_allow_natives_syntax = true;
23029 6 : LocalContext context;
23030 6 : v8::Isolate* isolate = context->GetIsolate();
23031 12 : v8::HandleScope scope(isolate);
23032 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23033 : templ->SetAccessor(v8_str("foo"),
23034 : GetterWhichReturns42,
23035 6 : SetterWhichSetsYOnThisTo23);
23036 36 : CHECK(context->Global()
23037 : ->Set(context.local(), v8_str("obj"),
23038 : templ->NewInstance(context.local()).ToLocalChecked())
23039 : .FromJust());
23040 :
23041 : // Turn monomorphic on slow object with native accessor, then just
23042 : // delete the property and fail.
23043 : CompileRun("function load(x) { return x.foo; }"
23044 : "function store(x) { x.foo = void 0; }"
23045 : "function keyed_load(x, key) { return x[key]; }"
23046 : // Second version of function has a different source (add void 0)
23047 : // so that it does not share code with the first version. This
23048 : // ensures that the ICs are monomorphic.
23049 : "function load2(x) { void 0; return x.foo; }"
23050 : "function store2(x) { void 0; x.foo = void 0; }"
23051 : "function keyed_load2(x, key) { void 0; return x[key]; }"
23052 :
23053 : "obj.y = void 0;"
23054 : "obj.__proto__ = null;"
23055 : "var subobj = {};"
23056 : "subobj.y = void 0;"
23057 : "subobj.__proto__ = obj;"
23058 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
23059 :
23060 : // Make the ICs monomorphic.
23061 : "load(obj); load(obj);"
23062 : "load2(subobj); load2(subobj);"
23063 : "store(obj); store(obj);"
23064 : "store2(subobj); store2(subobj);"
23065 : "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
23066 : "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
23067 :
23068 : // Actually test the shiny new ICs and better not crash. This
23069 : // serves as a regression test for issue 142088 as well.
23070 : "load(obj);"
23071 : "load2(subobj);"
23072 : "store(obj);"
23073 : "store2(subobj);"
23074 : "keyed_load(obj, 'foo');"
23075 : "keyed_load2(subobj, 'foo');"
23076 :
23077 : // Delete the accessor. It better not be called any more now.
23078 : "delete obj.foo;"
23079 : "obj.y = void 0;"
23080 : "subobj.y = void 0;"
23081 :
23082 : "var load_result = load(obj);"
23083 : "var load_result2 = load2(subobj);"
23084 : "var keyed_load_result = keyed_load(obj, 'foo');"
23085 : "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
23086 : "store(obj);"
23087 : "store2(subobj);"
23088 : "var y_from_obj = obj.y;"
23089 : "var y_from_subobj = subobj.y;");
23090 30 : CHECK(context->Global()
23091 : ->Get(context.local(), v8_str("load_result"))
23092 : .ToLocalChecked()
23093 : ->IsUndefined());
23094 30 : CHECK(context->Global()
23095 : ->Get(context.local(), v8_str("load_result2"))
23096 : .ToLocalChecked()
23097 : ->IsUndefined());
23098 30 : CHECK(context->Global()
23099 : ->Get(context.local(), v8_str("keyed_load_result"))
23100 : .ToLocalChecked()
23101 : ->IsUndefined());
23102 30 : CHECK(context->Global()
23103 : ->Get(context.local(), v8_str("keyed_load_result2"))
23104 : .ToLocalChecked()
23105 : ->IsUndefined());
23106 30 : CHECK(context->Global()
23107 : ->Get(context.local(), v8_str("y_from_obj"))
23108 : .ToLocalChecked()
23109 : ->IsUndefined());
23110 30 : CHECK(context->Global()
23111 : ->Get(context.local(), v8_str("y_from_subobj"))
23112 : .ToLocalChecked()
23113 6 : ->IsUndefined());
23114 6 : }
23115 :
23116 :
23117 28343 : THREADED_TEST(Regress142088) {
23118 6 : i::FLAG_allow_natives_syntax = true;
23119 6 : LocalContext context;
23120 6 : v8::Isolate* isolate = context->GetIsolate();
23121 12 : v8::HandleScope scope(isolate);
23122 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23123 : templ->SetAccessor(v8_str("foo"),
23124 : GetterWhichReturns42,
23125 6 : SetterWhichSetsYOnThisTo23);
23126 36 : CHECK(context->Global()
23127 : ->Set(context.local(), v8_str("obj"),
23128 : templ->NewInstance(context.local()).ToLocalChecked())
23129 : .FromJust());
23130 :
23131 : CompileRun("function load(x) { return x.foo; }"
23132 : "var o = Object.create(obj);"
23133 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
23134 6 : "load(o); load(o); load(o); load(o);");
23135 6 : }
23136 :
23137 :
23138 28343 : THREADED_TEST(Regress137496) {
23139 6 : i::FLAG_expose_gc = true;
23140 6 : LocalContext context;
23141 12 : v8::HandleScope scope(context->GetIsolate());
23142 :
23143 : // Compile a try-finally clause where the finally block causes a GC
23144 : // while there still is a message pending for external reporting.
23145 12 : TryCatch try_catch(context->GetIsolate());
23146 6 : try_catch.SetVerbose(true);
23147 : CompileRun("try { throw new Error(); } finally { gc(); }");
23148 12 : CHECK(try_catch.HasCaught());
23149 6 : }
23150 :
23151 :
23152 28343 : THREADED_TEST(Regress157124) {
23153 6 : LocalContext context;
23154 6 : v8::Isolate* isolate = context->GetIsolate();
23155 12 : v8::HandleScope scope(isolate);
23156 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23157 12 : Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
23158 6 : obj->GetIdentityHash();
23159 : obj->DeletePrivate(context.local(),
23160 6 : v8::Private::ForApi(isolate, v8_str("Bug")))
23161 18 : .FromJust();
23162 6 : }
23163 :
23164 :
23165 28343 : THREADED_TEST(Regress2535) {
23166 6 : LocalContext context;
23167 12 : v8::HandleScope scope(context->GetIsolate());
23168 : Local<Value> set_value = CompileRun("new Set();");
23169 : Local<Object> set_object(Local<Object>::Cast(set_value));
23170 6 : CHECK_EQ(0, set_object->InternalFieldCount());
23171 : Local<Value> map_value = CompileRun("new Map();");
23172 : Local<Object> map_object(Local<Object>::Cast(map_value));
23173 12 : CHECK_EQ(0, map_object->InternalFieldCount());
23174 6 : }
23175 :
23176 :
23177 28343 : THREADED_TEST(Regress2746) {
23178 6 : LocalContext context;
23179 6 : v8::Isolate* isolate = context->GetIsolate();
23180 12 : v8::HandleScope scope(isolate);
23181 6 : Local<Object> obj = Object::New(isolate);
23182 6 : Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
23183 12 : CHECK(
23184 : obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
23185 6 : Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
23186 6 : CHECK(!value.IsEmpty());
23187 12 : CHECK(value->IsUndefined());
23188 6 : }
23189 :
23190 :
23191 28343 : THREADED_TEST(Regress260106) {
23192 6 : LocalContext context;
23193 6 : v8::Isolate* isolate = context->GetIsolate();
23194 12 : v8::HandleScope scope(isolate);
23195 : Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
23196 6 : DummyCallHandler);
23197 : CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
23198 : Local<Function> function =
23199 12 : templ->GetFunction(context.local()).ToLocalChecked();
23200 6 : CHECK(!function.IsEmpty());
23201 12 : CHECK(function->IsFunction());
23202 6 : }
23203 :
23204 28343 : THREADED_TEST(JSONParseObject) {
23205 6 : LocalContext context;
23206 12 : HandleScope scope(context->GetIsolate());
23207 : Local<Value> obj =
23208 12 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
23209 6 : Local<Object> global = context->Global();
23210 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23211 12 : ExpectString("JSON.stringify(obj)", "{\"x\":42}");
23212 6 : }
23213 :
23214 28343 : THREADED_TEST(JSONParseNumber) {
23215 6 : LocalContext context;
23216 12 : HandleScope scope(context->GetIsolate());
23217 : Local<Value> obj =
23218 12 : v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
23219 6 : Local<Object> global = context->Global();
23220 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23221 12 : ExpectString("JSON.stringify(obj)", "42");
23222 6 : }
23223 :
23224 : namespace {
23225 42 : void TestJSONParseArray(Local<Context> context, const char* input_str,
23226 : const char* expected_output_str,
23227 : i::ElementsKind expected_elements_kind) {
23228 : Local<Value> obj =
23229 42 : v8::JSON::Parse(context, v8_str(input_str)).ToLocalChecked();
23230 :
23231 : i::Handle<i::JSArray> a =
23232 42 : i::Handle<i::JSArray>::cast(v8::Utils::OpenHandle(*obj));
23233 42 : CHECK_EQ(expected_elements_kind, a->GetElementsKind());
23234 :
23235 42 : Local<Object> global = context->Global();
23236 126 : global->Set(context, v8_str("obj"), obj).FromJust();
23237 42 : ExpectString("JSON.stringify(obj)", expected_output_str);
23238 42 : }
23239 : } // namespace
23240 :
23241 28343 : THREADED_TEST(JSONParseArray) {
23242 6 : LocalContext context;
23243 12 : HandleScope scope(context->GetIsolate());
23244 :
23245 : TestJSONParseArray(context.local(), "[0, 1, 2]", "[0,1,2]",
23246 6 : i::PACKED_SMI_ELEMENTS);
23247 : TestJSONParseArray(context.local(), "[0, 1.2, 2]", "[0,1.2,2]",
23248 6 : i::PACKED_DOUBLE_ELEMENTS);
23249 : TestJSONParseArray(context.local(), "[0.2, 1, 2]", "[0.2,1,2]",
23250 6 : i::PACKED_DOUBLE_ELEMENTS);
23251 : TestJSONParseArray(context.local(), "[0, \"a\", 2]", "[0,\"a\",2]",
23252 6 : i::PACKED_ELEMENTS);
23253 : TestJSONParseArray(context.local(), "[\"a\", 1, 2]", "[\"a\",1,2]",
23254 6 : i::PACKED_ELEMENTS);
23255 : TestJSONParseArray(context.local(), "[\"a\", 1.2, 2]", "[\"a\",1.2,2]",
23256 6 : i::PACKED_ELEMENTS);
23257 : TestJSONParseArray(context.local(), "[0, 1.2, \"a\"]", "[0,1.2,\"a\"]",
23258 12 : i::PACKED_ELEMENTS);
23259 6 : }
23260 :
23261 28343 : THREADED_TEST(JSONStringifyObject) {
23262 6 : LocalContext context;
23263 12 : HandleScope scope(context->GetIsolate());
23264 : Local<Value> value =
23265 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
23266 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
23267 6 : Local<Object> global = context->Global();
23268 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23269 : Local<String> json =
23270 12 : v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
23271 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
23272 12 : ExpectString("JSON.stringify(obj)", *utf8);
23273 6 : }
23274 :
23275 28343 : THREADED_TEST(JSONStringifyObjectWithGap) {
23276 6 : LocalContext context;
23277 12 : HandleScope scope(context->GetIsolate());
23278 : Local<Value> value =
23279 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
23280 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
23281 6 : Local<Object> global = context->Global();
23282 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23283 : Local<String> json =
23284 18 : v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
23285 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
23286 12 : ExpectString("JSON.stringify(obj, null, '*')", *utf8);
23287 6 : }
23288 :
23289 : #if V8_OS_POSIX
23290 : class ThreadInterruptTest {
23291 : public:
23292 6 : ThreadInterruptTest() : sem_(0), sem_value_(0) { }
23293 6 : ~ThreadInterruptTest() = default;
23294 :
23295 6 : void RunTest() {
23296 : InterruptThread i_thread(this);
23297 6 : i_thread.Start();
23298 :
23299 6 : sem_.Wait();
23300 6 : CHECK_EQ(kExpectedValue, sem_value_);
23301 6 : }
23302 :
23303 : private:
23304 : static const int kExpectedValue = 1;
23305 :
23306 6 : class InterruptThread : public v8::base::Thread {
23307 : public:
23308 : explicit InterruptThread(ThreadInterruptTest* test)
23309 6 : : Thread(Options("InterruptThread")), test_(test) {}
23310 :
23311 6 : void Run() override {
23312 : struct sigaction action;
23313 :
23314 : // Ensure that we'll enter waiting condition
23315 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
23316 :
23317 : // Setup signal handler
23318 : memset(&action, 0, sizeof(action));
23319 6 : action.sa_handler = SignalHandler;
23320 6 : sigaction(SIGCHLD, &action, nullptr);
23321 :
23322 : // Send signal
23323 6 : kill(getpid(), SIGCHLD);
23324 :
23325 : // Ensure that if wait has returned because of error
23326 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
23327 :
23328 : // Set value and signal semaphore
23329 6 : test_->sem_value_ = 1;
23330 6 : test_->sem_.Signal();
23331 6 : }
23332 :
23333 6 : static void SignalHandler(int signal) {
23334 6 : }
23335 :
23336 : private:
23337 : ThreadInterruptTest* test_;
23338 : };
23339 :
23340 : v8::base::Semaphore sem_;
23341 : volatile int sem_value_;
23342 : };
23343 :
23344 :
23345 28343 : THREADED_TEST(SemaphoreInterruption) {
23346 12 : ThreadInterruptTest().RunTest();
23347 6 : }
23348 :
23349 :
23350 : #endif // V8_OS_POSIX
23351 :
23352 :
23353 0 : void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23354 0 : UNREACHABLE();
23355 : }
23356 :
23357 :
23358 28342 : TEST(JSONStringifyAccessCheck) {
23359 5 : v8::V8::Initialize();
23360 5 : v8::Isolate* isolate = CcTest::isolate();
23361 5 : v8::HandleScope scope(isolate);
23362 :
23363 : // Create an ObjectTemplate for global objects and install access
23364 : // check callbacks that will block access.
23365 : v8::Local<v8::ObjectTemplate> global_template =
23366 5 : v8::ObjectTemplate::New(isolate);
23367 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
23368 :
23369 : // Create a context and set an x property on it's global object.
23370 10 : LocalContext context0(nullptr, global_template);
23371 5 : v8::Local<v8::Object> global0 = context0->Global();
23372 15 : global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
23373 5 : ExpectString("JSON.stringify(this)", "{\"x\":42}");
23374 :
23375 15 : for (int i = 0; i < 2; i++) {
23376 10 : if (i == 1) {
23377 : // Install a toJSON function on the second run.
23378 : v8::Local<v8::FunctionTemplate> toJSON =
23379 5 : v8::FunctionTemplate::New(isolate, UnreachableCallback);
23380 :
23381 : global0->Set(context0.local(), v8_str("toJSON"),
23382 25 : toJSON->GetFunction(context0.local()).ToLocalChecked())
23383 10 : .FromJust();
23384 : }
23385 : // Create a context with a different security token so that the
23386 : // failed access check callback will be called on each access.
23387 10 : LocalContext context1(nullptr, global_template);
23388 50 : CHECK(context1->Global()
23389 : ->Set(context1.local(), v8_str("other"), global0)
23390 : .FromJust());
23391 :
23392 10 : CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
23393 10 : CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
23394 10 : CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
23395 15 : }
23396 5 : }
23397 :
23398 :
23399 : bool access_check_fail_thrown = false;
23400 : bool catch_callback_called = false;
23401 :
23402 :
23403 : // Failed access check callback that performs a GC on each invocation.
23404 80 : void FailedAccessCheckThrows(Local<v8::Object> target,
23405 : v8::AccessType type,
23406 : Local<v8::Value> data) {
23407 80 : access_check_fail_thrown = true;
23408 80 : i::PrintF("Access check failed. Error thrown.\n");
23409 : CcTest::isolate()->ThrowException(
23410 80 : v8::Exception::Error(v8_str("cross context")));
23411 80 : }
23412 :
23413 :
23414 300 : void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23415 300 : for (int i = 0; i < args.Length(); i++) {
23416 75 : i::PrintF("%s\n", *String::Utf8Value(args.GetIsolate(), args[i]));
23417 : }
23418 75 : catch_callback_called = true;
23419 75 : }
23420 :
23421 :
23422 5 : void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23423 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
23424 20 : CHECK(
23425 : args[0]
23426 : ->ToObject(context)
23427 : .ToLocalChecked()
23428 : ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
23429 : .IsNothing());
23430 5 : }
23431 :
23432 :
23433 75 : void CheckCorrectThrow(const char* script) {
23434 : // Test that the script, when wrapped into a try-catch, triggers the catch
23435 : // clause due to failed access check throwing an exception.
23436 : // The subsequent try-catch should run without any exception.
23437 75 : access_check_fail_thrown = false;
23438 75 : catch_callback_called = false;
23439 : i::ScopedVector<char> source(1024);
23440 75 : i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
23441 : CompileRun(source.start());
23442 75 : CHECK(access_check_fail_thrown);
23443 75 : CHECK(catch_callback_called);
23444 :
23445 75 : access_check_fail_thrown = false;
23446 75 : catch_callback_called = false;
23447 : CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
23448 75 : CHECK(!access_check_fail_thrown);
23449 75 : CHECK(!catch_callback_called);
23450 75 : }
23451 :
23452 :
23453 28342 : TEST(AccessCheckThrows) {
23454 5 : i::FLAG_allow_natives_syntax = true;
23455 5 : v8::V8::Initialize();
23456 5 : v8::Isolate* isolate = CcTest::isolate();
23457 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
23458 5 : v8::HandleScope scope(isolate);
23459 :
23460 : // Create an ObjectTemplate for global objects and install access
23461 : // check callbacks that will block access.
23462 : v8::Local<v8::ObjectTemplate> global_template =
23463 5 : v8::ObjectTemplate::New(isolate);
23464 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
23465 :
23466 : // Create a context and set an x property on it's global object.
23467 10 : LocalContext context0(nullptr, global_template);
23468 5 : v8::Local<v8::Object> global0 = context0->Global();
23469 15 : CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
23470 :
23471 : // Create a context with a different security token so that the
23472 : // failed access check callback will be called on each access.
23473 10 : LocalContext context1(nullptr, global_template);
23474 25 : CHECK(context1->Global()
23475 : ->Set(context1.local(), v8_str("other"), global0)
23476 : .FromJust());
23477 :
23478 : v8::Local<v8::FunctionTemplate> catcher_fun =
23479 5 : v8::FunctionTemplate::New(isolate, CatcherCallback);
23480 35 : CHECK(context1->Global()
23481 : ->Set(context1.local(), v8_str("catcher"),
23482 : catcher_fun->GetFunction(context1.local()).ToLocalChecked())
23483 : .FromJust());
23484 :
23485 : v8::Local<v8::FunctionTemplate> has_own_property_fun =
23486 5 : v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
23487 35 : CHECK(context1->Global()
23488 : ->Set(context1.local(), v8_str("has_own_property"),
23489 : has_own_property_fun->GetFunction(context1.local())
23490 : .ToLocalChecked())
23491 : .FromJust());
23492 :
23493 : {
23494 5 : v8::TryCatch try_catch(isolate);
23495 5 : access_check_fail_thrown = false;
23496 : CompileRun("other.x;");
23497 5 : CHECK(access_check_fail_thrown);
23498 5 : CHECK(try_catch.HasCaught());
23499 : }
23500 :
23501 5 : CheckCorrectThrow("other.x");
23502 5 : CheckCorrectThrow("other[1]");
23503 5 : CheckCorrectThrow("JSON.stringify(other)");
23504 5 : CheckCorrectThrow("has_own_property(other, 'x')");
23505 5 : CheckCorrectThrow("%GetProperty(other, 'x')");
23506 5 : CheckCorrectThrow("%SetKeyedProperty(other, 'x', 'foo', 0)");
23507 5 : CheckCorrectThrow("%SetNamedProperty(other, 'y', 'foo', 1)");
23508 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kSloppy) == 0);
23509 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kStrict) == 1);
23510 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); // 0 == SLOPPY
23511 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 1)"); // 1 == STRICT
23512 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
23513 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 1)");
23514 5 : CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
23515 5 : CheckCorrectThrow("%HasProperty(other, 'x')");
23516 5 : CheckCorrectThrow("Object.prototype.propertyIsEnumerable(other, 'x')");
23517 : // PROPERTY_ATTRIBUTES_NONE = 0
23518 : CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
23519 5 : "other, 'x', null, null, 1)");
23520 :
23521 : // Reset the failed access check callback so it does not influence
23522 : // the other tests.
23523 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
23524 5 : }
23525 :
23526 : class RequestInterruptTestBase {
23527 : public:
23528 35 : RequestInterruptTestBase()
23529 : : env_(),
23530 35 : isolate_(env_->GetIsolate()),
23531 : sem_(0),
23532 : warmup_(20000),
23533 105 : should_continue_(true) {
23534 35 : }
23535 :
23536 35 : virtual ~RequestInterruptTestBase() = default;
23537 :
23538 : virtual void StartInterruptThread() = 0;
23539 :
23540 : virtual void TestBody() = 0;
23541 :
23542 70 : void RunTest() {
23543 35 : StartInterruptThread();
23544 :
23545 35 : v8::HandleScope handle_scope(isolate_);
23546 :
23547 35 : TestBody();
23548 :
23549 : // Verify we arrived here because interruptor was called
23550 : // not due to a bug causing us to exit the loop too early.
23551 35 : CHECK(!should_continue());
23552 35 : }
23553 :
23554 : void WakeUpInterruptor() {
23555 35 : sem_.Signal();
23556 : }
23557 :
23558 : bool should_continue() const { return should_continue_; }
23559 :
23560 867215 : bool ShouldContinue() {
23561 867215 : if (warmup_ > 0) {
23562 600000 : if (--warmup_ == 0) {
23563 : WakeUpInterruptor();
23564 : }
23565 : }
23566 :
23567 867215 : return should_continue_;
23568 : }
23569 :
23570 759555 : static void ShouldContinueCallback(
23571 1519110 : const v8::FunctionCallbackInfo<Value>& info) {
23572 : RequestInterruptTestBase* test =
23573 : reinterpret_cast<RequestInterruptTestBase*>(
23574 759555 : info.Data().As<v8::External>()->Value());
23575 759555 : info.GetReturnValue().Set(test->ShouldContinue());
23576 759555 : }
23577 :
23578 : LocalContext env_;
23579 : v8::Isolate* isolate_;
23580 : v8::base::Semaphore sem_;
23581 : int warmup_;
23582 : bool should_continue_;
23583 : };
23584 :
23585 :
23586 60 : class RequestInterruptTestBaseWithSimpleInterrupt
23587 : : public RequestInterruptTestBase {
23588 : public:
23589 60 : RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
23590 :
23591 30 : void StartInterruptThread() override { i_thread.Start(); }
23592 :
23593 : private:
23594 30 : class InterruptThread : public v8::base::Thread {
23595 : public:
23596 : explicit InterruptThread(RequestInterruptTestBase* test)
23597 30 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23598 :
23599 30 : void Run() override {
23600 30 : test_->sem_.Wait();
23601 30 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23602 30 : }
23603 :
23604 30 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23605 : reinterpret_cast<RequestInterruptTestBase*>(data)->
23606 30 : should_continue_ = false;
23607 30 : }
23608 :
23609 : private:
23610 : RequestInterruptTestBase* test_;
23611 : };
23612 :
23613 : InterruptThread i_thread;
23614 : };
23615 :
23616 :
23617 10 : class RequestInterruptTestWithFunctionCall
23618 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23619 : public:
23620 5 : void TestBody() override {
23621 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23622 15 : v8::External::New(isolate_, this))
23623 5 : .ToLocalChecked();
23624 25 : CHECK(env_->Global()
23625 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23626 : .FromJust());
23627 :
23628 : CompileRun("while (ShouldContinue()) { }");
23629 5 : }
23630 : };
23631 :
23632 :
23633 10 : class RequestInterruptTestWithMethodCall
23634 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23635 : public:
23636 5 : void TestBody() override {
23637 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23638 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23639 : proto->Set(v8_str("shouldContinue"),
23640 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23641 20 : v8::External::New(isolate_, this)));
23642 30 : CHECK(env_->Global()
23643 : ->Set(env_.local(), v8_str("Klass"),
23644 : t->GetFunction(env_.local()).ToLocalChecked())
23645 : .FromJust());
23646 :
23647 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23648 5 : }
23649 : };
23650 :
23651 :
23652 10 : class RequestInterruptTestWithAccessor
23653 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23654 : public:
23655 5 : void TestBody() override {
23656 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23657 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23658 : proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23659 15 : isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23660 30 : CHECK(env_->Global()
23661 : ->Set(env_.local(), v8_str("Klass"),
23662 : t->GetFunction(env_.local()).ToLocalChecked())
23663 : .FromJust());
23664 :
23665 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23666 5 : }
23667 : };
23668 :
23669 :
23670 10 : class RequestInterruptTestWithNativeAccessor
23671 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23672 : public:
23673 5 : void TestBody() override {
23674 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23675 10 : t->InstanceTemplate()->SetNativeDataProperty(
23676 : v8_str("shouldContinue"), &ShouldContinueNativeGetter, nullptr,
23677 20 : v8::External::New(isolate_, this));
23678 30 : CHECK(env_->Global()
23679 : ->Set(env_.local(), v8_str("Klass"),
23680 : t->GetFunction(env_.local()).ToLocalChecked())
23681 : .FromJust());
23682 :
23683 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23684 5 : }
23685 :
23686 : private:
23687 107660 : static void ShouldContinueNativeGetter(
23688 : Local<String> property,
23689 : const v8::PropertyCallbackInfo<v8::Value>& info) {
23690 : RequestInterruptTestBase* test =
23691 : reinterpret_cast<RequestInterruptTestBase*>(
23692 107660 : info.Data().As<v8::External>()->Value());
23693 107660 : info.GetReturnValue().Set(test->ShouldContinue());
23694 107660 : }
23695 : };
23696 :
23697 :
23698 10 : class RequestInterruptTestWithMethodCallAndInterceptor
23699 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23700 : public:
23701 5 : void TestBody() override {
23702 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23703 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23704 : proto->Set(v8_str("shouldContinue"),
23705 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23706 20 : v8::External::New(isolate_, this)));
23707 5 : v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23708 : instance_template->SetHandler(
23709 5 : v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23710 :
23711 30 : CHECK(env_->Global()
23712 : ->Set(env_.local(), v8_str("Klass"),
23713 : t->GetFunction(env_.local()).ToLocalChecked())
23714 : .FromJust());
23715 :
23716 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23717 5 : }
23718 :
23719 : private:
23720 100031 : static void EmptyInterceptor(
23721 100031 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23722 : };
23723 :
23724 :
23725 10 : class RequestInterruptTestWithMathAbs
23726 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23727 : public:
23728 5 : void TestBody() override {
23729 : env_->Global()
23730 : ->Set(env_.local(), v8_str("WakeUpInterruptor"),
23731 : Function::New(env_.local(), WakeUpInterruptorCallback,
23732 15 : v8::External::New(isolate_, this))
23733 25 : .ToLocalChecked())
23734 10 : .FromJust();
23735 :
23736 : env_->Global()
23737 : ->Set(env_.local(), v8_str("ShouldContinue"),
23738 : Function::New(env_.local(), ShouldContinueCallback,
23739 15 : v8::External::New(isolate_, this))
23740 25 : .ToLocalChecked())
23741 10 : .FromJust();
23742 :
23743 5 : i::FLAG_allow_natives_syntax = true;
23744 : CompileRun("function loopish(o) {"
23745 : " var pre = 10;"
23746 : " while (o.abs(1) > 0) {"
23747 : " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23748 : " if (pre > 0) {"
23749 : " if (--pre === 0) WakeUpInterruptor(o === Math);"
23750 : " }"
23751 : " }"
23752 : "}"
23753 : "var i = 50;"
23754 : "var obj = {abs: function () { return i-- }, x: null};"
23755 : "delete obj.x;"
23756 : "loopish(obj);"
23757 : "%OptimizeFunctionOnNextCall(loopish);"
23758 : "loopish(Math);");
23759 :
23760 5 : i::FLAG_allow_natives_syntax = false;
23761 5 : }
23762 :
23763 : private:
23764 10 : static void WakeUpInterruptorCallback(
23765 15 : const v8::FunctionCallbackInfo<Value>& info) {
23766 10 : if (!info[0]->BooleanValue(info.GetIsolate())) {
23767 10 : return;
23768 : }
23769 :
23770 : RequestInterruptTestBase* test =
23771 : reinterpret_cast<RequestInterruptTestBase*>(
23772 5 : info.Data().As<v8::External>()->Value());
23773 : test->WakeUpInterruptor();
23774 : }
23775 :
23776 56310 : static void ShouldContinueCallback(
23777 112620 : const v8::FunctionCallbackInfo<Value>& info) {
23778 56310 : RequestInterruptTestBase* test =
23779 : reinterpret_cast<RequestInterruptTestBase*>(
23780 56310 : info.Data().As<v8::External>()->Value());
23781 : info.GetReturnValue().Set(test->should_continue());
23782 56310 : }
23783 : };
23784 :
23785 :
23786 28342 : TEST(RequestInterruptTestWithFunctionCall) {
23787 15 : RequestInterruptTestWithFunctionCall().RunTest();
23788 5 : }
23789 :
23790 :
23791 28342 : TEST(RequestInterruptTestWithMethodCall) {
23792 15 : RequestInterruptTestWithMethodCall().RunTest();
23793 5 : }
23794 :
23795 :
23796 28342 : TEST(RequestInterruptTestWithAccessor) {
23797 15 : RequestInterruptTestWithAccessor().RunTest();
23798 5 : }
23799 :
23800 :
23801 28342 : TEST(RequestInterruptTestWithNativeAccessor) {
23802 15 : RequestInterruptTestWithNativeAccessor().RunTest();
23803 5 : }
23804 :
23805 :
23806 28342 : TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23807 15 : RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23808 5 : }
23809 :
23810 :
23811 28342 : TEST(RequestInterruptTestWithMathAbs) {
23812 15 : RequestInterruptTestWithMathAbs().RunTest();
23813 5 : }
23814 :
23815 :
23816 10 : class RequestMultipleInterrupts : public RequestInterruptTestBase {
23817 : public:
23818 10 : RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23819 :
23820 5 : void StartInterruptThread() override { i_thread.Start(); }
23821 :
23822 5 : void TestBody() override {
23823 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23824 15 : v8::External::New(isolate_, this))
23825 5 : .ToLocalChecked();
23826 25 : CHECK(env_->Global()
23827 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23828 : .FromJust());
23829 :
23830 : CompileRun("while (ShouldContinue()) { }");
23831 5 : }
23832 :
23833 : private:
23834 5 : class InterruptThread : public v8::base::Thread {
23835 : public:
23836 : enum { NUM_INTERRUPTS = 10 };
23837 : explicit InterruptThread(RequestMultipleInterrupts* test)
23838 5 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23839 :
23840 5 : void Run() override {
23841 5 : test_->sem_.Wait();
23842 55 : for (int i = 0; i < NUM_INTERRUPTS; i++) {
23843 50 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23844 : }
23845 5 : }
23846 :
23847 50 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23848 : RequestMultipleInterrupts* test =
23849 : reinterpret_cast<RequestMultipleInterrupts*>(data);
23850 50 : test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23851 50 : }
23852 :
23853 : private:
23854 : RequestMultipleInterrupts* test_;
23855 : };
23856 :
23857 : InterruptThread i_thread;
23858 : int counter_;
23859 : };
23860 :
23861 :
23862 28342 : TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23863 :
23864 :
23865 : static bool interrupt_was_called = false;
23866 :
23867 :
23868 5 : void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
23869 5 : interrupt_was_called = true;
23870 5 : }
23871 :
23872 :
23873 28342 : TEST(RequestInterruptSmallScripts) {
23874 5 : LocalContext env;
23875 5 : v8::Isolate* isolate = CcTest::isolate();
23876 10 : v8::HandleScope scope(isolate);
23877 :
23878 5 : interrupt_was_called = false;
23879 5 : isolate->RequestInterrupt(&SmallScriptsInterruptCallback, nullptr);
23880 : CompileRun("(function(x){return x;})(1);");
23881 10 : CHECK(interrupt_was_called);
23882 5 : }
23883 :
23884 :
23885 : static Local<Value> function_new_expected_env;
23886 24 : static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23887 36 : CHECK(
23888 : function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
23889 : info.Data())
23890 : .FromJust());
23891 : info.GetReturnValue().Set(17);
23892 12 : }
23893 :
23894 :
23895 28343 : THREADED_TEST(FunctionNew) {
23896 6 : LocalContext env;
23897 6 : v8::Isolate* isolate = env->GetIsolate();
23898 12 : v8::HandleScope scope(isolate);
23899 6 : Local<Object> data = v8::Object::New(isolate);
23900 6 : function_new_expected_env = data;
23901 : Local<Function> func =
23902 12 : Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
23903 30 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
23904 6 : Local<Value> result = CompileRun("func();");
23905 18 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
23906 : // Serial number should be invalid => should not be cached.
23907 : auto serial_number =
23908 : i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
23909 18 : ->shared()
23910 12 : ->get_api_func_data()
23911 12 : ->serial_number())
23912 : ->value();
23913 6 : CHECK_EQ(i::FunctionTemplateInfo::kInvalidSerialNumber, serial_number);
23914 :
23915 : // Verify that each Function::New creates a new function instance
23916 6 : Local<Object> data2 = v8::Object::New(isolate);
23917 6 : function_new_expected_env = data2;
23918 : Local<Function> func2 =
23919 12 : Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
23920 6 : CHECK(!func2->IsNull());
23921 12 : CHECK(!func->Equals(env.local(), func2).FromJust());
23922 30 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
23923 6 : Local<Value> result2 = CompileRun("func2();");
23924 24 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
23925 6 : }
23926 :
23927 : namespace {
23928 :
23929 : void Verify(v8::Isolate* isolate, Local<v8::Object> obj) {
23930 : #if VERIFY_HEAP
23931 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23932 : i::Handle<i::JSReceiver> i_obj = v8::Utils::OpenHandle(*obj);
23933 : i_obj->ObjectVerify(i_isolate);
23934 : #endif
23935 : }
23936 :
23937 : } // namespace
23938 :
23939 28343 : THREADED_TEST(ObjectNew) {
23940 6 : LocalContext env;
23941 6 : v8::Isolate* isolate = env->GetIsolate();
23942 12 : v8::HandleScope scope(isolate);
23943 : {
23944 : // Verify that Object::New(null) produces an object with a null
23945 : // [[Prototype]].
23946 : Local<v8::Object> obj =
23947 6 : v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0);
23948 12 : CHECK(obj->GetPrototype()->IsNull());
23949 : Verify(isolate, obj);
23950 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23951 6 : CHECK_EQ(0, keys->Length());
23952 : }
23953 : {
23954 : // Verify that Object::New(proto) produces an object with
23955 : // proto as it's [[Prototype]].
23956 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23957 : Local<v8::Object> obj =
23958 6 : v8::Object::New(isolate, proto, nullptr, nullptr, 0);
23959 : Verify(isolate, obj);
23960 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23961 : }
23962 : {
23963 : // Verify that the properties are installed correctly.
23964 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("b"), v8_str("c")};
23965 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23966 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23967 6 : values, arraysize(values));
23968 : Verify(isolate, obj);
23969 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23970 6 : CHECK_EQ(arraysize(names), keys->Length());
23971 18 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23972 54 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23973 54 : CHECK(values[i]->SameValue(
23974 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23975 : }
23976 : }
23977 : {
23978 : // Same as above, but with non-null prototype.
23979 6 : Local<v8::Object> proto = v8::Object::New(isolate);
23980 18 : Local<v8::Name> names[3] = {v8_str("x"), v8_str("y"), v8_str("z")};
23981 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23982 : Local<v8::Object> obj =
23983 6 : v8::Object::New(isolate, proto, names, values, arraysize(values));
23984 12 : CHECK(obj->GetPrototype()->SameValue(proto));
23985 : Verify(isolate, obj);
23986 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23987 6 : CHECK_EQ(arraysize(names), keys->Length());
23988 18 : for (uint32_t i = 0; i < arraysize(names); ++i) {
23989 54 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23990 54 : CHECK(values[i]->SameValue(
23991 : obj->Get(env.local(), names[i]).ToLocalChecked()));
23992 : }
23993 : }
23994 : {
23995 : // This has to work with duplicate names too.
23996 18 : Local<v8::Name> names[3] = {v8_str("a"), v8_str("a"), v8_str("a")};
23997 6 : Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23998 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23999 6 : values, arraysize(values));
24000 : Verify(isolate, obj);
24001 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
24002 6 : CHECK_EQ(1, keys->Length());
24003 18 : CHECK(v8_str("a")->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
24004 24 : CHECK(v8_num(3)->SameValue(
24005 : obj->Get(env.local(), v8_str("a")).ToLocalChecked()));
24006 : }
24007 : {
24008 : // This has to work with array indices too.
24009 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("1")};
24010 6 : Local<v8::Value> values[2] = {v8_num(0), v8_num(1)};
24011 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
24012 6 : values, arraysize(values));
24013 : Verify(isolate, obj);
24014 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
24015 6 : CHECK_EQ(arraysize(names), keys->Length());
24016 12 : for (uint32_t i = 0; i < arraysize(names); ++i) {
24017 36 : CHECK(v8::Number::New(isolate, i)
24018 : ->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
24019 36 : CHECK(values[i]->SameValue(obj->Get(env.local(), i).ToLocalChecked()));
24020 : }
24021 : }
24022 : {
24023 : // This has to work with mixed array indices / property names too.
24024 12 : Local<v8::Name> names[2] = {v8_str("0"), v8_str("x")};
24025 6 : Local<v8::Value> values[2] = {v8_num(42), v8_num(24)};
24026 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
24027 6 : values, arraysize(values));
24028 : Verify(isolate, obj);
24029 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
24030 6 : CHECK_EQ(arraysize(names), keys->Length());
24031 : // 0 -> 42
24032 18 : CHECK(v8_num(0)->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
24033 12 : CHECK(
24034 : values[0]->SameValue(obj->Get(env.local(), names[0]).ToLocalChecked()));
24035 : // "x" -> 24
24036 18 : CHECK(v8_str("x")->SameValue(keys->Get(env.local(), 1).ToLocalChecked()));
24037 12 : CHECK(
24038 : values[1]->SameValue(obj->Get(env.local(), names[1]).ToLocalChecked()));
24039 : }
24040 : {
24041 : // Verify that this also works for a couple thousand properties.
24042 : size_t const kLength = 10 * 1024;
24043 61446 : Local<v8::Name> names[kLength];
24044 61440 : Local<v8::Value> values[kLength];
24045 61440 : for (size_t i = 0; i < arraysize(names); ++i) {
24046 61440 : std::ostringstream ost;
24047 61440 : ost << "a" << i;
24048 122880 : names[i] = v8_str(ost.str().c_str());
24049 61440 : values[i] = v8_num(static_cast<double>(i));
24050 61440 : }
24051 : Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
24052 6 : values, arraysize(names));
24053 : Verify(isolate, obj);
24054 6 : Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
24055 6 : CHECK_EQ(arraysize(names), keys->Length());
24056 61440 : for (uint32_t i = 0; i < arraysize(names); ++i) {
24057 184320 : CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
24058 184320 : CHECK(values[i]->SameValue(
24059 : obj->Get(env.local(), names[i]).ToLocalChecked()));
24060 : }
24061 6 : }
24062 6 : }
24063 :
24064 28342 : TEST(EscapableHandleScope) {
24065 5 : HandleScope outer_scope(CcTest::isolate());
24066 10 : LocalContext context;
24067 : const int runs = 10;
24068 55 : Local<String> values[runs];
24069 50 : for (int i = 0; i < runs; i++) {
24070 50 : v8::EscapableHandleScope inner_scope(CcTest::isolate());
24071 : Local<String> value;
24072 50 : if (i != 0) value = v8_str("escape value");
24073 50 : if (i < runs / 2) {
24074 25 : values[i] = inner_scope.Escape(value);
24075 : } else {
24076 : values[i] = inner_scope.EscapeMaybe(v8::MaybeLocal<String>(value))
24077 25 : .ToLocalChecked();
24078 : }
24079 : }
24080 50 : for (int i = 0; i < runs; i++) {
24081 : Local<String> expected;
24082 50 : if (i != 0) {
24083 135 : CHECK(v8_str("escape value")
24084 : ->Equals(context.local(), values[i])
24085 : .FromJust());
24086 : } else {
24087 10 : CHECK(values[i].IsEmpty());
24088 : }
24089 5 : }
24090 5 : }
24091 :
24092 :
24093 20 : static void SetterWhichExpectsThisAndHolderToDiffer(
24094 : Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
24095 20 : CHECK(info.Holder() != info.This());
24096 20 : }
24097 :
24098 :
24099 28342 : TEST(Regress239669) {
24100 5 : LocalContext context;
24101 5 : v8::Isolate* isolate = context->GetIsolate();
24102 10 : v8::HandleScope scope(isolate);
24103 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
24104 : templ->SetAccessor(v8_str("x"), nullptr,
24105 5 : SetterWhichExpectsThisAndHolderToDiffer);
24106 30 : CHECK(context->Global()
24107 : ->Set(context.local(), v8_str("P"),
24108 : templ->NewInstance(context.local()).ToLocalChecked())
24109 : .FromJust());
24110 : CompileRun(
24111 : "function C1() {"
24112 : " this.x = 23;"
24113 : "};"
24114 : "C1.prototype = P;"
24115 : "for (var i = 0; i < 4; i++ ) {"
24116 : " new C1();"
24117 5 : "}");
24118 5 : }
24119 :
24120 :
24121 : class ApiCallOptimizationChecker {
24122 : private:
24123 : static Local<Object> data;
24124 : static Local<Object> receiver;
24125 : static Local<Object> holder;
24126 : static Local<Object> callee;
24127 : static int count;
24128 :
24129 270 : static void OptimizationCallback(
24130 1350 : const v8::FunctionCallbackInfo<v8::Value>& info) {
24131 270 : CHECK(data == info.Data());
24132 270 : CHECK(receiver == info.This());
24133 270 : if (info.Length() == 1) {
24134 270 : CHECK(v8_num(1)
24135 : ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
24136 : .FromJust());
24137 : }
24138 270 : CHECK(holder == info.Holder());
24139 270 : count++;
24140 270 : info.GetReturnValue().Set(v8_str("returned"));
24141 270 : }
24142 :
24143 : public:
24144 : enum SignatureType {
24145 : kNoSignature,
24146 : kSignatureOnReceiver,
24147 : kSignatureOnPrototype
24148 : };
24149 :
24150 5 : void RunAll() {
24151 : SignatureType signature_types[] =
24152 5 : {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
24153 20 : for (unsigned i = 0; i < arraysize(signature_types); i++) {
24154 15 : SignatureType signature_type = signature_types[i];
24155 45 : for (int j = 0; j < 2; j++) {
24156 30 : bool global = j == 0;
24157 : int key = signature_type +
24158 30 : arraysize(signature_types) * (global ? 1 : 0);
24159 30 : Run(signature_type, global, key);
24160 : }
24161 : }
24162 5 : }
24163 :
24164 30 : void Run(SignatureType signature_type, bool global, int key) {
24165 30 : v8::Isolate* isolate = CcTest::isolate();
24166 30 : v8::HandleScope scope(isolate);
24167 : // Build a template for signature checks.
24168 : Local<v8::ObjectTemplate> signature_template;
24169 : Local<v8::Signature> signature;
24170 : {
24171 : Local<v8::FunctionTemplate> parent_template =
24172 30 : FunctionTemplate::New(isolate);
24173 30 : parent_template->SetHiddenPrototype(true);
24174 : Local<v8::FunctionTemplate> function_template
24175 30 : = FunctionTemplate::New(isolate);
24176 30 : function_template->Inherit(parent_template);
24177 30 : switch (signature_type) {
24178 : case kNoSignature:
24179 : break;
24180 : case kSignatureOnReceiver:
24181 10 : signature = v8::Signature::New(isolate, function_template);
24182 10 : break;
24183 : case kSignatureOnPrototype:
24184 10 : signature = v8::Signature::New(isolate, parent_template);
24185 10 : break;
24186 : }
24187 30 : signature_template = function_template->InstanceTemplate();
24188 : }
24189 : // Global object must pass checks.
24190 : Local<v8::Context> context =
24191 30 : v8::Context::New(isolate, nullptr, signature_template);
24192 : v8::Context::Scope context_scope(context);
24193 : // Install regular object that can pass signature checks.
24194 : Local<Object> function_receiver =
24195 30 : signature_template->NewInstance(context).ToLocalChecked();
24196 120 : CHECK(context->Global()
24197 : ->Set(context, v8_str("function_receiver"), function_receiver)
24198 : .FromJust());
24199 : // Get the holder objects.
24200 : Local<Object> inner_global =
24201 60 : Local<Object>::Cast(context->Global()->GetPrototype());
24202 : // Install functions on hidden prototype object if there is one.
24203 30 : data = Object::New(isolate);
24204 : Local<FunctionTemplate> function_template = FunctionTemplate::New(
24205 30 : isolate, OptimizationCallback, data, signature);
24206 : Local<Function> function =
24207 30 : function_template->GetFunction(context).ToLocalChecked();
24208 : Local<Object> global_holder = inner_global;
24209 : Local<Object> function_holder = function_receiver;
24210 30 : if (signature_type == kSignatureOnPrototype) {
24211 10 : function_holder = Local<Object>::Cast(function_holder->GetPrototype());
24212 10 : global_holder = Local<Object>::Cast(global_holder->GetPrototype());
24213 : }
24214 90 : global_holder->Set(context, v8_str("g_f"), function).FromJust();
24215 60 : global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
24216 90 : function_holder->Set(context, v8_str("f"), function).FromJust();
24217 60 : function_holder->SetAccessorProperty(v8_str("acc"), function, function);
24218 : // Initialize expected values.
24219 30 : callee = function;
24220 30 : count = 0;
24221 30 : if (global) {
24222 15 : receiver = context->Global();
24223 15 : holder = inner_global;
24224 : } else {
24225 15 : holder = function_receiver;
24226 : // If not using a signature, add something else to the prototype chain
24227 : // to test the case that holder != receiver
24228 15 : if (signature_type == kNoSignature) {
24229 : receiver = Local<Object>::Cast(CompileRun(
24230 : "var receiver_subclass = {};\n"
24231 : "receiver_subclass.__proto__ = function_receiver;\n"
24232 5 : "receiver_subclass"));
24233 : } else {
24234 : receiver = Local<Object>::Cast(CompileRun(
24235 : "var receiver_subclass = function_receiver;\n"
24236 10 : "receiver_subclass"));
24237 : }
24238 : }
24239 : // With no signature, the holder is not set.
24240 30 : if (signature_type == kNoSignature) holder = receiver;
24241 : // build wrap_function
24242 : i::ScopedVector<char> wrap_function(200);
24243 30 : if (global) {
24244 : i::SNPrintF(
24245 : wrap_function,
24246 : "function wrap_f_%d() { var f = g_f; return f(); }\n"
24247 : "function wrap_get_%d() { return this.g_acc; }\n"
24248 : "function wrap_set_%d() { return this.g_acc = 1; }\n",
24249 15 : key, key, key);
24250 : } else {
24251 : i::SNPrintF(
24252 : wrap_function,
24253 : "function wrap_f_%d() { return receiver_subclass.f(); }\n"
24254 : "function wrap_get_%d() { return receiver_subclass.acc; }\n"
24255 : "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
24256 15 : key, key, key);
24257 : }
24258 : // build source string
24259 : i::ScopedVector<char> source(1000);
24260 : i::SNPrintF(
24261 : source,
24262 : "%s\n" // wrap functions
24263 : "function wrap_f() { return wrap_f_%d(); }\n"
24264 : "function wrap_get() { return wrap_get_%d(); }\n"
24265 : "function wrap_set() { return wrap_set_%d(); }\n"
24266 : "check = function(returned) {\n"
24267 : " if (returned !== 'returned') { throw returned; }\n"
24268 : "}\n"
24269 : "\n"
24270 : "check(wrap_f());\n"
24271 : "check(wrap_f());\n"
24272 : "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
24273 : "check(wrap_f());\n"
24274 : "\n"
24275 : "check(wrap_get());\n"
24276 : "check(wrap_get());\n"
24277 : "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
24278 : "check(wrap_get());\n"
24279 : "\n"
24280 : "check = function(returned) {\n"
24281 : " if (returned !== 1) { throw returned; }\n"
24282 : "}\n"
24283 : "check(wrap_set());\n"
24284 : "check(wrap_set());\n"
24285 : "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
24286 : "check(wrap_set());\n",
24287 30 : wrap_function.start(), key, key, key, key, key, key);
24288 60 : v8::TryCatch try_catch(isolate);
24289 : CompileRun(source.start());
24290 30 : CHECK(!try_catch.HasCaught());
24291 60 : CHECK_EQ(9, count);
24292 30 : }
24293 : };
24294 :
24295 :
24296 : Local<Object> ApiCallOptimizationChecker::data;
24297 : Local<Object> ApiCallOptimizationChecker::receiver;
24298 : Local<Object> ApiCallOptimizationChecker::holder;
24299 : Local<Object> ApiCallOptimizationChecker::callee;
24300 : int ApiCallOptimizationChecker::count = 0;
24301 :
24302 :
24303 28342 : TEST(FunctionCallOptimization) {
24304 5 : i::FLAG_allow_natives_syntax = true;
24305 : ApiCallOptimizationChecker checker;
24306 5 : checker.RunAll();
24307 5 : }
24308 :
24309 :
24310 28342 : TEST(FunctionCallOptimizationMultipleArgs) {
24311 5 : i::FLAG_allow_natives_syntax = true;
24312 5 : LocalContext context;
24313 5 : v8::Isolate* isolate = context->GetIsolate();
24314 10 : v8::HandleScope scope(isolate);
24315 5 : Local<Object> global = context->Global();
24316 : Local<v8::Function> function =
24317 10 : Function::New(context.local(), Returns42).ToLocalChecked();
24318 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24319 : CompileRun(
24320 : "function x_wrap() {\n"
24321 : " for (var i = 0; i < 5; i++) {\n"
24322 : " x(1,2,3);\n"
24323 : " }\n"
24324 : "}\n"
24325 : "x_wrap();\n"
24326 : "%OptimizeFunctionOnNextCall(x_wrap);"
24327 5 : "x_wrap();\n");
24328 5 : }
24329 :
24330 :
24331 50 : static void ReturnsSymbolCallback(
24332 100 : const v8::FunctionCallbackInfo<v8::Value>& info) {
24333 100 : info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
24334 50 : }
24335 :
24336 :
24337 28342 : TEST(ApiCallbackCanReturnSymbols) {
24338 5 : i::FLAG_allow_natives_syntax = true;
24339 5 : LocalContext context;
24340 5 : v8::Isolate* isolate = context->GetIsolate();
24341 10 : v8::HandleScope scope(isolate);
24342 5 : Local<Object> global = context->Global();
24343 : Local<v8::Function> function =
24344 10 : Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
24345 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24346 : CompileRun(
24347 : "function x_wrap() {\n"
24348 : " for (var i = 0; i < 5; i++) {\n"
24349 : " x();\n"
24350 : " }\n"
24351 : "}\n"
24352 : "x_wrap();\n"
24353 : "%OptimizeFunctionOnNextCall(x_wrap);"
24354 5 : "x_wrap();\n");
24355 5 : }
24356 :
24357 :
24358 28342 : TEST(EmptyApiCallback) {
24359 5 : LocalContext context;
24360 5 : auto isolate = context->GetIsolate();
24361 10 : v8::HandleScope scope(isolate);
24362 5 : auto global = context->Global();
24363 5 : auto function = FunctionTemplate::New(isolate)
24364 15 : ->GetFunction(context.local())
24365 5 : .ToLocalChecked();
24366 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24367 :
24368 : auto result = CompileRun("x()");
24369 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24370 :
24371 : result = CompileRun("x(1,2,3)");
24372 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24373 :
24374 : result = CompileRun("x.call(undefined)");
24375 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24376 :
24377 : result = CompileRun("x.call(null)");
24378 10 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24379 :
24380 : result = CompileRun("7 + x.call(3) + 11");
24381 5 : CHECK(result->IsInt32());
24382 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
24383 :
24384 : result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
24385 5 : CHECK(result->IsInt32());
24386 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
24387 :
24388 : result = CompileRun("var y = []; x.call(y)");
24389 5 : CHECK(result->IsArray());
24390 :
24391 : result = CompileRun("x.call(y, 1, 2, 3, 4)");
24392 10 : CHECK(result->IsArray());
24393 5 : }
24394 :
24395 :
24396 28342 : TEST(SimpleSignatureCheck) {
24397 5 : LocalContext context;
24398 5 : auto isolate = context->GetIsolate();
24399 10 : v8::HandleScope scope(isolate);
24400 5 : auto global = context->Global();
24401 5 : auto sig_obj = FunctionTemplate::New(isolate);
24402 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24403 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24404 : global->Set(context.local(), v8_str("sig_obj"),
24405 25 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24406 10 : .FromJust();
24407 : global->Set(context.local(), v8_str("x"),
24408 25 : x->GetFunction(context.local()).ToLocalChecked())
24409 10 : .FromJust();
24410 : CompileRun("var s = new sig_obj();");
24411 : {
24412 5 : TryCatch try_catch(isolate);
24413 : CompileRun("x()");
24414 5 : CHECK(try_catch.HasCaught());
24415 : }
24416 : {
24417 5 : TryCatch try_catch(isolate);
24418 : CompileRun("x.call(1)");
24419 5 : CHECK(try_catch.HasCaught());
24420 : }
24421 : {
24422 5 : TryCatch try_catch(isolate);
24423 : auto result = CompileRun("s.x = x; s.x()");
24424 5 : CHECK(!try_catch.HasCaught());
24425 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24426 : }
24427 : {
24428 5 : TryCatch try_catch(isolate);
24429 : auto result = CompileRun("x.call(s)");
24430 5 : CHECK(!try_catch.HasCaught());
24431 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24432 5 : }
24433 5 : }
24434 :
24435 :
24436 28342 : TEST(ChainSignatureCheck) {
24437 5 : LocalContext context;
24438 5 : auto isolate = context->GetIsolate();
24439 10 : v8::HandleScope scope(isolate);
24440 5 : auto global = context->Global();
24441 5 : auto sig_obj = FunctionTemplate::New(isolate);
24442 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24443 25 : for (int i = 0; i < 4; ++i) {
24444 20 : auto temp = FunctionTemplate::New(isolate);
24445 20 : temp->Inherit(sig_obj);
24446 : sig_obj = temp;
24447 : }
24448 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24449 : global->Set(context.local(), v8_str("sig_obj"),
24450 20 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24451 10 : .FromJust();
24452 : global->Set(context.local(), v8_str("x"),
24453 25 : x->GetFunction(context.local()).ToLocalChecked())
24454 10 : .FromJust();
24455 : CompileRun("var s = new sig_obj();");
24456 : {
24457 5 : TryCatch try_catch(isolate);
24458 : CompileRun("x()");
24459 5 : CHECK(try_catch.HasCaught());
24460 : }
24461 : {
24462 5 : TryCatch try_catch(isolate);
24463 : CompileRun("x.call(1)");
24464 5 : CHECK(try_catch.HasCaught());
24465 : }
24466 : {
24467 5 : TryCatch try_catch(isolate);
24468 : auto result = CompileRun("s.x = x; s.x()");
24469 5 : CHECK(!try_catch.HasCaught());
24470 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24471 : }
24472 : {
24473 5 : TryCatch try_catch(isolate);
24474 : auto result = CompileRun("x.call(s)");
24475 5 : CHECK(!try_catch.HasCaught());
24476 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24477 5 : }
24478 5 : }
24479 :
24480 :
24481 28342 : TEST(PrototypeSignatureCheck) {
24482 5 : LocalContext context;
24483 5 : auto isolate = context->GetIsolate();
24484 10 : v8::HandleScope scope(isolate);
24485 5 : auto global = context->Global();
24486 5 : auto sig_obj = FunctionTemplate::New(isolate);
24487 5 : sig_obj->SetHiddenPrototype(true);
24488 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24489 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24490 : global->Set(context.local(), v8_str("sig_obj"),
24491 20 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24492 10 : .FromJust();
24493 : global->Set(context.local(), v8_str("x"),
24494 25 : x->GetFunction(context.local()).ToLocalChecked())
24495 10 : .FromJust();
24496 : CompileRun("s = {}; s.__proto__ = new sig_obj();");
24497 : {
24498 5 : TryCatch try_catch(isolate);
24499 : CompileRun("x()");
24500 5 : CHECK(try_catch.HasCaught());
24501 : }
24502 : {
24503 5 : TryCatch try_catch(isolate);
24504 : CompileRun("x.call(1)");
24505 5 : CHECK(try_catch.HasCaught());
24506 : }
24507 : {
24508 5 : TryCatch try_catch(isolate);
24509 : auto result = CompileRun("s.x = x; s.x()");
24510 5 : CHECK(!try_catch.HasCaught());
24511 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24512 : }
24513 : {
24514 5 : TryCatch try_catch(isolate);
24515 : auto result = CompileRun("x.call(s)");
24516 5 : CHECK(!try_catch.HasCaught());
24517 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24518 5 : }
24519 5 : }
24520 :
24521 :
24522 : static const char* last_event_message;
24523 : static int last_event_status;
24524 10 : void StoringEventLoggerCallback(const char* message, int status) {
24525 10 : last_event_message = message;
24526 10 : last_event_status = status;
24527 10 : }
24528 :
24529 :
24530 28342 : TEST(EventLogging) {
24531 5 : v8::Isolate* isolate = CcTest::isolate();
24532 5 : isolate->SetEventLogger(StoringEventLoggerCallback);
24533 : v8::internal::HistogramTimer histogramTimer(
24534 : "V8.Test", 0, 10000, v8::internal::HistogramTimerResolution::MILLISECOND,
24535 : 50, reinterpret_cast<v8::internal::Isolate*>(isolate)->counters());
24536 : histogramTimer.Start();
24537 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
24538 5 : CHECK_EQ(0, last_event_status);
24539 : histogramTimer.Stop();
24540 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
24541 5 : CHECK_EQ(1, last_event_status);
24542 5 : }
24543 :
24544 28342 : TEST(PropertyDescriptor) {
24545 5 : LocalContext context;
24546 5 : v8::Isolate* isolate = context->GetIsolate();
24547 10 : v8::HandleScope scope(isolate);
24548 :
24549 : { // empty descriptor
24550 5 : v8::PropertyDescriptor desc;
24551 5 : CHECK(!desc.has_value());
24552 5 : CHECK(!desc.has_set());
24553 5 : CHECK(!desc.has_get());
24554 5 : CHECK(!desc.has_enumerable());
24555 5 : CHECK(!desc.has_configurable());
24556 5 : CHECK(!desc.has_writable());
24557 : }
24558 : {
24559 : // data descriptor
24560 5 : v8::PropertyDescriptor desc(v8_num(42));
24561 5 : desc.set_enumerable(false);
24562 10 : CHECK(desc.value() == v8_num(42));
24563 5 : CHECK(desc.has_value());
24564 5 : CHECK(!desc.has_set());
24565 5 : CHECK(!desc.has_get());
24566 5 : CHECK(desc.has_enumerable());
24567 5 : CHECK(!desc.enumerable());
24568 5 : CHECK(!desc.has_configurable());
24569 5 : CHECK(!desc.has_writable());
24570 : }
24571 : {
24572 : // data descriptor
24573 5 : v8::PropertyDescriptor desc(v8_num(42));
24574 5 : desc.set_configurable(true);
24575 10 : CHECK(desc.value() == v8_num(42));
24576 5 : CHECK(desc.has_value());
24577 5 : CHECK(!desc.has_set());
24578 5 : CHECK(!desc.has_get());
24579 5 : CHECK(desc.has_configurable());
24580 5 : CHECK(desc.configurable());
24581 5 : CHECK(!desc.has_enumerable());
24582 5 : CHECK(!desc.has_writable());
24583 : }
24584 : {
24585 : // data descriptor
24586 5 : v8::PropertyDescriptor desc(v8_num(42));
24587 5 : desc.set_configurable(false);
24588 10 : CHECK(desc.value() == v8_num(42));
24589 5 : CHECK(desc.has_value());
24590 5 : CHECK(!desc.has_set());
24591 5 : CHECK(!desc.has_get());
24592 5 : CHECK(desc.has_configurable());
24593 5 : CHECK(!desc.configurable());
24594 5 : CHECK(!desc.has_enumerable());
24595 5 : CHECK(!desc.has_writable());
24596 : }
24597 : {
24598 : // data descriptor
24599 5 : v8::PropertyDescriptor desc(v8_num(42), false);
24600 10 : CHECK(desc.value() == v8_num(42));
24601 5 : CHECK(desc.has_value());
24602 5 : CHECK(!desc.has_set());
24603 5 : CHECK(!desc.has_get());
24604 5 : CHECK(!desc.has_enumerable());
24605 5 : CHECK(!desc.has_configurable());
24606 5 : CHECK(desc.has_writable());
24607 5 : CHECK(!desc.writable());
24608 : }
24609 : {
24610 : // data descriptor
24611 5 : v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true);
24612 5 : CHECK(!desc.has_value());
24613 5 : CHECK(!desc.has_set());
24614 5 : CHECK(!desc.has_get());
24615 5 : CHECK(!desc.has_enumerable());
24616 5 : CHECK(!desc.has_configurable());
24617 5 : CHECK(desc.has_writable());
24618 5 : CHECK(desc.writable());
24619 : }
24620 : {
24621 : // accessor descriptor
24622 : CompileRun("var set = function() {return 43;};");
24623 :
24624 : v8::Local<v8::Function> set =
24625 : v8::Local<v8::Function>::Cast(context->Global()
24626 20 : ->Get(context.local(), v8_str("set"))
24627 5 : .ToLocalChecked());
24628 5 : v8::PropertyDescriptor desc(v8::Undefined(isolate), set);
24629 5 : desc.set_configurable(false);
24630 5 : CHECK(!desc.has_value());
24631 5 : CHECK(desc.has_get());
24632 10 : CHECK(desc.get() == v8::Undefined(isolate));
24633 5 : CHECK(desc.has_set());
24634 10 : CHECK(desc.set() == set);
24635 5 : CHECK(!desc.has_enumerable());
24636 5 : CHECK(desc.has_configurable());
24637 5 : CHECK(!desc.configurable());
24638 5 : CHECK(!desc.has_writable());
24639 : }
24640 : {
24641 : // accessor descriptor with Proxy
24642 : CompileRun(
24643 : "var set = new Proxy(function() {}, {});"
24644 : "var get = undefined;");
24645 :
24646 : v8::Local<v8::Value> get =
24647 : v8::Local<v8::Value>::Cast(context->Global()
24648 20 : ->Get(context.local(), v8_str("get"))
24649 10 : .ToLocalChecked());
24650 : v8::Local<v8::Function> set =
24651 : v8::Local<v8::Function>::Cast(context->Global()
24652 20 : ->Get(context.local(), v8_str("set"))
24653 5 : .ToLocalChecked());
24654 5 : v8::PropertyDescriptor desc(get, set);
24655 5 : desc.set_configurable(false);
24656 5 : CHECK(!desc.has_value());
24657 10 : CHECK(desc.get() == v8::Undefined(isolate));
24658 5 : CHECK(desc.has_get());
24659 10 : CHECK(desc.set() == set);
24660 5 : CHECK(desc.has_set());
24661 5 : CHECK(!desc.has_enumerable());
24662 5 : CHECK(desc.has_configurable());
24663 5 : CHECK(!desc.configurable());
24664 5 : CHECK(!desc.has_writable());
24665 : }
24666 : {
24667 : // accessor descriptor with empty function handle
24668 : v8::Local<v8::Function> get = v8::Local<v8::Function>();
24669 5 : v8::PropertyDescriptor desc(get, get);
24670 5 : CHECK(!desc.has_value());
24671 5 : CHECK(!desc.has_get());
24672 5 : CHECK(!desc.has_set());
24673 5 : CHECK(!desc.has_enumerable());
24674 5 : CHECK(!desc.has_configurable());
24675 5 : CHECK(!desc.has_writable());
24676 5 : }
24677 5 : }
24678 :
24679 28342 : TEST(Promises) {
24680 5 : LocalContext context;
24681 5 : v8::Isolate* isolate = context->GetIsolate();
24682 10 : v8::HandleScope scope(isolate);
24683 :
24684 : // Creation.
24685 : Local<v8::Promise::Resolver> pr =
24686 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24687 : Local<v8::Promise::Resolver> rr =
24688 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24689 5 : Local<v8::Promise> p = pr->GetPromise();
24690 5 : Local<v8::Promise> r = rr->GetPromise();
24691 :
24692 : // IsPromise predicate.
24693 5 : CHECK(p->IsPromise());
24694 5 : CHECK(r->IsPromise());
24695 5 : Local<Value> o = v8::Object::New(isolate);
24696 5 : CHECK(!o->IsPromise());
24697 :
24698 : // Resolution and rejection.
24699 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24700 5 : CHECK(p->IsPromise());
24701 15 : rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
24702 10 : CHECK(r->IsPromise());
24703 5 : }
24704 :
24705 : // Promise.Then(on_fulfilled)
24706 28342 : TEST(PromiseThen) {
24707 5 : LocalContext context;
24708 5 : v8::Isolate* isolate = context->GetIsolate();
24709 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24710 10 : v8::HandleScope scope(isolate);
24711 5 : Local<Object> global = context->Global();
24712 :
24713 : // Creation.
24714 : Local<v8::Promise::Resolver> pr =
24715 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24716 : Local<v8::Promise::Resolver> qr =
24717 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24718 5 : Local<v8::Promise> p = pr->GetPromise();
24719 5 : Local<v8::Promise> q = qr->GetPromise();
24720 :
24721 5 : CHECK(p->IsPromise());
24722 5 : CHECK(q->IsPromise());
24723 :
24724 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24725 10 : qr->Resolve(context.local(), p).FromJust();
24726 :
24727 : // Chaining non-pending promises.
24728 : CompileRun(
24729 : "var x1 = 0;\n"
24730 : "var x2 = 0;\n"
24731 : "function f1(x) { x1 = x; return x+1 };\n"
24732 : "function f2(x) { x2 = x; return x+1 };\n");
24733 : Local<Function> f1 = Local<Function>::Cast(
24734 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24735 : Local<Function> f2 = Local<Function>::Cast(
24736 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24737 :
24738 : // Then
24739 : CompileRun("x1 = x2 = 0;");
24740 5 : q->Then(context.local(), f1).ToLocalChecked();
24741 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24742 : .ToLocalChecked()
24743 : ->Int32Value(context.local())
24744 : .FromJust());
24745 5 : isolate->RunMicrotasks();
24746 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24747 : .ToLocalChecked()
24748 : ->Int32Value(context.local())
24749 : .FromJust());
24750 :
24751 : // Then
24752 : CompileRun("x1 = x2 = 0;");
24753 5 : pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24754 5 : qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24755 :
24756 10 : qr->Resolve(context.local(), pr).FromJust();
24757 : qr->GetPromise()
24758 10 : ->Then(context.local(), f1)
24759 5 : .ToLocalChecked()
24760 5 : ->Then(context.local(), f2)
24761 5 : .ToLocalChecked();
24762 :
24763 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24764 : .ToLocalChecked()
24765 : ->Int32Value(context.local())
24766 : .FromJust());
24767 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24768 : .ToLocalChecked()
24769 : ->Int32Value(context.local())
24770 : .FromJust());
24771 5 : isolate->RunMicrotasks();
24772 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24773 : .ToLocalChecked()
24774 : ->Int32Value(context.local())
24775 : .FromJust());
24776 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24777 : .ToLocalChecked()
24778 : ->Int32Value(context.local())
24779 : .FromJust());
24780 :
24781 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
24782 :
24783 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24784 : .ToLocalChecked()
24785 : ->Int32Value(context.local())
24786 : .FromJust());
24787 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24788 : .ToLocalChecked()
24789 : ->Int32Value(context.local())
24790 : .FromJust());
24791 5 : isolate->RunMicrotasks();
24792 20 : CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
24793 : .ToLocalChecked()
24794 : ->Int32Value(context.local())
24795 : .FromJust());
24796 20 : CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
24797 : .ToLocalChecked()
24798 : ->Int32Value(context.local())
24799 5 : .FromJust());
24800 5 : }
24801 :
24802 : // Promise.Then(on_fulfilled, on_rejected)
24803 28342 : TEST(PromiseThen2) {
24804 5 : LocalContext context;
24805 5 : v8::Isolate* isolate = context->GetIsolate();
24806 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24807 10 : v8::HandleScope scope(isolate);
24808 5 : Local<Object> global = context->Global();
24809 :
24810 : // Creation.
24811 : Local<v8::Promise::Resolver> pr =
24812 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24813 5 : Local<v8::Promise> p = pr->GetPromise();
24814 :
24815 5 : CHECK(p->IsPromise());
24816 :
24817 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24818 :
24819 : // Chaining non-pending promises.
24820 : CompileRun(
24821 : "var x1 = 0;\n"
24822 : "var x2 = 0;\n"
24823 : "function f1(x) { x1 = x; return x+1 };\n"
24824 : "function f2(x) { x2 = x; return x+1 };\n"
24825 : "function f3(x) { throw x + 100 };\n");
24826 : Local<Function> f1 = Local<Function>::Cast(
24827 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24828 : Local<Function> f2 = Local<Function>::Cast(
24829 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24830 : Local<Function> f3 = Local<Function>::Cast(
24831 15 : global->Get(context.local(), v8_str("f3")).ToLocalChecked());
24832 :
24833 : // Then
24834 : CompileRun("x1 = x2 = 0;");
24835 5 : Local<v8::Promise> a = p->Then(context.local(), f1, f2).ToLocalChecked();
24836 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24837 : .ToLocalChecked()
24838 : ->Int32Value(context.local())
24839 : .FromJust());
24840 5 : isolate->RunMicrotasks();
24841 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24842 : .ToLocalChecked()
24843 : ->Int32Value(context.local())
24844 : .FromJust());
24845 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24846 : .ToLocalChecked()
24847 : ->Int32Value(context.local())
24848 : .FromJust());
24849 :
24850 5 : Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
24851 5 : isolate->RunMicrotasks();
24852 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24853 : .ToLocalChecked()
24854 : ->Int32Value(context.local())
24855 : .FromJust());
24856 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24857 : .ToLocalChecked()
24858 : ->Int32Value(context.local())
24859 : .FromJust());
24860 :
24861 5 : Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
24862 5 : isolate->RunMicrotasks();
24863 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24864 : .ToLocalChecked()
24865 : ->Int32Value(context.local())
24866 : .FromJust());
24867 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24868 : .ToLocalChecked()
24869 : ->Int32Value(context.local())
24870 : .FromJust());
24871 :
24872 5 : v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
24873 5 : isolate->RunMicrotasks();
24874 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24875 : .ToLocalChecked()
24876 : ->Int32Value(context.local())
24877 : .FromJust());
24878 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24879 : .ToLocalChecked()
24880 : ->Int32Value(context.local())
24881 : .FromJust());
24882 :
24883 5 : v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
24884 5 : isolate->RunMicrotasks();
24885 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24886 : .ToLocalChecked()
24887 : ->Int32Value(context.local())
24888 : .FromJust());
24889 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24890 : .ToLocalChecked()
24891 : ->Int32Value(context.local())
24892 : .FromJust());
24893 :
24894 5 : v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
24895 5 : isolate->RunMicrotasks();
24896 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24897 : .ToLocalChecked()
24898 : ->Int32Value(context.local())
24899 : .FromJust());
24900 20 : CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24901 : .ToLocalChecked()
24902 : ->Int32Value(context.local())
24903 : .FromJust());
24904 :
24905 5 : f->Then(context.local(), f1, f2).ToLocalChecked();
24906 5 : isolate->RunMicrotasks();
24907 20 : CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24908 : .ToLocalChecked()
24909 : ->Int32Value(context.local())
24910 : .FromJust());
24911 20 : CHECK_EQ(304, global->Get(context.local(), v8_str("x2"))
24912 : .ToLocalChecked()
24913 : ->Int32Value(context.local())
24914 5 : .FromJust());
24915 5 : }
24916 :
24917 28342 : TEST(PromiseStateAndValue) {
24918 5 : LocalContext context;
24919 5 : v8::Isolate* isolate = context->GetIsolate();
24920 10 : v8::HandleScope scope(isolate);
24921 : v8::Local<v8::Value> result = CompileRun(
24922 : "var resolver;"
24923 : "new Promise((res, rej) => { resolver = res; })");
24924 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24925 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24926 :
24927 : CompileRun("resolver('fulfilled')");
24928 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24929 10 : CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24930 :
24931 : result = CompileRun("Promise.reject('rejected')");
24932 : promise = v8::Local<v8::Promise>::Cast(result);
24933 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24934 15 : CHECK(v8_str("rejected")->SameValue(promise->Result()));
24935 5 : }
24936 :
24937 28342 : TEST(ResolvedPromiseReFulfill) {
24938 5 : LocalContext context;
24939 5 : v8::Isolate* isolate = context->GetIsolate();
24940 10 : v8::HandleScope scope(isolate);
24941 : v8::Local<v8::String> value1 =
24942 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24943 5 : .ToLocalChecked();
24944 : v8::Local<v8::String> value2 =
24945 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24946 5 : .ToLocalChecked();
24947 :
24948 : v8::Local<v8::Promise::Resolver> resolver =
24949 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24950 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24951 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24952 :
24953 10 : resolver->Resolve(context.local(), value1).ToChecked();
24954 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24955 10 : CHECK_EQ(promise->Result(), value1);
24956 :
24957 : // This should be a no-op.
24958 10 : resolver->Resolve(context.local(), value2).ToChecked();
24959 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24960 10 : CHECK_EQ(promise->Result(), value1);
24961 :
24962 : // This should be a no-op.
24963 10 : resolver->Reject(context.local(), value2).ToChecked();
24964 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24965 15 : CHECK_EQ(promise->Result(), value1);
24966 5 : }
24967 :
24968 28342 : TEST(RejectedPromiseReFulfill) {
24969 5 : LocalContext context;
24970 5 : v8::Isolate* isolate = context->GetIsolate();
24971 10 : v8::HandleScope scope(isolate);
24972 : v8::Local<v8::String> value1 =
24973 : v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24974 5 : .ToLocalChecked();
24975 : v8::Local<v8::String> value2 =
24976 : v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24977 5 : .ToLocalChecked();
24978 :
24979 : v8::Local<v8::Promise::Resolver> resolver =
24980 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24981 5 : v8::Local<v8::Promise> promise = resolver->GetPromise();
24982 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24983 :
24984 10 : resolver->Reject(context.local(), value1).ToChecked();
24985 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24986 10 : CHECK_EQ(promise->Result(), value1);
24987 :
24988 : // This should be a no-op.
24989 10 : resolver->Reject(context.local(), value2).ToChecked();
24990 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24991 10 : CHECK_EQ(promise->Result(), value1);
24992 :
24993 : // This should be a no-op.
24994 10 : resolver->Resolve(context.local(), value2).ToChecked();
24995 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24996 15 : CHECK_EQ(promise->Result(), value1);
24997 5 : }
24998 :
24999 28337 : TEST(DisallowJavascriptExecutionScope) {
25000 0 : LocalContext context;
25001 0 : v8::Isolate* isolate = context->GetIsolate();
25002 0 : v8::HandleScope scope(isolate);
25003 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
25004 0 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
25005 0 : CompileRun("2+2");
25006 0 : }
25007 :
25008 28342 : TEST(AllowJavascriptExecutionScope) {
25009 5 : LocalContext context;
25010 5 : v8::Isolate* isolate = context->GetIsolate();
25011 10 : v8::HandleScope scope(isolate);
25012 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
25013 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
25014 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
25015 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
25016 5 : { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
25017 5 : CompileRun("1+1");
25018 5 : }
25019 5 : }
25020 :
25021 28342 : TEST(ThrowOnJavascriptExecution) {
25022 5 : LocalContext context;
25023 5 : v8::Isolate* isolate = context->GetIsolate();
25024 10 : v8::HandleScope scope(isolate);
25025 10 : v8::TryCatch try_catch(isolate);
25026 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
25027 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
25028 : CompileRun("1+1");
25029 10 : CHECK(try_catch.HasCaught());
25030 5 : }
25031 :
25032 : namespace {
25033 :
25034 : class MockPlatform : public TestPlatform {
25035 : public:
25036 10 : MockPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {
25037 : // Now that it's completely constructed, make this the current platform.
25038 5 : i::V8::SetPlatformForTesting(this);
25039 5 : }
25040 10 : ~MockPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
25041 :
25042 : bool dump_without_crashing_called() const {
25043 : return dump_without_crashing_called_;
25044 : }
25045 :
25046 5 : void DumpWithoutCrashing() override { dump_without_crashing_called_ = true; }
25047 :
25048 : private:
25049 : v8::Platform* old_platform_;
25050 : bool dump_without_crashing_called_ = false;
25051 : };
25052 :
25053 : } // namespace
25054 :
25055 28342 : TEST(DumpOnJavascriptExecution) {
25056 5 : MockPlatform platform;
25057 :
25058 10 : LocalContext context;
25059 5 : v8::Isolate* isolate = context->GetIsolate();
25060 10 : v8::HandleScope scope(isolate);
25061 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
25062 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::DUMP_ON_FAILURE);
25063 5 : CHECK(!platform.dump_without_crashing_called());
25064 : CompileRun("1+1");
25065 10 : CHECK(platform.dump_without_crashing_called());
25066 5 : }
25067 :
25068 28342 : TEST(Regress354123) {
25069 5 : LocalContext current;
25070 5 : v8::Isolate* isolate = current->GetIsolate();
25071 10 : v8::HandleScope scope(isolate);
25072 :
25073 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
25074 5 : templ->SetAccessCheckCallback(AccessCounter);
25075 30 : CHECK(current->Global()
25076 : ->Set(current.local(), v8_str("friend"),
25077 : templ->NewInstance(current.local()).ToLocalChecked())
25078 : .FromJust());
25079 :
25080 : // Test access using __proto__ from the prototype chain.
25081 5 : access_count = 0;
25082 : CompileRun("friend.__proto__ = {};");
25083 5 : CHECK_EQ(2, access_count);
25084 : CompileRun("friend.__proto__;");
25085 5 : CHECK_EQ(4, access_count);
25086 :
25087 : // Test access using __proto__ as a hijacked function (A).
25088 5 : access_count = 0;
25089 : CompileRun("var p = Object.prototype;"
25090 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
25091 : "f.call(friend, {});");
25092 5 : CHECK_EQ(1, access_count);
25093 : CompileRun("var p = Object.prototype;"
25094 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
25095 : "f.call(friend);");
25096 5 : CHECK_EQ(2, access_count);
25097 :
25098 : // Test access using __proto__ as a hijacked function (B).
25099 5 : access_count = 0;
25100 : CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
25101 : "f.call(friend, {});");
25102 5 : CHECK_EQ(1, access_count);
25103 : CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
25104 : "f.call(friend);");
25105 5 : CHECK_EQ(2, access_count);
25106 :
25107 : // Test access using Object.setPrototypeOf reflective method.
25108 5 : access_count = 0;
25109 : CompileRun("Object.setPrototypeOf(friend, {});");
25110 5 : CHECK_EQ(1, access_count);
25111 : CompileRun("Object.getPrototypeOf(friend);");
25112 10 : CHECK_EQ(2, access_count);
25113 5 : }
25114 :
25115 :
25116 28342 : TEST(CaptureStackTraceForStackOverflow) {
25117 5 : v8::internal::FLAG_stack_size = 150;
25118 5 : LocalContext current;
25119 5 : v8::Isolate* isolate = current->GetIsolate();
25120 10 : v8::HandleScope scope(isolate);
25121 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
25122 5 : v8::StackTrace::kDetailed);
25123 10 : v8::TryCatch try_catch(isolate);
25124 : CompileRun("(function f(x) { f(x+1); })(0)");
25125 10 : CHECK(try_catch.HasCaught());
25126 5 : }
25127 :
25128 : namespace {
25129 5 : bool ValueEqualsString(v8::Isolate* isolate, Local<Value> lhs,
25130 : const char* rhs) {
25131 5 : CHECK(!lhs.IsEmpty());
25132 5 : CHECK(lhs->IsString());
25133 5 : String::Utf8Value utf8_lhs(isolate, lhs);
25134 5 : return strcmp(rhs, *utf8_lhs) == 0;
25135 : }
25136 : } // namespace
25137 :
25138 28342 : TEST(ScriptNameAndLineNumber) {
25139 5 : LocalContext env;
25140 5 : v8::Isolate* isolate = env->GetIsolate();
25141 10 : v8::HandleScope scope(isolate);
25142 : const char* url = "http://www.foo.com/foo.js";
25143 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
25144 5 : v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
25145 :
25146 : Local<Script> script =
25147 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
25148 10 : CHECK(ValueEqualsString(isolate, script->GetUnboundScript()->GetScriptName(),
25149 : url));
25150 :
25151 10 : int line_number = script->GetUnboundScript()->GetLineNumber(0);
25152 10 : CHECK_EQ(13, line_number);
25153 5 : }
25154 :
25155 28342 : TEST(ScriptPositionInfo) {
25156 5 : LocalContext env;
25157 5 : v8::Isolate* isolate = env->GetIsolate();
25158 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
25159 10 : v8::HandleScope scope(isolate);
25160 : const char* url = "http://www.foo.com/foo.js";
25161 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
25162 : v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
25163 : "var bar;\n"
25164 : "var fisk = foo + bar;\n"),
25165 5 : origin);
25166 : Local<Script> script =
25167 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
25168 :
25169 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
25170 10 : v8::Utils::OpenHandle(*script->GetUnboundScript()));
25171 10 : CHECK(obj->script()->IsScript());
25172 :
25173 10 : i::Handle<i::Script> script1(i::Script::cast(obj->script()), i_isolate);
25174 :
25175 : v8::internal::Script::PositionInfo info;
25176 :
25177 15 : for (int i = 0; i < 2; ++i) {
25178 : // With offset.
25179 :
25180 : // Behave as if 0 was passed if position is negative.
25181 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
25182 10 : CHECK_EQ(13, info.line);
25183 10 : CHECK_EQ(0, info.column);
25184 10 : CHECK_EQ(0, info.line_start);
25185 10 : CHECK_EQ(8, info.line_end);
25186 :
25187 10 : CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
25188 10 : CHECK_EQ(13, info.line);
25189 10 : CHECK_EQ(0, info.column);
25190 10 : CHECK_EQ(0, info.line_start);
25191 10 : CHECK_EQ(8, info.line_end);
25192 :
25193 10 : CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
25194 10 : CHECK_EQ(13, info.line);
25195 10 : CHECK_EQ(8, info.column);
25196 10 : CHECK_EQ(0, info.line_start);
25197 10 : CHECK_EQ(8, info.line_end);
25198 :
25199 10 : CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
25200 10 : CHECK_EQ(14, info.line);
25201 10 : CHECK_EQ(0, info.column);
25202 10 : CHECK_EQ(9, info.line_start);
25203 10 : CHECK_EQ(17, info.line_end);
25204 :
25205 : // Fail when position is larger than script size.
25206 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
25207 :
25208 : // Without offset.
25209 :
25210 : // Behave as if 0 was passed if position is negative.
25211 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
25212 10 : CHECK_EQ(0, info.line);
25213 10 : CHECK_EQ(0, info.column);
25214 10 : CHECK_EQ(0, info.line_start);
25215 10 : CHECK_EQ(8, info.line_end);
25216 :
25217 10 : CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
25218 10 : CHECK_EQ(0, info.line);
25219 10 : CHECK_EQ(0, info.column);
25220 10 : CHECK_EQ(0, info.line_start);
25221 10 : CHECK_EQ(8, info.line_end);
25222 :
25223 10 : CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
25224 10 : CHECK_EQ(0, info.line);
25225 10 : CHECK_EQ(8, info.column);
25226 10 : CHECK_EQ(0, info.line_start);
25227 10 : CHECK_EQ(8, info.line_end);
25228 :
25229 10 : CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
25230 10 : CHECK_EQ(1, info.line);
25231 10 : CHECK_EQ(0, info.column);
25232 10 : CHECK_EQ(9, info.line_start);
25233 10 : CHECK_EQ(17, info.line_end);
25234 :
25235 : // Fail when position is larger than script size.
25236 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
25237 :
25238 10 : i::Script::InitLineEnds(script1);
25239 5 : }
25240 5 : }
25241 :
25242 155 : void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
25243 : const char* expected_source_url,
25244 : const char* expected_source_mapping_url) {
25245 155 : if (expected_source_url != nullptr) {
25246 : v8::String::Utf8Value url(isolate,
25247 70 : script->GetUnboundScript()->GetSourceURL());
25248 35 : CHECK_EQ(0, strcmp(expected_source_url, *url));
25249 : } else {
25250 360 : CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
25251 : }
25252 155 : if (expected_source_mapping_url != nullptr) {
25253 : v8::String::Utf8Value url(
25254 60 : isolate, script->GetUnboundScript()->GetSourceMappingURL());
25255 30 : CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
25256 : } else {
25257 375 : CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
25258 : }
25259 155 : }
25260 :
25261 70 : void SourceURLHelper(v8::Isolate* isolate, const char* source,
25262 : const char* expected_source_url,
25263 : const char* expected_source_mapping_url) {
25264 70 : Local<Script> script = v8_compile(source);
25265 : CheckMagicComments(isolate, script, expected_source_url,
25266 70 : expected_source_mapping_url);
25267 70 : }
25268 :
25269 :
25270 28342 : TEST(ScriptSourceURLAndSourceMappingURL) {
25271 5 : LocalContext env;
25272 5 : v8::Isolate* isolate = env->GetIsolate();
25273 10 : v8::HandleScope scope(isolate);
25274 : SourceURLHelper(isolate,
25275 : "function foo() {}\n"
25276 : "//# sourceURL=bar1.js\n",
25277 5 : "bar1.js", nullptr);
25278 : SourceURLHelper(isolate,
25279 : "function foo() {}\n"
25280 : "//# sourceMappingURL=bar2.js\n",
25281 5 : nullptr, "bar2.js");
25282 :
25283 : // Both sourceURL and sourceMappingURL.
25284 : SourceURLHelper(isolate,
25285 : "function foo() {}\n"
25286 : "//# sourceURL=bar3.js\n"
25287 : "//# sourceMappingURL=bar4.js\n",
25288 5 : "bar3.js", "bar4.js");
25289 :
25290 : // Two source URLs; the first one is ignored.
25291 : SourceURLHelper(isolate,
25292 : "function foo() {}\n"
25293 : "//# sourceURL=ignoreme.js\n"
25294 : "//# sourceURL=bar5.js\n",
25295 5 : "bar5.js", nullptr);
25296 : SourceURLHelper(isolate,
25297 : "function foo() {}\n"
25298 : "//# sourceMappingURL=ignoreme.js\n"
25299 : "//# sourceMappingURL=bar6.js\n",
25300 5 : nullptr, "bar6.js");
25301 :
25302 : // SourceURL or sourceMappingURL in the middle of the script.
25303 : SourceURLHelper(isolate,
25304 : "function foo() {}\n"
25305 : "//# sourceURL=bar7.js\n"
25306 : "function baz() {}\n",
25307 5 : "bar7.js", nullptr);
25308 : SourceURLHelper(isolate,
25309 : "function foo() {}\n"
25310 : "//# sourceMappingURL=bar8.js\n"
25311 : "function baz() {}\n",
25312 5 : nullptr, "bar8.js");
25313 :
25314 : // Too much whitespace.
25315 : SourceURLHelper(isolate,
25316 : "function foo() {}\n"
25317 : "//# sourceURL=bar9.js\n"
25318 : "//# sourceMappingURL=bar10.js\n",
25319 5 : nullptr, nullptr);
25320 : SourceURLHelper(isolate,
25321 : "function foo() {}\n"
25322 : "//# sourceURL =bar11.js\n"
25323 : "//# sourceMappingURL =bar12.js\n",
25324 5 : nullptr, nullptr);
25325 :
25326 : // Disallowed characters in value.
25327 : SourceURLHelper(isolate,
25328 : "function foo() {}\n"
25329 : "//# sourceURL=bar13 .js \n"
25330 : "//# sourceMappingURL=bar14 .js \n",
25331 5 : nullptr, nullptr);
25332 : SourceURLHelper(isolate,
25333 : "function foo() {}\n"
25334 : "//# sourceURL=bar15\t.js \n"
25335 : "//# sourceMappingURL=bar16\t.js \n",
25336 5 : nullptr, nullptr);
25337 : SourceURLHelper(isolate,
25338 : "function foo() {}\n"
25339 : "//# sourceURL=bar17'.js \n"
25340 : "//# sourceMappingURL=bar18'.js \n",
25341 5 : nullptr, nullptr);
25342 : SourceURLHelper(isolate,
25343 : "function foo() {}\n"
25344 : "//# sourceURL=bar19\".js \n"
25345 : "//# sourceMappingURL=bar20\".js \n",
25346 5 : nullptr, nullptr);
25347 :
25348 : // Not too much whitespace.
25349 : SourceURLHelper(isolate,
25350 : "function foo() {}\n"
25351 : "//# sourceURL= bar21.js \n"
25352 : "//# sourceMappingURL= bar22.js \n",
25353 10 : "bar21.js", "bar22.js");
25354 5 : }
25355 :
25356 :
25357 28342 : TEST(GetOwnPropertyDescriptor) {
25358 5 : LocalContext env;
25359 5 : v8::Isolate* isolate = env->GetIsolate();
25360 10 : v8::HandleScope scope(isolate);
25361 : CompileRun(
25362 : "var x = { value : 13};"
25363 : "Object.defineProperty(x, 'p0', {value : 12});"
25364 : "Object.defineProperty(x, Symbol.toStringTag, {value: 'foo'});"
25365 : "Object.defineProperty(x, 'p1', {"
25366 : " set : function(value) { this.value = value; },"
25367 : " get : function() { return this.value; },"
25368 : "});");
25369 : Local<Object> x = Local<Object>::Cast(
25370 25 : env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
25371 : Local<Value> desc =
25372 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
25373 5 : .ToLocalChecked();
25374 5 : CHECK(desc->IsUndefined());
25375 : desc =
25376 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
25377 25 : CHECK(v8_num(12)
25378 : ->Equals(env.local(), Local<Object>::Cast(desc)
25379 : ->Get(env.local(), v8_str("value"))
25380 : .ToLocalChecked())
25381 : .FromJust());
25382 : desc =
25383 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
25384 : Local<Function> set =
25385 : Local<Function>::Cast(Local<Object>::Cast(desc)
25386 15 : ->Get(env.local(), v8_str("set"))
25387 5 : .ToLocalChecked());
25388 : Local<Function> get =
25389 : Local<Function>::Cast(Local<Object>::Cast(desc)
25390 15 : ->Get(env.local(), v8_str("get"))
25391 5 : .ToLocalChecked());
25392 20 : CHECK(v8_num(13)
25393 : ->Equals(env.local(),
25394 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
25395 : .FromJust());
25396 5 : Local<Value> args[] = {v8_num(14)};
25397 10 : set->Call(env.local(), x, 1, args).ToLocalChecked();
25398 20 : CHECK(v8_num(14)
25399 : ->Equals(env.local(),
25400 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
25401 : .FromJust());
25402 : desc =
25403 15 : x->GetOwnPropertyDescriptor(env.local(), Symbol::GetToStringTag(isolate))
25404 5 : .ToLocalChecked();
25405 25 : CHECK(v8_str("foo")
25406 : ->Equals(env.local(), Local<Object>::Cast(desc)
25407 : ->Get(env.local(), v8_str("value"))
25408 : .ToLocalChecked())
25409 5 : .FromJust());
25410 5 : }
25411 :
25412 :
25413 28342 : TEST(Regress411877) {
25414 5 : v8::Isolate* isolate = CcTest::isolate();
25415 5 : v8::HandleScope handle_scope(isolate);
25416 : v8::Local<v8::ObjectTemplate> object_template =
25417 5 : v8::ObjectTemplate::New(isolate);
25418 5 : object_template->SetAccessCheckCallback(AccessCounter);
25419 :
25420 5 : v8::Local<Context> context = Context::New(isolate);
25421 : v8::Context::Scope context_scope(context);
25422 :
25423 25 : CHECK(context->Global()
25424 : ->Set(context, v8_str("o"),
25425 : object_template->NewInstance(context).ToLocalChecked())
25426 : .FromJust());
25427 5 : CompileRun("Object.getOwnPropertyNames(o)");
25428 5 : }
25429 :
25430 :
25431 28342 : TEST(GetHiddenPropertyTableAfterAccessCheck) {
25432 5 : v8::Isolate* isolate = CcTest::isolate();
25433 5 : v8::HandleScope handle_scope(isolate);
25434 : v8::Local<v8::ObjectTemplate> object_template =
25435 5 : v8::ObjectTemplate::New(isolate);
25436 5 : object_template->SetAccessCheckCallback(AccessCounter);
25437 :
25438 5 : v8::Local<Context> context = Context::New(isolate);
25439 : v8::Context::Scope context_scope(context);
25440 :
25441 : v8::Local<v8::Object> obj =
25442 5 : object_template->NewInstance(context).ToLocalChecked();
25443 20 : obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
25444 15 : obj->Delete(context, v8_str("key")).FromJust();
25445 :
25446 : obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
25447 15 : v8_str("hidden value 2"))
25448 15 : .FromJust();
25449 5 : }
25450 :
25451 :
25452 28342 : TEST(Regress411793) {
25453 5 : v8::Isolate* isolate = CcTest::isolate();
25454 5 : v8::HandleScope handle_scope(isolate);
25455 : v8::Local<v8::ObjectTemplate> object_template =
25456 5 : v8::ObjectTemplate::New(isolate);
25457 5 : object_template->SetAccessCheckCallback(AccessCounter);
25458 :
25459 5 : v8::Local<Context> context = Context::New(isolate);
25460 : v8::Context::Scope context_scope(context);
25461 :
25462 25 : CHECK(context->Global()
25463 : ->Set(context, v8_str("o"),
25464 : object_template->NewInstance(context).ToLocalChecked())
25465 : .FromJust());
25466 : CompileRun(
25467 : "Object.defineProperty(o, 'key', "
25468 5 : " { get: function() {}, set: function() {} });");
25469 5 : }
25470 :
25471 210 : class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
25472 : public:
25473 105 : explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
25474 :
25475 405 : size_t GetMoreData(const uint8_t** src) override {
25476 : // Unlike in real use cases, this function will never block.
25477 405 : if (chunks_[index_] == nullptr) {
25478 : return 0;
25479 : }
25480 : // Copy the data, since the caller takes ownership of it.
25481 310 : size_t len = strlen(chunks_[index_]);
25482 : // We don't need to zero-terminate since we return the length.
25483 310 : uint8_t* copy = new uint8_t[len];
25484 310 : memcpy(copy, chunks_[index_], len);
25485 310 : *src = copy;
25486 310 : ++index_;
25487 310 : return len;
25488 : }
25489 :
25490 : // Helper for constructing a string from chunks (the compilation needs it
25491 : // too).
25492 105 : static char* FullSourceString(const char** chunks) {
25493 : size_t total_len = 0;
25494 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
25495 330 : total_len += strlen(chunks[i]);
25496 : }
25497 105 : char* full_string = new char[total_len + 1];
25498 : size_t offset = 0;
25499 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
25500 330 : size_t len = strlen(chunks[i]);
25501 330 : memcpy(full_string + offset, chunks[i], len);
25502 330 : offset += len;
25503 : }
25504 105 : full_string[total_len] = 0;
25505 105 : return full_string;
25506 : }
25507 :
25508 : private:
25509 : const char** chunks_;
25510 : unsigned index_;
25511 : };
25512 :
25513 :
25514 : // Helper function for running streaming tests.
25515 95 : void RunStreamingTest(const char** chunks,
25516 : v8::ScriptCompiler::StreamedSource::Encoding encoding =
25517 : v8::ScriptCompiler::StreamedSource::ONE_BYTE,
25518 : bool expected_success = true,
25519 : const char* expected_source_url = nullptr,
25520 : const char* expected_source_mapping_url = nullptr) {
25521 95 : LocalContext env;
25522 95 : v8::Isolate* isolate = env->GetIsolate();
25523 190 : v8::HandleScope scope(isolate);
25524 190 : v8::TryCatch try_catch(isolate);
25525 :
25526 : v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
25527 285 : encoding);
25528 : v8::ScriptCompiler::ScriptStreamingTask* task =
25529 95 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25530 :
25531 : // TestSourceStream::GetMoreData won't block, so it's OK to just run the
25532 : // task here in the main thread.
25533 95 : task->Run();
25534 95 : delete task;
25535 :
25536 : // Possible errors are only produced while compiling.
25537 95 : CHECK(!try_catch.HasCaught());
25538 :
25539 95 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25540 95 : char* full_source = TestSourceStream::FullSourceString(chunks);
25541 : v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
25542 95 : env.local(), &source, v8_str(full_source), origin);
25543 95 : if (expected_success) {
25544 85 : CHECK(!script.IsEmpty());
25545 : v8::Local<Value> result(
25546 170 : script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
25547 : // All scripts are supposed to return the fixed value 13 when ran.
25548 170 : CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
25549 : CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
25550 85 : expected_source_mapping_url);
25551 : } else {
25552 10 : CHECK(script.IsEmpty());
25553 10 : CHECK(try_catch.HasCaught());
25554 : }
25555 190 : delete[] full_source;
25556 95 : }
25557 :
25558 28342 : TEST(StreamingSimpleScript) {
25559 : // This script is unrealistically small, since no one chunk is enough to fill
25560 : // the backing buffer of Scanner, let alone overflow it.
25561 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
25562 5 : nullptr};
25563 5 : RunStreamingTest(chunks);
25564 5 : }
25565 :
25566 28342 : TEST(StreamingScriptConstantArray) {
25567 : // When run with Ignition, tests that the streaming parser canonicalizes
25568 : // handles so that they are only added to the constant pool array once.
25569 : const char* chunks[] = {
25570 : "var a = {};", "var b = {};", "var c = 'testing';",
25571 5 : "var d = 'testing';", "13;", nullptr};
25572 5 : RunStreamingTest(chunks);
25573 5 : }
25574 :
25575 28342 : TEST(StreamingScriptEvalShadowing) {
25576 : // When run with Ignition, tests that the streaming parser canonicalizes
25577 : // handles so the Variable::is_possibly_eval() is correct.
25578 : const char* chunk1 =
25579 : "(function() {\n"
25580 : " var y = 2;\n"
25581 : " return (function() {\n"
25582 : " eval('var y = 13;');\n"
25583 : " function g() {\n"
25584 : " return y\n"
25585 : " }\n"
25586 : " return g();\n"
25587 : " })()\n"
25588 : "})()\n";
25589 5 : const char* chunks[] = {chunk1, nullptr};
25590 5 : RunStreamingTest(chunks);
25591 5 : }
25592 :
25593 28342 : TEST(StreamingBiggerScript) {
25594 : const char* chunk1 =
25595 : "function foo() {\n"
25596 : " // Make this chunk sufficiently long so that it will overflow the\n"
25597 : " // backing buffer of the Scanner.\n"
25598 : " var i = 0;\n"
25599 : " var result = 0;\n"
25600 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25601 : " result = 0;\n"
25602 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25603 : " result = 0;\n"
25604 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25605 : " result = 0;\n"
25606 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25607 : " return result;\n"
25608 : "}\n";
25609 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
25610 5 : RunStreamingTest(chunks);
25611 5 : }
25612 :
25613 :
25614 28342 : TEST(StreamingScriptWithParseError) {
25615 : // Test that parse errors from streamed scripts are propagated correctly.
25616 : {
25617 : char chunk1[] =
25618 : " // This will result in a parse error.\n"
25619 5 : " var if else then foo";
25620 5 : char chunk2[] = " 13\n";
25621 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25622 :
25623 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
25624 5 : false);
25625 : }
25626 : // Test that the next script succeeds normally.
25627 : {
25628 : char chunk1[] =
25629 : " // This will be parsed successfully.\n"
25630 5 : " function foo() { return ";
25631 5 : char chunk2[] = " 13; }\n";
25632 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25633 :
25634 5 : RunStreamingTest(chunks);
25635 : }
25636 5 : }
25637 :
25638 :
25639 28342 : TEST(StreamingUtf8Script) {
25640 : // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
25641 : // don't like it.
25642 : const char* chunk1 =
25643 : "function foo() {\n"
25644 : " // This function will contain an UTF-8 character which is not in\n"
25645 : " // ASCII.\n"
25646 : " var foob\xec\x92\x81r = 13;\n"
25647 : " return foob\xec\x92\x81r;\n"
25648 : "}\n";
25649 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
25650 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25651 5 : }
25652 :
25653 :
25654 28342 : TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
25655 : // A sanity check to prove that the approach of splitting UTF-8
25656 : // characters is correct. Here is an UTF-8 character which will take three
25657 : // bytes.
25658 : const char* reference = "\xec\x92\x81";
25659 : CHECK_EQ(3, strlen(reference));
25660 :
25661 : char chunk1[] =
25662 : "function foo() {\n"
25663 : " // This function will contain an UTF-8 character which is not in\n"
25664 : " // ASCII.\n"
25665 5 : " var foob";
25666 : char chunk2[] =
25667 : "XXXr = 13;\n"
25668 : " return foob\xec\x92\x81r;\n"
25669 5 : "}\n";
25670 20 : for (int i = 0; i < 3; ++i) {
25671 15 : chunk2[i] = reference[i];
25672 : }
25673 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25674 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25675 5 : }
25676 :
25677 :
25678 28342 : TEST(StreamingUtf8ScriptWithSplitCharacters) {
25679 : // Stream data where a multi-byte UTF-8 character is split between two data
25680 : // chunks.
25681 : const char* reference = "\xec\x92\x81";
25682 : char chunk1[] =
25683 : "function foo() {\n"
25684 : " // This function will contain an UTF-8 character which is not in\n"
25685 : " // ASCII.\n"
25686 5 : " var foobX";
25687 : char chunk2[] =
25688 : "XXr = 13;\n"
25689 : " return foob\xec\x92\x81r;\n"
25690 5 : "}\n";
25691 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25692 5 : chunk2[0] = reference[1];
25693 5 : chunk2[1] = reference[2];
25694 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25695 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25696 5 : }
25697 :
25698 :
25699 28342 : TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
25700 : // Tests edge cases which should still be decoded correctly.
25701 :
25702 : // Case 1: a chunk contains only bytes for a split character (and no other
25703 : // data). This kind of a chunk would be exceptionally small, but we should
25704 : // still decode it correctly.
25705 : const char* reference = "\xec\x92\x81";
25706 : // The small chunk is at the beginning of the split character
25707 : {
25708 : char chunk1[] =
25709 : "function foo() {\n"
25710 : " // This function will contain an UTF-8 character which is not in\n"
25711 : " // ASCII.\n"
25712 5 : " var foob";
25713 5 : char chunk2[] = "XX";
25714 : char chunk3[] =
25715 : "Xr = 13;\n"
25716 : " return foob\xec\x92\x81r;\n"
25717 5 : "}\n";
25718 5 : chunk2[0] = reference[0];
25719 5 : chunk2[1] = reference[1];
25720 5 : chunk3[0] = reference[2];
25721 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25722 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25723 : }
25724 : // The small chunk is at the end of a character
25725 : {
25726 : char chunk1[] =
25727 : "function foo() {\n"
25728 : " // This function will contain an UTF-8 character which is not in\n"
25729 : " // ASCII.\n"
25730 5 : " var foobX";
25731 5 : char chunk2[] = "XX";
25732 : char chunk3[] =
25733 : "r = 13;\n"
25734 : " return foob\xec\x92\x81r;\n"
25735 5 : "}\n";
25736 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25737 5 : chunk2[0] = reference[1];
25738 5 : chunk2[1] = reference[2];
25739 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25740 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25741 : }
25742 : // Case 2: the script ends with a multi-byte character. Make sure that it's
25743 : // decoded correctly and not just ignored.
25744 : {
25745 : char chunk1[] =
25746 : "var foob\xec\x92\x81 = 13;\n"
25747 5 : "foob\xec\x92\x81";
25748 5 : const char* chunks[] = {chunk1, nullptr};
25749 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25750 : }
25751 5 : }
25752 :
25753 :
25754 28342 : TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
25755 : // Test cases where a UTF-8 character is split over several chunks. Those
25756 : // cases are not supported (the embedder should give the data in big enough
25757 : // chunks), but we shouldn't crash and parse this just fine.
25758 : const char* reference = "\xec\x92\x81";
25759 : char chunk1[] =
25760 : "function foo() {\n"
25761 : " // This function will contain an UTF-8 character which is not in\n"
25762 : " // ASCII.\n"
25763 5 : " var foobX";
25764 5 : char chunk2[] = "X";
25765 : char chunk3[] =
25766 : "Xr = 13;\n"
25767 : " return foob\xec\x92\x81r;\n"
25768 5 : "}\n";
25769 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25770 5 : chunk2[0] = reference[1];
25771 5 : chunk3[0] = reference[2];
25772 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25773 :
25774 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25775 5 : }
25776 :
25777 :
25778 :
25779 28342 : TEST(StreamingWithDebuggingEnabledLate) {
25780 : // The streaming parser can only parse lazily, i.e. inner functions are not
25781 : // fully parsed. However, we may compile inner functions eagerly when
25782 : // debugging. Make sure that we can deal with this when turning on debugging
25783 : // after streaming parser has already finished parsing.
25784 : const char* chunks[] = {"with({x:1}) {",
25785 : " var foo = function foo(y) {",
25786 : " return x + y;",
25787 : " };",
25788 : " foo(2);",
25789 : "}",
25790 5 : nullptr};
25791 :
25792 5 : LocalContext env;
25793 5 : v8::Isolate* isolate = env->GetIsolate();
25794 10 : v8::HandleScope scope(isolate);
25795 10 : v8::TryCatch try_catch(isolate);
25796 :
25797 : v8::ScriptCompiler::StreamedSource source(
25798 : new TestSourceStream(chunks),
25799 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25800 : v8::ScriptCompiler::ScriptStreamingTask* task =
25801 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25802 :
25803 5 : task->Run();
25804 5 : delete task;
25805 :
25806 5 : CHECK(!try_catch.HasCaught());
25807 :
25808 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25809 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25810 :
25811 : EnableDebugger(isolate);
25812 :
25813 : v8::Local<Script> script =
25814 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25815 5 : origin)
25816 5 : .ToLocalChecked();
25817 :
25818 : Maybe<uint32_t> result =
25819 10 : script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
25820 5 : CHECK_EQ(3U, result.FromMaybe(0));
25821 :
25822 5 : delete[] full_source;
25823 :
25824 5 : DisableDebugger(isolate);
25825 5 : }
25826 :
25827 :
25828 28342 : TEST(StreamingScriptWithInvalidUtf8) {
25829 : // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
25830 : // chunk don't produce a crash.
25831 : const char* reference = "\xec\x92\x81\x80\x80";
25832 : char chunk1[] =
25833 : "function foo() {\n"
25834 : " // This function will contain an UTF-8 character which is not in\n"
25835 : " // ASCII.\n"
25836 5 : " var foobXXXXX"; // Too many bytes which look like incomplete chars!
25837 : char chunk2[] =
25838 : "r = 13;\n"
25839 : " return foob\xec\x92\x81\x80\x80r;\n"
25840 5 : "}\n";
25841 5 : for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
25842 :
25843 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25844 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
25845 5 : }
25846 :
25847 :
25848 28342 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
25849 : // Regression test: Stream data where there are several multi-byte UTF-8
25850 : // characters in a sequence and one of them is split between two data chunks.
25851 : const char* reference = "\xec\x92\x81";
25852 : char chunk1[] =
25853 : "function foo() {\n"
25854 : " // This function will contain an UTF-8 character which is not in\n"
25855 : " // ASCII.\n"
25856 5 : " var foob\xec\x92\x81X";
25857 : char chunk2[] =
25858 : "XXr = 13;\n"
25859 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25860 5 : "}\n";
25861 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25862 5 : chunk2[0] = reference[1];
25863 5 : chunk2[1] = reference[2];
25864 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25865 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25866 5 : }
25867 :
25868 :
25869 28342 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
25870 : // Another regression test, similar to the previous one. The difference is
25871 : // that the split character is not the last one in the sequence.
25872 : const char* reference = "\xec\x92\x81";
25873 : char chunk1[] =
25874 : "function foo() {\n"
25875 : " // This function will contain an UTF-8 character which is not in\n"
25876 : " // ASCII.\n"
25877 5 : " var foobX";
25878 : char chunk2[] =
25879 : "XX\xec\x92\x81r = 13;\n"
25880 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25881 5 : "}\n";
25882 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25883 5 : chunk2[0] = reference[1];
25884 5 : chunk2[1] = reference[2];
25885 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25886 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25887 5 : }
25888 :
25889 :
25890 28342 : TEST(StreamingWithHarmonyScopes) {
25891 : // Don't use RunStreamingTest here so that both scripts get to use the same
25892 : // LocalContext and HandleScope.
25893 5 : LocalContext env;
25894 5 : v8::Isolate* isolate = env->GetIsolate();
25895 10 : v8::HandleScope scope(isolate);
25896 :
25897 : // First, run a script with a let variable.
25898 : CompileRun("\"use strict\"; let x = 1;");
25899 :
25900 : // Then stream a script which (erroneously) tries to introduce the same
25901 : // variable again.
25902 5 : const char* chunks[] = {"\"use strict\"; let x = 2;", nullptr};
25903 :
25904 10 : v8::TryCatch try_catch(isolate);
25905 : v8::ScriptCompiler::StreamedSource source(
25906 : new TestSourceStream(chunks),
25907 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25908 : v8::ScriptCompiler::ScriptStreamingTask* task =
25909 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25910 5 : task->Run();
25911 5 : delete task;
25912 :
25913 : // Parsing should succeed (the script will be parsed and compiled in a context
25914 : // independent way, so the error is not detected).
25915 5 : CHECK(!try_catch.HasCaught());
25916 :
25917 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25918 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25919 : v8::Local<Script> script =
25920 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25921 5 : origin)
25922 5 : .ToLocalChecked();
25923 5 : CHECK(!script.IsEmpty());
25924 5 : CHECK(!try_catch.HasCaught());
25925 :
25926 : // Running the script exposes the error.
25927 10 : CHECK(script->Run(env.local()).IsEmpty());
25928 5 : CHECK(try_catch.HasCaught());
25929 10 : delete[] full_source;
25930 5 : }
25931 :
25932 :
25933 28342 : TEST(CodeCache) {
25934 : v8::Isolate::CreateParams create_params;
25935 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25936 :
25937 : const char* source = "Math.sqrt(4)";
25938 : const char* origin = "code cache test";
25939 : v8::ScriptCompiler::CachedData* cache;
25940 :
25941 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
25942 : {
25943 : v8::Isolate::Scope iscope(isolate1);
25944 10 : v8::HandleScope scope(isolate1);
25945 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
25946 : v8::Context::Scope cscope(context);
25947 5 : v8::Local<v8::String> source_string = v8_str(source);
25948 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25949 : v8::ScriptCompiler::Source source(source_string, script_origin);
25950 : v8::ScriptCompiler::CompileOptions option =
25951 : v8::ScriptCompiler::kNoCompileOptions;
25952 : v8::Local<v8::Script> script =
25953 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25954 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25955 : }
25956 5 : isolate1->Dispose();
25957 :
25958 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
25959 : {
25960 : v8::Isolate::Scope iscope(isolate2);
25961 10 : v8::HandleScope scope(isolate2);
25962 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
25963 : v8::Context::Scope cscope(context);
25964 5 : v8::Local<v8::String> source_string = v8_str(source);
25965 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25966 : v8::ScriptCompiler::Source source(source_string, script_origin, cache);
25967 : v8::ScriptCompiler::CompileOptions option =
25968 : v8::ScriptCompiler::kConsumeCodeCache;
25969 : v8::Local<v8::Script> script;
25970 : {
25971 : i::DisallowCompilation no_compile(
25972 : reinterpret_cast<i::Isolate*>(isolate2));
25973 : script = v8::ScriptCompiler::Compile(context, &source, option)
25974 5 : .ToLocalChecked();
25975 : }
25976 20 : CHECK_EQ(2, script->Run(context)
25977 : .ToLocalChecked()
25978 : ->ToInt32(context)
25979 : .ToLocalChecked()
25980 : ->Int32Value(context)
25981 : .FromJust());
25982 : }
25983 5 : isolate2->Dispose();
25984 5 : }
25985 :
25986 0 : v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
25987 : Local<String> specifier,
25988 : Local<Module> referrer) {
25989 0 : CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
25990 : }
25991 :
25992 : namespace {
25993 :
25994 10 : Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
25995 : Local<Context> context,
25996 : const char* resource_name,
25997 : const char* source) {
25998 10 : Local<String> source_string = v8_str(source);
25999 : v8::ScriptOrigin script_origin(
26000 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
26001 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
26002 10 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
26003 : v8::ScriptCompiler::Source script_compiler_source(source_string,
26004 : script_origin);
26005 : Local<Module> module =
26006 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source)
26007 10 : .ToLocalChecked();
26008 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
26009 20 : .ToChecked();
26010 :
26011 20 : return module;
26012 : }
26013 :
26014 5 : Local<Module> CompileAndInstantiateModuleFromCache(
26015 : v8::Isolate* isolate, Local<Context> context, const char* resource_name,
26016 : const char* source, v8::ScriptCompiler::CachedData* cache) {
26017 5 : Local<String> source_string = v8_str(source);
26018 : v8::ScriptOrigin script_origin(
26019 : v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
26020 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
26021 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
26022 : v8::ScriptCompiler::Source script_compiler_source(source_string,
26023 : script_origin, cache);
26024 :
26025 : Local<Module> module =
26026 : v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source,
26027 : v8::ScriptCompiler::kConsumeCodeCache)
26028 5 : .ToLocalChecked();
26029 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
26030 10 : .ToChecked();
26031 :
26032 10 : return module;
26033 : }
26034 :
26035 : } // namespace
26036 :
26037 28342 : TEST(ModuleCodeCache) {
26038 : v8::Isolate::CreateParams create_params;
26039 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
26040 :
26041 : const char* origin = "code cache test";
26042 : const char* source =
26043 : "export default 5; export const a = 10; function f() { return 42; } "
26044 : "(function() { return f(); })();";
26045 :
26046 : v8::ScriptCompiler::CachedData* cache;
26047 : {
26048 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26049 : {
26050 : v8::Isolate::Scope iscope(isolate);
26051 10 : v8::HandleScope scope(isolate);
26052 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26053 : v8::Context::Scope cscope(context);
26054 :
26055 : Local<Module> module =
26056 5 : CompileAndInstantiateModule(isolate, context, origin, source);
26057 :
26058 : // Fetch the shared function info before evaluation.
26059 : Local<v8::UnboundModuleScript> unbound_module_script =
26060 5 : module->GetUnboundModuleScript();
26061 :
26062 : // Evaluate for possible lazy compilation.
26063 : Local<Value> completion_value =
26064 5 : module->Evaluate(context).ToLocalChecked();
26065 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
26066 :
26067 : // Now create the cache. Note that it is freed, obscurely, when
26068 : // ScriptCompiler::Source goes out of scope below.
26069 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
26070 : }
26071 5 : isolate->Dispose();
26072 : }
26073 :
26074 : // Test that the cache is consumed and execution still works.
26075 : {
26076 : // Disable --always_opt, otherwise we try to optimize during module
26077 : // instantiation, violating the DisallowCompilation scope.
26078 5 : i::FLAG_always_opt = false;
26079 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26080 : {
26081 : v8::Isolate::Scope iscope(isolate);
26082 10 : v8::HandleScope scope(isolate);
26083 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26084 : v8::Context::Scope cscope(context);
26085 :
26086 : Local<Module> module;
26087 : {
26088 : i::DisallowCompilation no_compile(
26089 : reinterpret_cast<i::Isolate*>(isolate));
26090 : module = CompileAndInstantiateModuleFromCache(isolate, context, origin,
26091 5 : source, cache);
26092 : }
26093 :
26094 : Local<Value> completion_value =
26095 5 : module->Evaluate(context).ToLocalChecked();
26096 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
26097 : }
26098 5 : isolate->Dispose();
26099 : }
26100 5 : }
26101 :
26102 : // Tests that the code cache does not confuse the same source code compiled as a
26103 : // script and as a module.
26104 28342 : TEST(CodeCacheModuleScriptMismatch) {
26105 : v8::Isolate::CreateParams create_params;
26106 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
26107 :
26108 : const char* origin = "code cache test";
26109 : const char* source = "42";
26110 :
26111 : v8::ScriptCompiler::CachedData* cache;
26112 : {
26113 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26114 : {
26115 : v8::Isolate::Scope iscope(isolate);
26116 10 : v8::HandleScope scope(isolate);
26117 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26118 : v8::Context::Scope cscope(context);
26119 :
26120 : Local<Module> module =
26121 5 : CompileAndInstantiateModule(isolate, context, origin, source);
26122 :
26123 : // Fetch the shared function info before evaluation.
26124 : Local<v8::UnboundModuleScript> unbound_module_script =
26125 5 : module->GetUnboundModuleScript();
26126 :
26127 : // Evaluate for possible lazy compilation.
26128 : Local<Value> completion_value =
26129 5 : module->Evaluate(context).ToLocalChecked();
26130 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
26131 :
26132 : // Now create the cache. Note that it is freed, obscurely, when
26133 : // ScriptCompiler::Source goes out of scope below.
26134 5 : cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
26135 : }
26136 5 : isolate->Dispose();
26137 : }
26138 :
26139 : // Test that the cache is not consumed when source is compiled as a script.
26140 : {
26141 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26142 : {
26143 : v8::Isolate::Scope iscope(isolate);
26144 10 : v8::HandleScope scope(isolate);
26145 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26146 : v8::Context::Scope cscope(context);
26147 :
26148 5 : v8::ScriptOrigin script_origin(v8_str(origin));
26149 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
26150 5 : script_origin, cache);
26151 :
26152 : v8::Local<v8::Script> script =
26153 : v8::ScriptCompiler::Compile(context, &script_compiler_source,
26154 : v8::ScriptCompiler::kConsumeCodeCache)
26155 5 : .ToLocalChecked();
26156 :
26157 5 : CHECK(cache->rejected);
26158 :
26159 20 : CHECK_EQ(42, script->Run(context)
26160 : .ToLocalChecked()
26161 : ->ToInt32(context)
26162 : .ToLocalChecked()
26163 : ->Int32Value(context)
26164 : .FromJust());
26165 : }
26166 5 : isolate->Dispose();
26167 : }
26168 5 : }
26169 :
26170 : // Same as above but other way around.
26171 28342 : TEST(CodeCacheScriptModuleMismatch) {
26172 : v8::Isolate::CreateParams create_params;
26173 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
26174 :
26175 : const char* origin = "code cache test";
26176 : const char* source = "42";
26177 :
26178 : v8::ScriptCompiler::CachedData* cache;
26179 : {
26180 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26181 : {
26182 : v8::Isolate::Scope iscope(isolate);
26183 10 : v8::HandleScope scope(isolate);
26184 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26185 : v8::Context::Scope cscope(context);
26186 5 : v8::Local<v8::String> source_string = v8_str(source);
26187 5 : v8::ScriptOrigin script_origin(v8_str(origin));
26188 : v8::ScriptCompiler::Source source(source_string, script_origin);
26189 : v8::ScriptCompiler::CompileOptions option =
26190 : v8::ScriptCompiler::kNoCompileOptions;
26191 : v8::Local<v8::Script> script =
26192 : v8::ScriptCompiler::Compile(context, &source, option)
26193 5 : .ToLocalChecked();
26194 5 : cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
26195 : }
26196 5 : isolate->Dispose();
26197 : }
26198 :
26199 : // Test that the cache is not consumed when source is compiled as a module.
26200 : {
26201 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
26202 : {
26203 : v8::Isolate::Scope iscope(isolate);
26204 10 : v8::HandleScope scope(isolate);
26205 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
26206 : v8::Context::Scope cscope(context);
26207 :
26208 : v8::ScriptOrigin script_origin(
26209 : v8_str(origin), Local<v8::Integer>(), Local<v8::Integer>(),
26210 : Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
26211 5 : Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
26212 : v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
26213 5 : script_origin, cache);
26214 :
26215 : Local<Module> module = v8::ScriptCompiler::CompileModule(
26216 : isolate, &script_compiler_source,
26217 : v8::ScriptCompiler::kConsumeCodeCache)
26218 5 : .ToLocalChecked();
26219 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
26220 10 : .ToChecked();
26221 :
26222 5 : CHECK(cache->rejected);
26223 :
26224 : Local<Value> completion_value =
26225 5 : module->Evaluate(context).ToLocalChecked();
26226 10 : CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
26227 : }
26228 5 : isolate->Dispose();
26229 : }
26230 5 : }
26231 :
26232 : // Tests that compilation can handle a garbled cache.
26233 28342 : TEST(InvalidCodeCacheDataInCompileModule) {
26234 5 : v8::V8::Initialize();
26235 5 : v8::Isolate* isolate = CcTest::isolate();
26236 5 : v8::HandleScope scope(isolate);
26237 10 : LocalContext local_context;
26238 :
26239 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
26240 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
26241 5 : Local<String> origin = v8_str("origin");
26242 : int length = 16;
26243 : v8::ScriptCompiler::CachedData* cached_data =
26244 5 : new v8::ScriptCompiler::CachedData(data, length);
26245 5 : CHECK(!cached_data->rejected);
26246 :
26247 : v8::ScriptOrigin script_origin(
26248 : origin, Local<v8::Integer>(), Local<v8::Integer>(), Local<v8::Boolean>(),
26249 : Local<v8::Integer>(), Local<v8::Value>(), Local<v8::Boolean>(),
26250 : Local<v8::Boolean>(), True(isolate));
26251 5 : v8::ScriptCompiler::Source source(v8_str("42"), script_origin, cached_data);
26252 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
26253 :
26254 : Local<Module> module =
26255 : v8::ScriptCompiler::CompileModule(isolate, &source,
26256 : v8::ScriptCompiler::kConsumeCodeCache)
26257 5 : .ToLocalChecked();
26258 : module->InstantiateModule(context, UnexpectedModuleResolveCallback)
26259 10 : .ToChecked();
26260 :
26261 5 : CHECK(cached_data->rejected);
26262 15 : CHECK_EQ(42, module->Evaluate(context)
26263 : .ToLocalChecked()
26264 : ->Int32Value(context)
26265 5 : .FromJust());
26266 5 : }
26267 :
26268 5 : void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
26269 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
26270 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
26271 : int length = 16;
26272 : v8::ScriptCompiler::CachedData* cached_data =
26273 5 : new v8::ScriptCompiler::CachedData(data, length);
26274 5 : CHECK(!cached_data->rejected);
26275 5 : v8::ScriptOrigin origin(v8_str("origin"));
26276 5 : v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
26277 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
26278 : v8::Local<v8::Script> script =
26279 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
26280 5 : CHECK(cached_data->rejected);
26281 15 : CHECK_EQ(
26282 : 42,
26283 : script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
26284 5 : }
26285 :
26286 :
26287 28342 : TEST(InvalidCodeCacheData) {
26288 5 : v8::V8::Initialize();
26289 5 : v8::HandleScope scope(CcTest::isolate());
26290 10 : LocalContext context;
26291 10 : TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
26292 5 : }
26293 :
26294 :
26295 28342 : TEST(StringConcatOverflow) {
26296 5 : v8::V8::Initialize();
26297 5 : v8::Isolate* isolate = CcTest::isolate();
26298 5 : v8::HandleScope scope(isolate);
26299 : RandomLengthOneByteResource* r =
26300 5 : new RandomLengthOneByteResource(i::String::kMaxLength);
26301 : v8::Local<v8::String> str =
26302 5 : v8::String::NewExternalOneByte(isolate, r).ToLocalChecked();
26303 5 : CHECK(!str.IsEmpty());
26304 10 : v8::TryCatch try_catch(isolate);
26305 5 : v8::Local<v8::String> result = v8::String::Concat(isolate, str, str);
26306 5 : v8::String::Concat(CcTest::isolate(), str, str);
26307 5 : CHECK(result.IsEmpty());
26308 10 : CHECK(!try_catch.HasCaught());
26309 5 : }
26310 :
26311 28342 : TEST(TurboAsmDisablesDetach) {
26312 : #ifndef V8_LITE_MODE
26313 5 : i::FLAG_opt = true;
26314 5 : i::FLAG_allow_natives_syntax = true;
26315 5 : v8::V8::Initialize();
26316 5 : v8::HandleScope scope(CcTest::isolate());
26317 10 : LocalContext context;
26318 : const char* load =
26319 : "function Module(stdlib, foreign, heap) {"
26320 : " 'use asm';"
26321 : " var MEM32 = new stdlib.Int32Array(heap);"
26322 : " function load() { return MEM32[0] | 0; }"
26323 : " return { load: load };"
26324 : "}"
26325 : "var buffer = new ArrayBuffer(4096);"
26326 : "var module = Module(this, {}, buffer);"
26327 : "%OptimizeFunctionOnNextCall(module.load);"
26328 : "module.load();"
26329 : "buffer";
26330 :
26331 : v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
26332 5 : CHECK(!result->IsDetachable());
26333 :
26334 : const char* store =
26335 : "function Module(stdlib, foreign, heap) {"
26336 : " 'use asm';"
26337 : " var MEM32 = new stdlib.Int32Array(heap);"
26338 : " function store() { MEM32[0] = 0; }"
26339 : " return { store: store };"
26340 : "}"
26341 : "var buffer = new ArrayBuffer(4096);"
26342 : "var module = Module(this, {}, buffer);"
26343 : "%OptimizeFunctionOnNextCall(module.store);"
26344 : "module.store();"
26345 : "buffer";
26346 :
26347 : result = CompileRun(store).As<v8::ArrayBuffer>();
26348 10 : CHECK(!result->IsDetachable());
26349 : #endif // V8_LITE_MODE
26350 5 : }
26351 :
26352 28342 : TEST(ClassPrototypeCreationContext) {
26353 5 : v8::Isolate* isolate = CcTest::isolate();
26354 5 : v8::HandleScope handle_scope(isolate);
26355 10 : LocalContext env;
26356 :
26357 : Local<Object> result = Local<Object>::Cast(
26358 : CompileRun("'use strict'; class Example { }; Example.prototype"));
26359 15 : CHECK(env.local() == result->CreationContext());
26360 5 : }
26361 :
26362 :
26363 28342 : TEST(SimpleStreamingScriptWithSourceURL) {
26364 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
26365 5 : "//# sourceURL=bar2.js\n", nullptr};
26366 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
26367 5 : "bar2.js");
26368 5 : }
26369 :
26370 :
26371 28342 : TEST(StreamingScriptWithSplitSourceURL) {
26372 : const char* chunks[] = {"function foo() { ret", "urn 13; } f",
26373 5 : "oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
26374 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
26375 5 : "bar2.js");
26376 5 : }
26377 :
26378 :
26379 28342 : TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
26380 : const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
26381 5 : " sourceMappingURL=bar2.js\n", "foo();", nullptr};
26382 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
26383 5 : nullptr, "bar2.js");
26384 5 : }
26385 :
26386 :
26387 28342 : TEST(NewStringRangeError) {
26388 : // This test uses a lot of memory and fails with flaky OOM when run
26389 : // with --stress-incremental-marking on TSAN.
26390 5 : i::FLAG_stress_incremental_marking = false;
26391 5 : v8::Isolate* isolate = CcTest::isolate();
26392 5 : v8::HandleScope handle_scope(isolate);
26393 : const int length = i::String::kMaxLength + 1;
26394 : const int buffer_size = length * sizeof(uint16_t);
26395 5 : void* buffer = malloc(buffer_size);
26396 5 : if (buffer == nullptr) return;
26397 : memset(buffer, 'A', buffer_size);
26398 : {
26399 5 : v8::TryCatch try_catch(isolate);
26400 : char* data = reinterpret_cast<char*>(buffer);
26401 10 : CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
26402 : length)
26403 : .IsEmpty());
26404 5 : CHECK(!try_catch.HasCaught());
26405 : }
26406 : {
26407 5 : v8::TryCatch try_catch(isolate);
26408 : uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
26409 10 : CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
26410 : length)
26411 : .IsEmpty());
26412 5 : CHECK(!try_catch.HasCaught());
26413 : }
26414 : {
26415 5 : v8::TryCatch try_catch(isolate);
26416 : uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
26417 10 : CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
26418 : length)
26419 : .IsEmpty());
26420 5 : CHECK(!try_catch.HasCaught());
26421 : }
26422 5 : free(buffer);
26423 : }
26424 :
26425 :
26426 28337 : TEST(SealHandleScope) {
26427 0 : v8::Isolate* isolate = CcTest::isolate();
26428 0 : v8::HandleScope handle_scope(isolate);
26429 0 : LocalContext env;
26430 :
26431 0 : v8::SealHandleScope seal(isolate);
26432 :
26433 : // Should fail
26434 0 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
26435 :
26436 0 : USE(obj);
26437 0 : }
26438 :
26439 :
26440 28342 : TEST(SealHandleScopeNested) {
26441 5 : v8::Isolate* isolate = CcTest::isolate();
26442 5 : v8::HandleScope handle_scope(isolate);
26443 10 : LocalContext env;
26444 :
26445 10 : v8::SealHandleScope seal(isolate);
26446 :
26447 : {
26448 5 : v8::HandleScope handle_scope(isolate);
26449 :
26450 : // Should work
26451 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
26452 :
26453 5 : USE(obj);
26454 5 : }
26455 5 : }
26456 :
26457 :
26458 5 : static void ExtrasBindingTestRuntimeFunction(
26459 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
26460 15 : CHECK_EQ(
26461 : 3,
26462 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
26463 5 : args.GetReturnValue().Set(v8_num(7));
26464 5 : }
26465 :
26466 28342 : TEST(ExtrasFunctionSource) {
26467 5 : v8::Isolate* isolate = CcTest::isolate();
26468 5 : v8::HandleScope handle_scope(isolate);
26469 10 : LocalContext env;
26470 :
26471 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26472 :
26473 : // Functions defined in extras do not expose source code.
26474 15 : auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
26475 5 : .ToLocalChecked()
26476 : .As<v8::Function>();
26477 : auto undefined = v8::Undefined(isolate);
26478 10 : auto result = func->Call(env.local(), undefined, 0, {})
26479 5 : .ToLocalChecked()
26480 : .As<v8::String>();
26481 10 : CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
26482 :
26483 : // Functions defined in extras do not show up in the stack trace.
26484 15 : auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
26485 5 : .ToLocalChecked()
26486 : .As<v8::Function>();
26487 25 : CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
26488 : ExpectString(
26489 : "function f(x) { return wrapper(x) }"
26490 : "function g() { return new Error().stack; }"
26491 : "f(g)",
26492 : "Error\n"
26493 : " at g (<anonymous>:1:58)\n"
26494 : " at f (<anonymous>:1:24)\n"
26495 10 : " at <anonymous>:1:78");
26496 5 : }
26497 :
26498 28342 : TEST(ExtrasBindingObject) {
26499 5 : v8::Isolate* isolate = CcTest::isolate();
26500 5 : v8::HandleScope handle_scope(isolate);
26501 10 : LocalContext env;
26502 :
26503 : // standalone.gypi ensures we include the test-extra.js file, which should
26504 : // export the tested functions.
26505 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26506 :
26507 15 : auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
26508 5 : .ToLocalChecked()
26509 : .As<v8::Function>();
26510 : auto undefined = v8::Undefined(isolate);
26511 10 : auto result = func->Call(env.local(), undefined, 0, {})
26512 5 : .ToLocalChecked()
26513 : .As<v8::Number>();
26514 10 : CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
26515 :
26516 : v8::Local<v8::FunctionTemplate> runtimeFunction =
26517 5 : v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
26518 : binding->Set(env.local(), v8_str("runtime"),
26519 25 : runtimeFunction->GetFunction(env.local()).ToLocalChecked())
26520 10 : .FromJust();
26521 15 : func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
26522 5 : .ToLocalChecked()
26523 : .As<v8::Function>();
26524 10 : result = func->Call(env.local(), undefined, 0, {})
26525 5 : .ToLocalChecked()
26526 : .As<v8::Number>();
26527 15 : CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
26528 5 : }
26529 :
26530 :
26531 28342 : TEST(ExtrasCreatePromise) {
26532 5 : i::FLAG_allow_natives_syntax = true;
26533 5 : LocalContext context;
26534 5 : v8::Isolate* isolate = context->GetIsolate();
26535 10 : v8::HandleScope handle_scope(isolate);
26536 :
26537 10 : LocalContext env;
26538 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26539 :
26540 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromise"))
26541 5 : .ToLocalChecked()
26542 : .As<v8::Function>();
26543 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26544 :
26545 : auto promise = CompileRun(
26546 : "func();\n"
26547 : "func();\n"
26548 : "%OptimizeFunctionOnNextCall(func);\n"
26549 : "func()\n")
26550 : .As<v8::Promise>();
26551 10 : CHECK_EQ(v8::Promise::kPending, promise->State());
26552 5 : }
26553 :
26554 28342 : TEST(ExtrasCreatePromiseWithParent) {
26555 5 : i::FLAG_allow_natives_syntax = true;
26556 5 : LocalContext context;
26557 5 : v8::Isolate* isolate = context->GetIsolate();
26558 10 : v8::HandleScope handle_scope(isolate);
26559 :
26560 10 : LocalContext env;
26561 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26562 :
26563 15 : auto func = binding->Get(env.local(), v8_str("testCreatePromiseWithParent"))
26564 5 : .ToLocalChecked()
26565 : .As<v8::Function>();
26566 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26567 :
26568 : auto promise = CompileRun(
26569 : "var parent = new Promise((a, b) => {});\n"
26570 : "func(parent);\n"
26571 : "func(parent);\n"
26572 : "%OptimizeFunctionOnNextCall(func);\n"
26573 : "func(parent)\n")
26574 : .As<v8::Promise>();
26575 10 : CHECK_EQ(v8::Promise::kPending, promise->State());
26576 5 : }
26577 :
26578 28342 : TEST(ExtrasRejectPromise) {
26579 5 : i::FLAG_allow_natives_syntax = true;
26580 5 : LocalContext context;
26581 5 : v8::Isolate* isolate = context->GetIsolate();
26582 10 : v8::HandleScope handle_scope(isolate);
26583 :
26584 10 : LocalContext env;
26585 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26586 :
26587 15 : auto func = binding->Get(env.local(), v8_str("testRejectPromise"))
26588 5 : .ToLocalChecked()
26589 : .As<v8::Function>();
26590 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26591 :
26592 : auto rejected_promise = CompileRun(
26593 : "function newPromise() {\n"
26594 : " return new Promise((a, b) => {});\n"
26595 : "}\n"
26596 : "func(newPromise(), 1);\n"
26597 : "func(newPromise(), 1);\n"
26598 : "%OptimizeFunctionOnNextCall(func);\n"
26599 : "var promise = newPromise();\n"
26600 : "func(promise, 1);\n"
26601 : "promise;\n")
26602 : .As<v8::Promise>();
26603 5 : CHECK_EQ(v8::Promise::kRejected, rejected_promise->State());
26604 20 : CHECK_EQ(1, rejected_promise->Result()->Int32Value(env.local()).FromJust());
26605 5 : }
26606 :
26607 28342 : TEST(ExtrasResolvePromise) {
26608 5 : i::FLAG_allow_natives_syntax = true;
26609 5 : LocalContext context;
26610 5 : v8::Isolate* isolate = context->GetIsolate();
26611 10 : v8::HandleScope handle_scope(isolate);
26612 :
26613 10 : LocalContext env;
26614 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26615 :
26616 15 : auto func = binding->Get(env.local(), v8_str("testResolvePromise"))
26617 5 : .ToLocalChecked()
26618 : .As<v8::Function>();
26619 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26620 :
26621 : auto pending_promise = CompileRun(
26622 : "function newPromise() {\n"
26623 : " return new Promise((a, b) => {});\n"
26624 : "}\n"
26625 : "func(newPromise(), newPromise());\n"
26626 : "func(newPromise(), newPromise());\n"
26627 : "%OptimizeFunctionOnNextCall(func);\n"
26628 : "var promise = newPromise();\n"
26629 : "func(promise, newPromise());\n"
26630 : "promise;\n")
26631 : .As<v8::Promise>();
26632 5 : CHECK_EQ(v8::Promise::kPending, pending_promise->State());
26633 :
26634 : auto fulfilled_promise = CompileRun(
26635 : "function newPromise() {\n"
26636 : " return new Promise((a, b) => {});\n"
26637 : "}\n"
26638 : "func(newPromise(), 1);\n"
26639 : "func(newPromise(), 1);\n"
26640 : "%OptimizeFunctionOnNextCall(func);\n"
26641 : "var promise = newPromise();\n"
26642 : "func(promise, 1);\n"
26643 : "promise;\n")
26644 : .As<v8::Promise>();
26645 5 : CHECK_EQ(v8::Promise::kFulfilled, fulfilled_promise->State());
26646 20 : CHECK_EQ(1, fulfilled_promise->Result()->Int32Value(env.local()).FromJust());
26647 5 : }
26648 :
26649 28342 : TEST(ExtrasUtilsObject) {
26650 5 : LocalContext context;
26651 5 : v8::Isolate* isolate = context->GetIsolate();
26652 10 : v8::HandleScope handle_scope(isolate);
26653 :
26654 10 : LocalContext env;
26655 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
26656 :
26657 15 : auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
26658 5 : .ToLocalChecked()
26659 : .As<v8::Function>();
26660 : auto undefined = v8::Undefined(isolate);
26661 10 : auto result = func->Call(env.local(), undefined, 0, {})
26662 5 : .ToLocalChecked()
26663 : .As<v8::Object>();
26664 :
26665 15 : auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
26666 5 : .ToLocalChecked()
26667 : .As<v8::Symbol>();
26668 : i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
26669 5 : CHECK(ips->IsPrivate());
26670 :
26671 : CompileRun("var result = 0; function store(x) { result = x; }");
26672 5 : auto store = CompileRun("store").As<v8::Function>();
26673 :
26674 15 : auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
26675 5 : .ToLocalChecked()
26676 : .As<v8::Promise>();
26677 5 : fulfilled_promise->Then(env.local(), store).ToLocalChecked();
26678 5 : isolate->RunMicrotasks();
26679 15 : CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
26680 :
26681 : auto fulfilled_promise_2 =
26682 15 : result->Get(env.local(), v8_str("fulfilledPromise2"))
26683 5 : .ToLocalChecked()
26684 : .As<v8::Promise>();
26685 5 : fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
26686 5 : isolate->RunMicrotasks();
26687 15 : CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
26688 :
26689 15 : auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
26690 5 : .ToLocalChecked()
26691 : .As<v8::Promise>();
26692 5 : rejected_promise->Catch(env.local(), store).ToLocalChecked();
26693 5 : isolate->RunMicrotasks();
26694 15 : CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
26695 :
26696 : auto rejected_but_handled_promise =
26697 15 : result->Get(env.local(), v8_str("rejectedButHandledPromise"))
26698 5 : .ToLocalChecked()
26699 : .As<v8::Promise>();
26700 5 : CHECK(rejected_but_handled_promise->HasHandler());
26701 :
26702 15 : auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
26703 5 : .ToLocalChecked()
26704 : .As<v8::String>();
26705 10 : String::Utf8Value promise_states_string(isolate, promise_states);
26706 5 : CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
26707 :
26708 15 : auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
26709 5 : .ToLocalChecked()
26710 : .As<v8::Boolean>();
26711 5 : CHECK_EQ(true, promise_is_promise->Value());
26712 :
26713 : auto thenable_is_promise =
26714 15 : result->Get(env.local(), v8_str("thenableIsPromise"))
26715 5 : .ToLocalChecked()
26716 : .As<v8::Boolean>();
26717 10 : CHECK_EQ(false, thenable_is_promise->Value());
26718 :
26719 15 : auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
26720 5 : .ToLocalChecked()
26721 : .As<v8::Boolean>();
26722 10 : CHECK_EQ(true, uncurry_this->Value());
26723 5 : }
26724 :
26725 :
26726 28342 : TEST(Map) {
26727 5 : v8::Isolate* isolate = CcTest::isolate();
26728 5 : v8::HandleScope handle_scope(isolate);
26729 10 : LocalContext env;
26730 :
26731 5 : v8::Local<v8::Map> map = v8::Map::New(isolate);
26732 5 : CHECK(map->IsObject());
26733 5 : CHECK(map->IsMap());
26734 10 : CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
26735 5 : CHECK_EQ(0U, map->Size());
26736 :
26737 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
26738 5 : CHECK(val->IsMap());
26739 : map = v8::Local<v8::Map>::Cast(val);
26740 5 : CHECK_EQ(2U, map->Size());
26741 :
26742 5 : v8::Local<v8::Array> contents = map->AsArray();
26743 5 : CHECK_EQ(4U, contents->Length());
26744 10 : CHECK_EQ(
26745 : 1,
26746 : contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26747 10 : CHECK_EQ(
26748 : 2,
26749 : contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26750 10 : CHECK_EQ(
26751 : 3,
26752 : contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
26753 10 : CHECK_EQ(
26754 : 4,
26755 : contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
26756 :
26757 5 : CHECK_EQ(2U, map->Size());
26758 :
26759 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26760 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26761 :
26762 15 : CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26763 10 : CHECK(!map->Has(env.local(), map).FromJust());
26764 :
26765 20 : CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
26766 : .ToLocalChecked()
26767 : ->Int32Value(env.local())
26768 : .FromJust());
26769 20 : CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
26770 : .ToLocalChecked()
26771 : ->Int32Value(env.local())
26772 : .FromJust());
26773 :
26774 15 : CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
26775 : .ToLocalChecked()
26776 : ->IsUndefined());
26777 :
26778 10 : CHECK(!map->Set(env.local(), map, map).IsEmpty());
26779 5 : CHECK_EQ(3U, map->Size());
26780 10 : CHECK(map->Has(env.local(), map).FromJust());
26781 :
26782 10 : CHECK(map->Delete(env.local(), map).FromJust());
26783 5 : CHECK_EQ(2U, map->Size());
26784 10 : CHECK(!map->Has(env.local(), map).FromJust());
26785 10 : CHECK(!map->Delete(env.local(), map).FromJust());
26786 :
26787 5 : map->Clear();
26788 10 : CHECK_EQ(0U, map->Size());
26789 5 : }
26790 :
26791 :
26792 28342 : TEST(Set) {
26793 5 : v8::Isolate* isolate = CcTest::isolate();
26794 5 : v8::HandleScope handle_scope(isolate);
26795 10 : LocalContext env;
26796 :
26797 5 : v8::Local<v8::Set> set = v8::Set::New(isolate);
26798 5 : CHECK(set->IsObject());
26799 5 : CHECK(set->IsSet());
26800 10 : CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
26801 5 : CHECK_EQ(0U, set->Size());
26802 :
26803 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
26804 5 : CHECK(val->IsSet());
26805 : set = v8::Local<v8::Set>::Cast(val);
26806 5 : CHECK_EQ(2U, set->Size());
26807 :
26808 5 : v8::Local<v8::Array> keys = set->AsArray();
26809 5 : CHECK_EQ(2U, keys->Length());
26810 10 : CHECK_EQ(1,
26811 : keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26812 10 : CHECK_EQ(2,
26813 : keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26814 :
26815 5 : CHECK_EQ(2U, set->Size());
26816 :
26817 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26818 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26819 :
26820 15 : CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26821 10 : CHECK(!set->Has(env.local(), set).FromJust());
26822 :
26823 10 : CHECK(!set->Add(env.local(), set).IsEmpty());
26824 5 : CHECK_EQ(3U, set->Size());
26825 10 : CHECK(set->Has(env.local(), set).FromJust());
26826 :
26827 10 : CHECK(set->Delete(env.local(), set).FromJust());
26828 5 : CHECK_EQ(2U, set->Size());
26829 10 : CHECK(!set->Has(env.local(), set).FromJust());
26830 10 : CHECK(!set->Delete(env.local(), set).FromJust());
26831 :
26832 5 : set->Clear();
26833 10 : CHECK_EQ(0U, set->Size());
26834 5 : }
26835 :
26836 28342 : TEST(SetDeleteThenAsArray) {
26837 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26838 5 : v8::Isolate* isolate = CcTest::isolate();
26839 5 : v8::HandleScope handle_scope(isolate);
26840 10 : LocalContext env;
26841 :
26842 : // make a Set
26843 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
26844 : v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
26845 5 : CHECK_EQ(3U, set->Size());
26846 :
26847 : // delete the "middle" element (using AsArray to
26848 : // determine which element is the "middle" element)
26849 5 : v8::Local<v8::Array> array1 = set->AsArray();
26850 5 : CHECK_EQ(3U, array1->Length());
26851 15 : CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
26852 : .FromJust());
26853 :
26854 : // make sure there are no undefined values when we convert to an array again.
26855 5 : v8::Local<v8::Array> array2 = set->AsArray();
26856 5 : uint32_t length = array2->Length();
26857 5 : CHECK_EQ(2U, length);
26858 10 : for (uint32_t i = 0; i < length; i++) {
26859 20 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26860 5 : }
26861 5 : }
26862 :
26863 28342 : TEST(MapDeleteThenAsArray) {
26864 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26865 5 : v8::Isolate* isolate = CcTest::isolate();
26866 5 : v8::HandleScope handle_scope(isolate);
26867 10 : LocalContext env;
26868 :
26869 : // make a Map
26870 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
26871 : v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
26872 5 : CHECK_EQ(3U, map->Size());
26873 :
26874 : // delete the "middle" element (using AsArray to
26875 : // determine which element is the "middle" element)
26876 5 : v8::Local<v8::Array> array1 = map->AsArray();
26877 5 : CHECK_EQ(6U, array1->Length());
26878 : // Map::AsArray returns a flat array, so the second key is at index 2.
26879 10 : v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
26880 10 : CHECK(map->Delete(env.local(), key).FromJust());
26881 :
26882 : // make sure there are no undefined values when we convert to an array again.
26883 5 : v8::Local<v8::Array> array2 = map->AsArray();
26884 5 : uint32_t length = array2->Length();
26885 5 : CHECK_EQ(4U, length);
26886 20 : for (uint32_t i = 0; i < length; i++) {
26887 40 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26888 5 : }
26889 5 : }
26890 :
26891 28342 : TEST(CompatibleReceiverCheckOnCachedICHandler) {
26892 5 : v8::Isolate* isolate = CcTest::isolate();
26893 5 : v8::HandleScope scope(isolate);
26894 5 : v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
26895 5 : v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
26896 : auto returns_42 =
26897 5 : v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
26898 15 : parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
26899 5 : v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
26900 5 : child->Inherit(parent);
26901 10 : LocalContext env;
26902 30 : CHECK(env->Global()
26903 : ->Set(env.local(), v8_str("Child"),
26904 : child->GetFunction(env.local()).ToLocalChecked())
26905 : .FromJust());
26906 :
26907 : // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
26908 : CompileRun(
26909 : "var real = new Child();\n"
26910 : "for (var i = 0; i < 3; ++i) {\n"
26911 : " real.age;\n"
26912 : "}\n");
26913 :
26914 : // Check that the cached stub is never used.
26915 : ExpectInt32(
26916 : "var fake = Object.create(Child.prototype);\n"
26917 : "var result = 0;\n"
26918 : "function test(d) {\n"
26919 : " if (d == 3) return;\n"
26920 : " try {\n"
26921 : " fake.age;\n"
26922 : " result = 1;\n"
26923 : " } catch (e) {\n"
26924 : " }\n"
26925 : " test(d+1);\n"
26926 : "}\n"
26927 : "test(0);\n"
26928 : "result;\n",
26929 10 : 0);
26930 5 : }
26931 :
26932 28343 : THREADED_TEST(ReceiverConversionForAccessors) {
26933 6 : LocalContext env;
26934 6 : v8::Isolate* isolate = CcTest::isolate();
26935 12 : v8::HandleScope scope(isolate);
26936 : Local<v8::FunctionTemplate> acc =
26937 6 : v8::FunctionTemplate::New(isolate, Returns42);
26938 42 : CHECK(env->Global()
26939 : ->Set(env.local(), v8_str("acc"),
26940 : acc->GetFunction(env.local()).ToLocalChecked())
26941 : .FromJust());
26942 :
26943 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
26944 12 : templ->SetAccessorProperty(v8_str("acc"), acc, acc);
26945 6 : Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
26946 :
26947 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
26948 6 : CHECK(CompileRun("(p.acc == 42)")->BooleanValue(isolate));
26949 6 : CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(isolate));
26950 :
26951 6 : CHECK(!CompileRun("Number.prototype.__proto__ = p;"
26952 : "var a = 1;")
26953 : .IsEmpty());
26954 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26955 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26956 :
26957 6 : CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
26958 : "var a = true;")
26959 : .IsEmpty());
26960 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26961 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26962 :
26963 6 : CHECK(!CompileRun("String.prototype.__proto__ = p;"
26964 : "var a = 'foo';")
26965 : .IsEmpty());
26966 6 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26967 6 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26968 :
26969 6 : CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(isolate));
26970 6 : CHECK(CompileRun("acc.call(true)==42")->BooleanValue(isolate));
26971 6 : CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(isolate));
26972 6 : CHECK(CompileRun("acc.call(null) == 42")->BooleanValue(isolate));
26973 12 : CHECK(CompileRun("acc.call(undefined) == 42")->BooleanValue(isolate));
26974 6 : }
26975 :
26976 5 : class FutexInterruptionThread : public v8::base::Thread {
26977 : public:
26978 : explicit FutexInterruptionThread(v8::Isolate* isolate)
26979 5 : : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
26980 :
26981 5 : void Run() override {
26982 : // Wait a bit before terminating.
26983 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
26984 5 : isolate_->TerminateExecution();
26985 5 : }
26986 :
26987 : private:
26988 : v8::Isolate* isolate_;
26989 : };
26990 :
26991 :
26992 28342 : TEST(FutexInterruption) {
26993 5 : i::FLAG_harmony_sharedarraybuffer = true;
26994 5 : v8::Isolate* isolate = CcTest::isolate();
26995 5 : v8::HandleScope scope(isolate);
26996 10 : LocalContext env;
26997 :
26998 : FutexInterruptionThread timeout_thread(isolate);
26999 :
27000 10 : v8::TryCatch try_catch(CcTest::isolate());
27001 5 : timeout_thread.Start();
27002 :
27003 : CompileRun(
27004 : "var ab = new SharedArrayBuffer(4);"
27005 : "var i32a = new Int32Array(ab);"
27006 : "Atomics.wait(i32a, 0, 0);");
27007 5 : CHECK(try_catch.HasTerminated());
27008 10 : timeout_thread.Join();
27009 5 : }
27010 :
27011 28343 : THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
27012 6 : i::FLAG_harmony_sharedarraybuffer = true;
27013 6 : LocalContext env;
27014 6 : v8::Isolate* isolate = env->GetIsolate();
27015 12 : v8::HandleScope handle_scope(isolate);
27016 :
27017 : const size_t ab_size = 1024;
27018 : Local<v8::SharedArrayBuffer> ab =
27019 6 : v8::SharedArrayBuffer::New(isolate, ab_size);
27020 12 : ScopedSharedArrayBufferContents contents(ab->Externalize());
27021 :
27022 : // Array buffers should have normal allocation mode.
27023 6 : CHECK_EQ(contents.AllocationMode(),
27024 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
27025 : // The allocation must contain the buffer (normally they will be equal, but
27026 : // this is not required by the contract).
27027 6 : CHECK_NOT_NULL(contents.AllocationBase());
27028 : const uintptr_t alloc =
27029 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
27030 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
27031 6 : CHECK_LE(alloc, data);
27032 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
27033 6 : }
27034 :
27035 : static int nb_uncaught_exception_callback_calls = 0;
27036 :
27037 :
27038 5 : bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
27039 5 : ++nb_uncaught_exception_callback_calls;
27040 5 : return false;
27041 : }
27042 :
27043 :
27044 28342 : TEST(AbortOnUncaughtExceptionNoAbort) {
27045 5 : v8::Isolate* isolate = CcTest::isolate();
27046 5 : v8::HandleScope handle_scope(isolate);
27047 : v8::Local<v8::ObjectTemplate> global_template =
27048 5 : v8::ObjectTemplate::New(isolate);
27049 10 : LocalContext env(nullptr, global_template);
27050 :
27051 5 : i::FLAG_abort_on_uncaught_exception = true;
27052 5 : isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
27053 :
27054 : CompileRun("function boom() { throw new Error(\"boom\") }");
27055 :
27056 5 : v8::Local<v8::Object> global_object = env->Global();
27057 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
27058 20 : global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
27059 :
27060 10 : CHECK(foo->Call(env.local(), global_object, 0, nullptr).IsEmpty());
27061 :
27062 10 : CHECK_EQ(1, nb_uncaught_exception_callback_calls);
27063 5 : }
27064 :
27065 :
27066 28342 : TEST(AccessCheckedIsConcatSpreadable) {
27067 5 : v8::Isolate* isolate = CcTest::isolate();
27068 5 : HandleScope scope(isolate);
27069 10 : LocalContext env;
27070 :
27071 : // Object with access check
27072 5 : Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
27073 5 : spreadable_template->SetAccessCheckCallback(AccessBlocker);
27074 : spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
27075 10 : v8::Boolean::New(isolate, true));
27076 : Local<Object> object =
27077 5 : spreadable_template->NewInstance(env.local()).ToLocalChecked();
27078 :
27079 5 : allowed_access = true;
27080 25 : CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
27081 15 : object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
27082 15 : object->Set(env.local(), 0U, v8_str("a")).FromJust();
27083 15 : object->Set(env.local(), 1U, v8_str("b")).FromJust();
27084 :
27085 : // Access check is allowed, and the object is spread
27086 : CompileRun("var result = [].concat(object)");
27087 : ExpectTrue("Array.isArray(result)");
27088 5 : ExpectString("result[0]", "a");
27089 5 : ExpectString("result[1]", "b");
27090 : ExpectTrue("result.length === 2");
27091 : ExpectTrue("object[Symbol.isConcatSpreadable]");
27092 :
27093 : // If access check fails, the value of @@isConcatSpreadable is ignored
27094 5 : allowed_access = false;
27095 : CompileRun("var result = [].concat(object)");
27096 : ExpectTrue("Array.isArray(result)");
27097 : ExpectTrue("result[0] === object");
27098 : ExpectTrue("result.length === 1");
27099 5 : ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
27100 5 : }
27101 :
27102 :
27103 28342 : TEST(AccessCheckedToStringTag) {
27104 5 : v8::Isolate* isolate = CcTest::isolate();
27105 5 : HandleScope scope(isolate);
27106 10 : LocalContext env;
27107 :
27108 : // Object with access check
27109 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
27110 5 : object_template->SetAccessCheckCallback(AccessBlocker);
27111 : Local<Object> object =
27112 5 : object_template->NewInstance(env.local()).ToLocalChecked();
27113 :
27114 5 : allowed_access = true;
27115 25 : env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
27116 20 : object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
27117 10 : .FromJust();
27118 :
27119 : // Access check is allowed, and the toStringTag is read
27120 : CompileRun("var result = Object.prototype.toString.call(object)");
27121 5 : ExpectString("result", "[object hello]");
27122 5 : ExpectString("object[Symbol.toStringTag]", "hello");
27123 :
27124 : // ToString through the API should succeed too.
27125 : String::Utf8Value result_allowed(
27126 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
27127 5 : CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
27128 :
27129 : // If access check fails, the value of @@toStringTag is ignored
27130 5 : allowed_access = false;
27131 : CompileRun("var result = Object.prototype.toString.call(object)");
27132 5 : ExpectString("result", "[object Object]");
27133 : ExpectTrue("object[Symbol.toStringTag] === undefined");
27134 :
27135 : // ToString through the API should also fail.
27136 : String::Utf8Value result_denied(
27137 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
27138 10 : CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
27139 5 : }
27140 :
27141 28342 : TEST(TemplateIteratorPrototypeIntrinsics) {
27142 5 : v8::Isolate* isolate = CcTest::isolate();
27143 5 : v8::HandleScope scope(isolate);
27144 10 : LocalContext env;
27145 :
27146 : // Object templates.
27147 : {
27148 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
27149 : object_template->SetIntrinsicDataProperty(v8_str("iter_proto"),
27150 10 : v8::kIteratorPrototype);
27151 : Local<Object> object =
27152 5 : object_template->NewInstance(env.local()).ToLocalChecked();
27153 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
27154 : ExpectTrue("obj.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
27155 : }
27156 : // Setting %IteratorProto% on the function object's prototype template.
27157 : {
27158 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
27159 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
27160 15 : v8_str("iter_proto"), v8::kIteratorPrototype);
27161 : Local<Function> func1 =
27162 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27163 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
27164 : Local<Function> func2 =
27165 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27166 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
27167 : ExpectTrue(
27168 : "func1.prototype.iter_proto === "
27169 : "[][Symbol.iterator]().__proto__.__proto__");
27170 : ExpectTrue(
27171 : "func2.prototype.iter_proto === "
27172 : "[][Symbol.iterator]().__proto__.__proto__");
27173 : ExpectTrue("func1.prototype.iter_proto === func2.prototype.iter_proto");
27174 :
27175 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
27176 25 : CHECK(env->Global()
27177 : ->Set(env.local(), v8_str("instance1"), instance1)
27178 : .FromJust());
27179 : ExpectFalse("instance1.hasOwnProperty('iter_proto')");
27180 : ExpectTrue("'iter_proto' in instance1.__proto__");
27181 : ExpectTrue(
27182 : "instance1.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
27183 : }
27184 : // Put %IteratorProto% in a function object's inheritance chain.
27185 : {
27186 : Local<FunctionTemplate> parent_template =
27187 5 : v8::FunctionTemplate::New(isolate);
27188 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
27189 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
27190 10 : v8::kIteratorPrototype);
27191 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
27192 5 : func_template->Inherit(parent_template);
27193 :
27194 : Local<Function> func =
27195 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27196 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
27197 : ExpectTrue(
27198 : "func.prototype.__proto__ === "
27199 : "[][Symbol.iterator]().__proto__.__proto__");
27200 :
27201 : Local<Object> func_instance =
27202 5 : func->NewInstance(env.local()).ToLocalChecked();
27203 25 : CHECK(env->Global()
27204 : ->Set(env.local(), v8_str("instance"), func_instance)
27205 : .FromJust());
27206 : ExpectTrue(
27207 : "instance.__proto__.__proto__ === "
27208 : "[][Symbol.iterator]().__proto__.__proto__");
27209 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
27210 5 : }
27211 5 : }
27212 :
27213 28342 : TEST(TemplateErrorPrototypeIntrinsics) {
27214 5 : v8::Isolate* isolate = CcTest::isolate();
27215 5 : v8::HandleScope scope(isolate);
27216 10 : LocalContext env;
27217 :
27218 : // Object templates.
27219 : {
27220 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
27221 : object_template->SetIntrinsicDataProperty(v8_str("error_proto"),
27222 10 : v8::kErrorPrototype);
27223 : Local<Object> object =
27224 5 : object_template->NewInstance(env.local()).ToLocalChecked();
27225 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
27226 : ExpectTrue("obj.error_proto === Error.prototype");
27227 5 : Local<Value> error = v8::Exception::Error(v8_str("error message"));
27228 25 : CHECK(env->Global()->Set(env.local(), v8_str("err"), error).FromJust());
27229 : ExpectTrue("obj.error_proto === Object.getPrototypeOf(err)");
27230 : }
27231 : // Setting %ErrorPrototype% on the function object's prototype template.
27232 : {
27233 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
27234 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
27235 15 : v8_str("error_proto"), v8::kErrorPrototype);
27236 : Local<Function> func1 =
27237 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27238 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
27239 : Local<Function> func2 =
27240 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27241 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
27242 : ExpectTrue("func1.prototype.error_proto === Error.prototype");
27243 : ExpectTrue("func2.prototype.error_proto === Error.prototype");
27244 : ExpectTrue("func1.prototype.error_proto === func2.prototype.error_proto");
27245 :
27246 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
27247 25 : CHECK(env->Global()
27248 : ->Set(env.local(), v8_str("instance1"), instance1)
27249 : .FromJust());
27250 : ExpectFalse("instance1.hasOwnProperty('error_proto')");
27251 : ExpectTrue("'error_proto' in instance1.__proto__");
27252 : ExpectTrue("instance1.error_proto === Error.prototype");
27253 : }
27254 : // Put %ErrorPrototype% in a function object's inheritance chain.
27255 : {
27256 : Local<FunctionTemplate> parent_template =
27257 5 : v8::FunctionTemplate::New(isolate);
27258 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
27259 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
27260 10 : v8::kErrorPrototype);
27261 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
27262 5 : func_template->Inherit(parent_template);
27263 :
27264 : Local<Function> func =
27265 5 : func_template->GetFunction(env.local()).ToLocalChecked();
27266 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
27267 : ExpectTrue("func.prototype.__proto__ === Error.prototype");
27268 :
27269 : Local<Object> func_instance =
27270 5 : func->NewInstance(env.local()).ToLocalChecked();
27271 25 : CHECK(env->Global()
27272 : ->Set(env.local(), v8_str("instance"), func_instance)
27273 : .FromJust());
27274 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
27275 : // Now let's check if %ErrorPrototype% properties are in the instance.
27276 : ExpectTrue("'constructor' in instance");
27277 : ExpectTrue("'message' in instance");
27278 : ExpectTrue("'name' in instance");
27279 : ExpectTrue("'toString' in instance");
27280 5 : }
27281 5 : }
27282 :
27283 28342 : TEST(ObjectTemplateArrayProtoIntrinsics) {
27284 5 : v8::Isolate* isolate = CcTest::isolate();
27285 5 : v8::HandleScope scope(isolate);
27286 10 : LocalContext env;
27287 :
27288 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
27289 : object_template->SetIntrinsicDataProperty(v8_str("prop_entries"),
27290 10 : v8::kArrayProto_entries);
27291 : object_template->SetIntrinsicDataProperty(v8_str("prop_forEach"),
27292 10 : v8::kArrayProto_forEach);
27293 : object_template->SetIntrinsicDataProperty(v8_str("prop_keys"),
27294 10 : v8::kArrayProto_keys);
27295 : object_template->SetIntrinsicDataProperty(v8_str("prop_values"),
27296 10 : v8::kArrayProto_values);
27297 : Local<Object> object =
27298 5 : object_template->NewInstance(env.local()).ToLocalChecked();
27299 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
27300 :
27301 : const struct {
27302 : const char* const object_property_name;
27303 : const char* const array_property_name;
27304 : } intrinsics_comparisons[] = {
27305 : {"prop_entries", "Array.prototype.entries"},
27306 : {"prop_forEach", "Array.prototype.forEach"},
27307 : {"prop_keys", "Array.prototype.keys"},
27308 : {"prop_values", "Array.prototype[Symbol.iterator]"},
27309 5 : };
27310 :
27311 25 : for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) {
27312 : i::ScopedVector<char> test_string(64);
27313 :
27314 : i::SNPrintF(test_string, "typeof obj1.%s",
27315 20 : intrinsics_comparisons[i].object_property_name);
27316 20 : ExpectString(test_string.start(), "function");
27317 :
27318 : i::SNPrintF(test_string, "obj1.%s === %s",
27319 : intrinsics_comparisons[i].object_property_name,
27320 20 : intrinsics_comparisons[i].array_property_name);
27321 : ExpectTrue(test_string.start());
27322 :
27323 : i::SNPrintF(test_string, "obj1.%s = 42",
27324 20 : intrinsics_comparisons[i].object_property_name);
27325 : CompileRun(test_string.start());
27326 :
27327 : i::SNPrintF(test_string, "obj1.%s === %s",
27328 : intrinsics_comparisons[i].object_property_name,
27329 20 : intrinsics_comparisons[i].array_property_name);
27330 : ExpectFalse(test_string.start());
27331 :
27332 : i::SNPrintF(test_string, "typeof obj1.%s",
27333 20 : intrinsics_comparisons[i].object_property_name);
27334 20 : ExpectString(test_string.start(), "number");
27335 5 : }
27336 5 : }
27337 :
27338 28342 : TEST(ObjectTemplatePerContextIntrinsics) {
27339 5 : v8::Isolate* isolate = CcTest::isolate();
27340 5 : v8::HandleScope scope(isolate);
27341 10 : LocalContext env;
27342 :
27343 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
27344 : object_template->SetIntrinsicDataProperty(v8_str("values"),
27345 10 : v8::kArrayProto_values);
27346 : Local<Object> object =
27347 5 : object_template->NewInstance(env.local()).ToLocalChecked();
27348 :
27349 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
27350 5 : ExpectString("typeof obj1.values", "function");
27351 :
27352 : auto values = Local<Function>::Cast(
27353 15 : object->Get(env.local(), v8_str("values")).ToLocalChecked());
27354 5 : auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
27355 10 : auto ctx = v8::Utils::OpenHandle(*env.local());
27356 20 : CHECK_EQ(*fn->GetCreationContext(), *ctx);
27357 :
27358 : {
27359 5 : LocalContext env2;
27360 : Local<Object> object2 =
27361 5 : object_template->NewInstance(env2.local()).ToLocalChecked();
27362 25 : CHECK(
27363 : env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
27364 5 : ExpectString("typeof obj2.values", "function");
27365 25 : CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
27366 : *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
27367 :
27368 : auto values2 = Local<Function>::Cast(
27369 15 : object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
27370 5 : auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
27371 10 : auto ctx2 = v8::Utils::OpenHandle(*env2.local());
27372 20 : CHECK_EQ(*fn2->GetCreationContext(), *ctx2);
27373 5 : }
27374 5 : }
27375 :
27376 :
27377 28342 : TEST(Proxy) {
27378 5 : LocalContext context;
27379 5 : v8::Isolate* isolate = CcTest::isolate();
27380 10 : v8::HandleScope scope(isolate);
27381 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
27382 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
27383 :
27384 : v8::Local<v8::Proxy> proxy =
27385 5 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
27386 5 : CHECK(proxy->IsProxy());
27387 5 : CHECK(!target->IsProxy());
27388 5 : CHECK(!proxy->IsRevoked());
27389 10 : CHECK(proxy->GetTarget()->SameValue(target));
27390 10 : CHECK(proxy->GetHandler()->SameValue(handler));
27391 :
27392 5 : proxy->Revoke();
27393 5 : CHECK(proxy->IsProxy());
27394 5 : CHECK(!target->IsProxy());
27395 5 : CHECK(proxy->IsRevoked());
27396 10 : CHECK(proxy->GetTarget()->IsNull());
27397 15 : CHECK(proxy->GetHandler()->IsNull());
27398 5 : }
27399 :
27400 10 : WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
27401 : v8::Isolate* isolate, WeakCallCounter* counter) {
27402 : v8::Locker locker(isolate);
27403 20 : LocalContext env;
27404 20 : HandleScope scope(isolate);
27405 : WeakCallCounterAndPersistent<Value>* val =
27406 10 : new WeakCallCounterAndPersistent<Value>(counter);
27407 20 : val->handle.Reset(isolate, Object::New(isolate));
27408 : val->handle.SetWeak(val, &WeakPointerCallback,
27409 : v8::WeakCallbackType::kParameter);
27410 10 : return val;
27411 : }
27412 :
27413 5 : class MemoryPressureThread : public v8::base::Thread {
27414 : public:
27415 : explicit MemoryPressureThread(v8::Isolate* isolate,
27416 : v8::MemoryPressureLevel level)
27417 : : Thread(Options("MemoryPressureThread")),
27418 : isolate_(isolate),
27419 5 : level_(level) {}
27420 :
27421 5 : void Run() override { isolate_->MemoryPressureNotification(level_); }
27422 :
27423 : private:
27424 : v8::Isolate* isolate_;
27425 : v8::MemoryPressureLevel level_;
27426 : };
27427 :
27428 28342 : TEST(MemoryPressure) {
27429 5 : if (v8::internal::FLAG_optimize_for_size) return;
27430 5 : v8::Isolate* isolate = CcTest::isolate();
27431 : WeakCallCounter counter(1234);
27432 :
27433 : // Check that critical memory pressure notification sets GC interrupt.
27434 5 : auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
27435 5 : CHECK(!v8::Locker::IsLocked(isolate));
27436 : {
27437 : v8::Locker locker(isolate);
27438 10 : v8::HandleScope scope(isolate);
27439 10 : LocalContext env;
27440 : MemoryPressureThread memory_pressure_thread(
27441 : isolate, v8::MemoryPressureLevel::kCritical);
27442 5 : memory_pressure_thread.Start();
27443 5 : memory_pressure_thread.Join();
27444 : // This should trigger GC.
27445 5 : CHECK_EQ(0, counter.NumberOfWeakCalls());
27446 : CompileRun("(function noop() { return 0; })()");
27447 10 : CHECK_EQ(1, counter.NumberOfWeakCalls());
27448 : }
27449 5 : delete garbage;
27450 : // Check that critical memory pressure notification triggers GC.
27451 5 : garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
27452 : {
27453 : v8::Locker locker(isolate);
27454 : // If isolate is locked, memory pressure notification should trigger GC.
27455 5 : CHECK_EQ(1, counter.NumberOfWeakCalls());
27456 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
27457 5 : CHECK_EQ(2, counter.NumberOfWeakCalls());
27458 : }
27459 5 : delete garbage;
27460 : // Check that moderate memory pressure notification sets GC into memory
27461 : // optimizing mode.
27462 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
27463 5 : CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
27464 : // Check that disabling memory pressure returns GC into normal mode.
27465 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
27466 5 : CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
27467 : }
27468 :
27469 28342 : TEST(SetIntegrityLevel) {
27470 5 : LocalContext context;
27471 5 : v8::Isolate* isolate = CcTest::isolate();
27472 10 : v8::HandleScope scope(isolate);
27473 :
27474 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
27475 25 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
27476 :
27477 : v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
27478 5 : CHECK(!is_frozen->BooleanValue(isolate));
27479 :
27480 10 : CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
27481 : .FromJust());
27482 :
27483 : is_frozen = CompileRun("Object.isFrozen(o)");
27484 10 : CHECK(is_frozen->BooleanValue(isolate));
27485 5 : }
27486 :
27487 28342 : TEST(PrivateForApiIsNumber) {
27488 5 : LocalContext context;
27489 5 : v8::Isolate* isolate = CcTest::isolate();
27490 10 : v8::HandleScope scope(isolate);
27491 :
27492 : // Shouldn't crash.
27493 10 : v8::Private::ForApi(isolate, v8_str("42"));
27494 5 : }
27495 :
27496 28343 : THREADED_TEST(ImmutableProto) {
27497 6 : LocalContext context;
27498 6 : v8::Isolate* isolate = context->GetIsolate();
27499 12 : v8::HandleScope handle_scope(isolate);
27500 :
27501 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
27502 12 : templ->InstanceTemplate()->SetImmutableProto();
27503 :
27504 6 : Local<v8::Object> object = templ->GetFunction(context.local())
27505 6 : .ToLocalChecked()
27506 6 : ->NewInstance(context.local())
27507 : .ToLocalChecked();
27508 :
27509 : // Look up the prototype
27510 : Local<v8::Value> original_proto =
27511 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
27512 :
27513 : // Setting the prototype (e.g., to null) throws
27514 12 : CHECK(object->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
27515 :
27516 : // The original prototype is still there
27517 : Local<Value> new_proto =
27518 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
27519 6 : CHECK(new_proto->IsObject());
27520 12 : CHECK(new_proto.As<v8::Object>()
27521 : ->Equals(context.local(), original_proto)
27522 6 : .FromJust());
27523 6 : }
27524 :
27525 : Local<v8::Context> call_eval_context;
27526 : Local<v8::Function> call_eval_bound_function;
27527 :
27528 10 : static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
27529 : v8::Context::Scope scope(call_eval_context);
27530 : args.GetReturnValue().Set(
27531 : call_eval_bound_function
27532 10 : ->Call(call_eval_context, call_eval_context->Global(), 0, nullptr)
27533 5 : .ToLocalChecked());
27534 5 : }
27535 :
27536 28342 : TEST(CrossActivationEval) {
27537 5 : LocalContext env;
27538 5 : v8::Isolate* isolate = env->GetIsolate();
27539 10 : v8::HandleScope scope(isolate);
27540 : {
27541 5 : call_eval_context = v8::Context::New(isolate);
27542 : v8::Context::Scope scope(call_eval_context);
27543 : call_eval_bound_function =
27544 5 : Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
27545 : }
27546 : env->Global()
27547 : ->Set(env.local(), v8_str("CallEval"),
27548 5 : v8::FunctionTemplate::New(isolate, CallEval)
27549 15 : ->GetFunction(env.local())
27550 25 : .ToLocalChecked())
27551 10 : .FromJust();
27552 : Local<Value> result = CompileRun("CallEval();");
27553 5 : CHECK(result->IsInt32());
27554 15 : CHECK_EQ(1, result->Int32Value(env.local()).FromJust());
27555 5 : }
27556 :
27557 28342 : TEST(EvalInAccessCheckedContext) {
27558 5 : v8::Isolate* isolate = CcTest::isolate();
27559 5 : v8::HandleScope scope(isolate);
27560 :
27561 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
27562 :
27563 5 : obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
27564 :
27565 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
27566 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, obj_template);
27567 :
27568 5 : Local<Value> foo = v8_str("foo");
27569 5 : Local<Value> bar = v8_str("bar");
27570 :
27571 : // Set to different domains.
27572 5 : context0->SetSecurityToken(foo);
27573 5 : context1->SetSecurityToken(bar);
27574 :
27575 : // Set up function in context0 that uses eval from context0.
27576 5 : context0->Enter();
27577 : v8::Local<v8::Value> fun = CompileRun(
27578 : "var x = 42;"
27579 : "(function() {"
27580 : " var e = eval;"
27581 : " return function(s) { return e(s); }"
27582 5 : "})()");
27583 5 : context0->Exit();
27584 :
27585 : // Put the function into context1 and call it. Since the access check
27586 : // callback always returns true, the call succeeds even though the tokens
27587 : // are different.
27588 5 : context1->Enter();
27589 20 : context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
27590 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
27591 10 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
27592 5 : context1->Exit();
27593 5 : }
27594 :
27595 28343 : THREADED_TEST(ImmutableProtoWithParent) {
27596 6 : LocalContext context;
27597 6 : v8::Isolate* isolate = context->GetIsolate();
27598 12 : v8::HandleScope handle_scope(isolate);
27599 :
27600 6 : Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
27601 :
27602 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
27603 6 : templ->Inherit(parent);
27604 12 : templ->PrototypeTemplate()->SetImmutableProto();
27605 :
27606 : Local<v8::Function> function =
27607 6 : templ->GetFunction(context.local()).ToLocalChecked();
27608 : Local<v8::Object> instance =
27609 6 : function->NewInstance(context.local()).ToLocalChecked();
27610 : Local<v8::Object> prototype =
27611 18 : instance->Get(context.local(), v8_str("__proto__"))
27612 6 : .ToLocalChecked()
27613 6 : ->ToObject(context.local())
27614 6 : .ToLocalChecked();
27615 :
27616 : // Look up the prototype
27617 : Local<v8::Value> original_proto =
27618 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
27619 :
27620 : // Setting the prototype (e.g., to null) throws
27621 12 : CHECK(
27622 : prototype->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
27623 :
27624 : // The original prototype is still there
27625 : Local<Value> new_proto =
27626 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
27627 6 : CHECK(new_proto->IsObject());
27628 12 : CHECK(new_proto.As<v8::Object>()
27629 : ->Equals(context.local(), original_proto)
27630 6 : .FromJust());
27631 6 : }
27632 :
27633 28342 : TEST(InternalFieldsOnGlobalProxy) {
27634 5 : v8::Isolate* isolate = CcTest::isolate();
27635 5 : v8::HandleScope scope(isolate);
27636 :
27637 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
27638 5 : obj_template->SetInternalFieldCount(1);
27639 :
27640 5 : v8::Local<v8::Context> context = Context::New(isolate, nullptr, obj_template);
27641 5 : v8::Local<v8::Object> global = context->Global();
27642 5 : CHECK_EQ(1, global->InternalFieldCount());
27643 5 : }
27644 :
27645 28343 : THREADED_TEST(ImmutableProtoGlobal) {
27646 6 : v8::Isolate* isolate = CcTest::isolate();
27647 6 : v8::HandleScope handle_scope(isolate);
27648 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
27649 6 : global_template->SetImmutableProto();
27650 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
27651 : Context::Scope context_scope(context);
27652 : v8::Local<Value> result = CompileRun(
27653 : "global = this;"
27654 : "(function() {"
27655 : " try {"
27656 : " global.__proto__ = {};"
27657 : " return 0;"
27658 : " } catch (e) {"
27659 : " return 1;"
27660 : " }"
27661 : "})()");
27662 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 1))
27663 6 : .FromJust());
27664 6 : }
27665 :
27666 28343 : THREADED_TEST(MutableProtoGlobal) {
27667 6 : v8::Isolate* isolate = CcTest::isolate();
27668 6 : v8::HandleScope handle_scope(isolate);
27669 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
27670 6 : v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
27671 : Context::Scope context_scope(context);
27672 : v8::Local<Value> result = CompileRun(
27673 : "global = this;"
27674 : "(function() {"
27675 : " try {"
27676 : " global.__proto__ = {};"
27677 : " return 0;"
27678 : " } catch (e) {"
27679 : " return 1;"
27680 : " }"
27681 : "})()");
27682 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 0))
27683 6 : .FromJust());
27684 6 : }
27685 :
27686 28342 : TEST(InternalFieldsOnTypedArray) {
27687 5 : LocalContext env;
27688 5 : v8::Isolate* isolate = env->GetIsolate();
27689 10 : v8::HandleScope scope(isolate);
27690 5 : v8::Local<v8::Context> context = env.local();
27691 : Context::Scope context_scope(context);
27692 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27693 5 : v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
27694 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27695 10 : CHECK_EQ(static_cast<void*>(nullptr),
27696 : array->GetAlignedPointerFromInternalField(i));
27697 5 : }
27698 5 : }
27699 :
27700 28342 : TEST(InternalFieldsOnDataView) {
27701 5 : LocalContext env;
27702 5 : v8::Isolate* isolate = env->GetIsolate();
27703 10 : v8::HandleScope scope(isolate);
27704 5 : v8::Local<v8::Context> context = env.local();
27705 : Context::Scope context_scope(context);
27706 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27707 5 : v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
27708 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27709 10 : CHECK_EQ(static_cast<void*>(nullptr),
27710 : array->GetAlignedPointerFromInternalField(i));
27711 5 : }
27712 5 : }
27713 :
27714 28342 : TEST(SetPrototypeTemplate) {
27715 5 : LocalContext env;
27716 5 : v8::Isolate* isolate = env->GetIsolate();
27717 10 : v8::HandleScope scope(isolate);
27718 :
27719 5 : Local<FunctionTemplate> HTMLElementTemplate = FunctionTemplate::New(isolate);
27720 : Local<FunctionTemplate> HTMLImageElementTemplate =
27721 5 : FunctionTemplate::New(isolate);
27722 5 : HTMLImageElementTemplate->Inherit(HTMLElementTemplate);
27723 :
27724 5 : Local<FunctionTemplate> ImageTemplate = FunctionTemplate::New(isolate);
27725 5 : ImageTemplate->SetPrototypeProviderTemplate(HTMLImageElementTemplate);
27726 :
27727 : Local<Function> HTMLImageElement =
27728 5 : HTMLImageElementTemplate->GetFunction(env.local()).ToLocalChecked();
27729 : Local<Function> Image =
27730 5 : ImageTemplate->GetFunction(env.local()).ToLocalChecked();
27731 :
27732 25 : CHECK(env->Global()
27733 : ->Set(env.local(), v8_str("HTMLImageElement"), HTMLImageElement)
27734 : .FromJust());
27735 25 : CHECK(env->Global()->Set(env.local(), v8_str("Image"), Image).FromJust());
27736 :
27737 5 : ExpectTrue("Image.prototype === HTMLImageElement.prototype");
27738 5 : }
27739 :
27740 120 : void ensure_receiver_is_global_proxy(
27741 : v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
27742 240 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSGlobalProxy());
27743 120 : }
27744 :
27745 28343 : THREADED_TEST(GlobalAccessorInfo) {
27746 6 : v8::Isolate* isolate = CcTest::isolate();
27747 6 : v8::HandleScope scope(isolate);
27748 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
27749 : global_template->SetAccessor(
27750 : v8::String::NewFromUtf8(isolate, "prop", v8::NewStringType::kInternalized)
27751 : .ToLocalChecked(),
27752 12 : &ensure_receiver_is_global_proxy);
27753 12 : LocalContext env(nullptr, global_template);
27754 : CompileRun("for (var i = 0; i < 10; i++) this.prop");
27755 6 : CompileRun("for (var i = 0; i < 10; i++) prop");
27756 6 : }
27757 :
27758 28342 : TEST(DeterministicRandomNumberGeneration) {
27759 5 : v8::HandleScope scope(CcTest::isolate());
27760 :
27761 5 : int previous_seed = v8::internal::FLAG_random_seed;
27762 5 : v8::internal::FLAG_random_seed = 1234;
27763 :
27764 : double first_value;
27765 : double second_value;
27766 : {
27767 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27768 : Context::Scope context_scope(context);
27769 : v8::Local<Value> result = CompileRun("Math.random();");
27770 10 : first_value = result->ToNumber(context).ToLocalChecked()->Value();
27771 : }
27772 : {
27773 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27774 : Context::Scope context_scope(context);
27775 : v8::Local<Value> result = CompileRun("Math.random();");
27776 10 : second_value = result->ToNumber(context).ToLocalChecked()->Value();
27777 : }
27778 5 : CHECK_EQ(first_value, second_value);
27779 :
27780 5 : v8::internal::FLAG_random_seed = previous_seed;
27781 5 : }
27782 :
27783 28342 : UNINITIALIZED_TEST(AllowAtomicsWait) {
27784 : v8::Isolate::CreateParams create_params;
27785 5 : create_params.allow_atomics_wait = false;
27786 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27787 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
27788 10 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27789 : {
27790 5 : CHECK_EQ(false, i_isolate->allow_atomics_wait());
27791 5 : isolate->SetAllowAtomicsWait(true);
27792 5 : CHECK_EQ(true, i_isolate->allow_atomics_wait());
27793 : }
27794 5 : isolate->Dispose();
27795 5 : }
27796 :
27797 : enum ContextId { EnteredContext, CurrentContext };
27798 :
27799 20 : void CheckContexts(v8::Isolate* isolate) {
27800 60 : CHECK_EQ(CurrentContext, isolate->GetCurrentContext()
27801 : ->GetEmbedderData(1)
27802 : .As<v8::Integer>()
27803 : ->Value());
27804 60 : CHECK_EQ(EnteredContext, isolate->GetEnteredOrMicrotaskContext()
27805 : ->GetEmbedderData(1)
27806 : .As<v8::Integer>()
27807 : ->Value());
27808 20 : }
27809 :
27810 5 : void ContextCheckGetter(Local<String> name,
27811 : const v8::PropertyCallbackInfo<v8::Value>& info) {
27812 5 : CheckContexts(info.GetIsolate());
27813 : info.GetReturnValue().Set(true);
27814 5 : }
27815 :
27816 5 : void ContextCheckSetter(Local<String> name, Local<Value>,
27817 : const v8::PropertyCallbackInfo<void>& info) {
27818 5 : CheckContexts(info.GetIsolate());
27819 5 : }
27820 :
27821 20 : void ContextCheckToString(const v8::FunctionCallbackInfo<v8::Value>& info) {
27822 10 : CheckContexts(info.GetIsolate());
27823 10 : info.GetReturnValue().Set(v8_str("foo"));
27824 10 : }
27825 :
27826 28342 : TEST(CorrectEnteredContext) {
27827 5 : v8::HandleScope scope(CcTest::isolate());
27828 :
27829 10 : LocalContext currentContext;
27830 : currentContext->SetEmbedderData(
27831 10 : 1, v8::Integer::New(currentContext->GetIsolate(), CurrentContext));
27832 10 : LocalContext enteredContext;
27833 : enteredContext->SetEmbedderData(
27834 10 : 1, v8::Integer::New(enteredContext->GetIsolate(), EnteredContext));
27835 :
27836 5 : v8::Context::Scope contextScope(enteredContext.local());
27837 :
27838 : v8::Local<v8::ObjectTemplate> object_template =
27839 5 : ObjectTemplate::New(currentContext->GetIsolate());
27840 : object_template->SetAccessor(v8_str("p"), &ContextCheckGetter,
27841 5 : &ContextCheckSetter);
27842 :
27843 : v8::Local<v8::Object> object =
27844 5 : object_template->NewInstance(currentContext.local()).ToLocalChecked();
27845 :
27846 15 : object->Get(currentContext.local(), v8_str("p")).ToLocalChecked();
27847 15 : object->Set(currentContext.local(), v8_str("p"), v8_int(0)).FromJust();
27848 :
27849 : v8::Local<v8::Function> to_string =
27850 10 : v8::Function::New(currentContext.local(), ContextCheckToString)
27851 5 : .ToLocalChecked();
27852 :
27853 10 : to_string->Call(currentContext.local(), object, 0, nullptr).ToLocalChecked();
27854 :
27855 : object
27856 : ->CreateDataProperty(currentContext.local(), v8_str("toString"),
27857 15 : to_string)
27858 10 : .FromJust();
27859 :
27860 10 : object->ToString(currentContext.local()).ToLocalChecked();
27861 5 : }
27862 :
27863 5 : v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
27864 : Local<Context> context, Local<v8::ScriptOrModule> referrer,
27865 : Local<String> specifier) {
27866 5 : CHECK(!referrer.IsEmpty());
27867 : String::Utf8Value referrer_utf8(
27868 10 : context->GetIsolate(), Local<String>::Cast(referrer->GetResourceName()));
27869 5 : CHECK_EQ(0, strcmp("www.google.com", *referrer_utf8));
27870 15 : CHECK(referrer->GetHostDefinedOptions()
27871 : ->Get(context->GetIsolate(), 0)
27872 : ->IsSymbol());
27873 :
27874 5 : CHECK(!specifier.IsEmpty());
27875 10 : String::Utf8Value specifier_utf8(context->GetIsolate(), specifier);
27876 5 : CHECK_EQ(0, strcmp("index.js", *specifier_utf8));
27877 :
27878 : Local<v8::Promise::Resolver> resolver =
27879 5 : v8::Promise::Resolver::New(context).ToLocalChecked();
27880 5 : auto result = v8_str("hello world");
27881 10 : resolver->Resolve(context, result).ToChecked();
27882 10 : return resolver->GetPromise();
27883 : }
27884 :
27885 28342 : TEST(DynamicImport) {
27886 5 : i::FLAG_harmony_dynamic_import = true;
27887 5 : LocalContext context;
27888 5 : v8::Isolate* isolate = context->GetIsolate();
27889 10 : v8::HandleScope scope(isolate);
27890 :
27891 : isolate->SetHostImportModuleDynamicallyCallback(
27892 5 : HostImportModuleDynamicallyCallbackResolve);
27893 :
27894 10 : i::Handle<i::String> url(v8::Utils::OpenHandle(*v8_str("www.google.com")));
27895 10 : i::Handle<i::Object> specifier(v8::Utils::OpenHandle(*v8_str("index.js")));
27896 10 : i::Handle<i::String> result(v8::Utils::OpenHandle(*v8_str("hello world")));
27897 10 : i::Handle<i::String> source(v8::Utils::OpenHandle(*v8_str("foo")));
27898 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27899 5 : i::Handle<i::FixedArray> options = i_isolate->factory()->NewFixedArray(1);
27900 5 : i::Handle<i::Symbol> symbol = i_isolate->factory()->NewSymbol();
27901 10 : options->set(0, *symbol);
27902 5 : i::Handle<i::Script> referrer = i_isolate->factory()->NewScript(source);
27903 10 : referrer->set_name(*url);
27904 5 : referrer->set_host_defined_options(*options);
27905 : i::MaybeHandle<i::JSPromise> maybe_promise =
27906 5 : i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
27907 : i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
27908 5 : isolate->RunMicrotasks();
27909 15 : CHECK(result->Equals(i::String::cast(promise->result())));
27910 5 : }
27911 :
27912 5 : void HostInitializeImportMetaObjectCallbackStatic(Local<Context> context,
27913 : Local<Module> module,
27914 : Local<Object> meta) {
27915 5 : CHECK(!module.IsEmpty());
27916 :
27917 20 : meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
27918 5 : }
27919 :
27920 28342 : TEST(ImportMeta) {
27921 5 : i::FLAG_harmony_dynamic_import = true;
27922 5 : i::FLAG_harmony_import_meta = true;
27923 5 : LocalContext context;
27924 5 : v8::Isolate* isolate = context->GetIsolate();
27925 10 : v8::HandleScope scope(isolate);
27926 :
27927 : isolate->SetHostInitializeImportMetaObjectCallback(
27928 5 : HostInitializeImportMetaObjectCallbackStatic);
27929 :
27930 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27931 5 : Local<String> url = v8_str("www.google.com");
27932 5 : Local<String> source_text = v8_str("import.meta;");
27933 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27934 : Local<v8::Boolean>(), Local<v8::Integer>(),
27935 : Local<v8::Value>(), Local<v8::Boolean>(),
27936 : Local<v8::Boolean>(), True(isolate));
27937 : v8::ScriptCompiler::Source source(source_text, origin);
27938 : Local<Module> module =
27939 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27940 : i::Handle<i::Object> meta =
27941 : i_isolate->RunHostInitializeImportMetaObjectCallback(
27942 5 : v8::Utils::OpenHandle(*module));
27943 10 : CHECK(meta->IsJSObject());
27944 : Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
27945 15 : CHECK(meta_obj->Get(context.local(), v8_str("foo"))
27946 : .ToLocalChecked()
27947 : ->IsString());
27948 15 : CHECK(meta_obj->Get(context.local(), v8_str("zapp"))
27949 : .ToLocalChecked()
27950 : ->IsUndefined());
27951 :
27952 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27953 10 : .ToChecked();
27954 5 : Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
27955 10 : CHECK(result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
27956 5 : }
27957 :
27958 28342 : TEST(GetModuleNamespace) {
27959 5 : LocalContext context;
27960 5 : v8::Isolate* isolate = context->GetIsolate();
27961 10 : v8::HandleScope scope(isolate);
27962 :
27963 5 : Local<String> url = v8_str("www.google.com");
27964 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27965 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27966 : Local<v8::Boolean>(), Local<v8::Integer>(),
27967 : Local<v8::Value>(), Local<v8::Boolean>(),
27968 : Local<v8::Boolean>(), True(isolate));
27969 : v8::ScriptCompiler::Source source(source_text, origin);
27970 : Local<Module> module =
27971 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27972 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27973 10 : .ToChecked();
27974 5 : module->Evaluate(context.local()).ToLocalChecked();
27975 :
27976 5 : Local<Value> ns_val = module->GetModuleNamespace();
27977 5 : CHECK(ns_val->IsModuleNamespaceObject());
27978 : Local<Object> ns = ns_val.As<Object>();
27979 20 : CHECK(ns->Get(context.local(), v8_str("default"))
27980 : .ToLocalChecked()
27981 : ->StrictEquals(v8::Number::New(isolate, 5)));
27982 20 : CHECK(ns->Get(context.local(), v8_str("a"))
27983 : .ToLocalChecked()
27984 5 : ->StrictEquals(v8::Number::New(isolate, 10)));
27985 5 : }
27986 :
27987 28342 : TEST(ModuleGetUnboundModuleScript) {
27988 5 : LocalContext context;
27989 5 : v8::Isolate* isolate = context->GetIsolate();
27990 10 : v8::HandleScope scope(isolate);
27991 :
27992 5 : Local<String> url = v8_str("www.google.com");
27993 5 : Local<String> source_text = v8_str("export default 5; export const a = 10;");
27994 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27995 : Local<v8::Boolean>(), Local<v8::Integer>(),
27996 : Local<v8::Value>(), Local<v8::Boolean>(),
27997 : Local<v8::Boolean>(), True(isolate));
27998 : v8::ScriptCompiler::Source source(source_text, origin);
27999 : Local<Module> module =
28000 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
28001 : Local<v8::UnboundModuleScript> sfi_before_instantiation =
28002 5 : module->GetUnboundModuleScript();
28003 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
28004 10 : .ToChecked();
28005 : Local<v8::UnboundModuleScript> sfi_after_instantiation =
28006 5 : module->GetUnboundModuleScript();
28007 :
28008 : // Check object identity.
28009 : {
28010 : i::Handle<i::Object> s1 = v8::Utils::OpenHandle(*sfi_before_instantiation);
28011 : i::Handle<i::Object> s2 = v8::Utils::OpenHandle(*sfi_after_instantiation);
28012 15 : CHECK_EQ(*s1, *s2);
28013 5 : }
28014 5 : }
28015 :
28016 28342 : TEST(GlobalTemplateWithDoubleProperty) {
28017 5 : v8::Isolate* isolate = CcTest::isolate();
28018 5 : v8::HandleScope handle_scope(isolate);
28019 :
28020 5 : v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
28021 15 : global->Set(v8_str("double"), v8_num(3.14));
28022 :
28023 5 : v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
28024 :
28025 : v8::Context::Scope context_scope(context);
28026 :
28027 : Local<Value> result = CompileRun("double");
28028 5 : CHECK(result->IsNumber());
28029 15 : CheckDoubleEquals(3.14, result->NumberValue(context).ToChecked());
28030 5 : }
28031 :
28032 28342 : TEST(PrimitiveArray) {
28033 5 : v8::Isolate* isolate = CcTest::isolate();
28034 5 : v8::HandleScope scope(isolate);
28035 10 : LocalContext env;
28036 :
28037 : int length = 5;
28038 5 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 5));
28039 5 : CHECK_EQ(length, array->Length());
28040 :
28041 25 : for (int i = 0; i < length; i++) {
28042 25 : Local<v8::Primitive> item = array->Get(isolate, i);
28043 25 : CHECK(item->IsUndefined());
28044 : }
28045 :
28046 5 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
28047 5 : array->Set(isolate, 0, symbol);
28048 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
28049 :
28050 : Local<v8::String> string =
28051 : v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kInternalized)
28052 5 : .ToLocalChecked();
28053 5 : array->Set(isolate, 1, string);
28054 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
28055 10 : CHECK(array->Get(isolate, 1)->IsString());
28056 :
28057 5 : Local<v8::Number> num = v8::Number::New(env->GetIsolate(), 3.1415926);
28058 5 : array->Set(isolate, 2, num);
28059 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
28060 10 : CHECK(array->Get(isolate, 1)->IsString());
28061 10 : CHECK(array->Get(isolate, 2)->IsNumber());
28062 :
28063 : v8::Local<v8::Boolean> f = v8::False(isolate);
28064 5 : array->Set(isolate, 3, f);
28065 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
28066 10 : CHECK(array->Get(isolate, 1)->IsString());
28067 10 : CHECK(array->Get(isolate, 2)->IsNumber());
28068 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
28069 :
28070 5 : v8::Local<v8::Primitive> n = v8::Null(isolate);
28071 5 : array->Set(isolate, 4, n);
28072 10 : CHECK(array->Get(isolate, 0)->IsSymbol());
28073 10 : CHECK(array->Get(isolate, 1)->IsString());
28074 10 : CHECK(array->Get(isolate, 2)->IsNumber());
28075 10 : CHECK(array->Get(isolate, 3)->IsBoolean());
28076 15 : CHECK(array->Get(isolate, 4)->IsNull());
28077 5 : }
28078 :
28079 28342 : TEST(PersistentValueMap) {
28080 5 : v8::Isolate* isolate = CcTest::isolate();
28081 5 : v8::HandleScope scope(isolate);
28082 10 : LocalContext env;
28083 :
28084 : v8::PersistentValueMap<
28085 : std::string, v8::Value,
28086 : v8::DefaultPersistentValueMapTraits<std::string, v8::Value>>
28087 : map(isolate);
28088 : v8::Local<v8::Value> value =
28089 : v8::String::NewFromUtf8(isolate, "value",
28090 : v8::NewStringType::kInternalized)
28091 5 : .ToLocalChecked();
28092 20 : map.Set("key", value);
28093 5 : }
28094 :
28095 : namespace {
28096 :
28097 : bool wasm_streaming_callback_got_called = false;
28098 : bool wasm_streaming_data_got_collected = false;
28099 :
28100 10 : void WasmStreamingTestFinalizer(const v8::WeakCallbackInfo<void>& data) {
28101 5 : CHECK(!wasm_streaming_data_got_collected);
28102 5 : wasm_streaming_data_got_collected = true;
28103 5 : i::GlobalHandles::Destroy(reinterpret_cast<i::Address*>(data.GetParameter()));
28104 5 : }
28105 :
28106 5 : void WasmStreamingCallbackTestCallbackIsCalled(
28107 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28108 5 : CHECK(!wasm_streaming_callback_got_called);
28109 5 : wasm_streaming_callback_got_called = true;
28110 :
28111 : i::Handle<i::Object> global_handle =
28112 : reinterpret_cast<i::Isolate*>(args.GetIsolate())
28113 : ->global_handles()
28114 5 : ->Create(*v8::Utils::OpenHandle(*args.Data()));
28115 : i::GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
28116 : WasmStreamingTestFinalizer,
28117 5 : v8::WeakCallbackType::kParameter);
28118 5 : }
28119 :
28120 5 : void WasmStreamingCallbackTestOnBytesReceived(
28121 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28122 : std::shared_ptr<v8::WasmStreaming> streaming =
28123 5 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
28124 :
28125 : // The first bytes of the WebAssembly magic word.
28126 5 : const uint8_t bytes[]{0x00, 0x61, 0x73};
28127 5 : streaming->OnBytesReceived(bytes, arraysize(bytes));
28128 5 : }
28129 :
28130 5 : void WasmStreamingCallbackTestFinishWithSuccess(
28131 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28132 : std::shared_ptr<v8::WasmStreaming> streaming =
28133 5 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
28134 : // The bytes of a minimal WebAssembly module.
28135 5 : const uint8_t bytes[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
28136 5 : streaming->OnBytesReceived(bytes, arraysize(bytes));
28137 5 : streaming->Finish();
28138 5 : }
28139 :
28140 5 : void WasmStreamingCallbackTestFinishWithFailure(
28141 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28142 : std::shared_ptr<v8::WasmStreaming> streaming =
28143 5 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
28144 5 : streaming->Finish();
28145 5 : }
28146 :
28147 5 : void WasmStreamingCallbackTestAbortWithReject(
28148 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28149 : std::shared_ptr<v8::WasmStreaming> streaming =
28150 5 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
28151 10 : streaming->Abort(v8::Object::New(args.GetIsolate()));
28152 5 : }
28153 :
28154 5 : void WasmStreamingCallbackTestAbortNoReject(
28155 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
28156 : std::shared_ptr<v8::WasmStreaming> streaming =
28157 5 : v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
28158 5 : streaming->Abort({});
28159 5 : }
28160 :
28161 30 : void TestWasmStreaming(v8::WasmStreamingCallback callback,
28162 : v8::Promise::PromiseState expected_state) {
28163 30 : CcTest::isolate()->SetWasmStreamingCallback(callback);
28164 30 : LocalContext env;
28165 30 : v8::Isolate* isolate = env->GetIsolate();
28166 60 : v8::HandleScope scope(isolate);
28167 :
28168 : // Call {WebAssembly.compileStreaming} with {null} as parameter. The parameter
28169 : // is only really processed by the embedder, so for this test the value is
28170 : // irrelevant.
28171 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(
28172 : CompileRun("WebAssembly.compileStreaming(null)"));
28173 :
28174 30 : EmptyMessageQueues(isolate);
28175 60 : CHECK_EQ(expected_state, promise->State());
28176 30 : }
28177 :
28178 : } // namespace
28179 :
28180 28342 : TEST(WasmStreamingCallback) {
28181 : TestWasmStreaming(WasmStreamingCallbackTestCallbackIsCalled,
28182 5 : v8::Promise::kPending);
28183 5 : CHECK(wasm_streaming_callback_got_called);
28184 5 : CcTest::CollectAllAvailableGarbage();
28185 5 : CHECK(wasm_streaming_data_got_collected);
28186 5 : }
28187 :
28188 28342 : TEST(WasmStreamingOnBytesReceived) {
28189 : TestWasmStreaming(WasmStreamingCallbackTestOnBytesReceived,
28190 5 : v8::Promise::kPending);
28191 5 : }
28192 :
28193 28342 : TEST(WasmStreamingFinishWithSuccess) {
28194 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithSuccess,
28195 5 : v8::Promise::kFulfilled);
28196 5 : }
28197 :
28198 28342 : TEST(WasmStreamingFinishWithFailure) {
28199 : TestWasmStreaming(WasmStreamingCallbackTestFinishWithFailure,
28200 5 : v8::Promise::kRejected);
28201 5 : }
28202 :
28203 28342 : TEST(WasmStreamingAbortWithReject) {
28204 : TestWasmStreaming(WasmStreamingCallbackTestAbortWithReject,
28205 5 : v8::Promise::kRejected);
28206 5 : }
28207 :
28208 28342 : TEST(WasmStreamingAbortWithoutReject) {
28209 : TestWasmStreaming(WasmStreamingCallbackTestAbortNoReject,
28210 5 : v8::Promise::kPending);
28211 5 : }
28212 :
28213 : enum class AtomicsWaitCallbackAction {
28214 : Interrupt,
28215 : StopAndThrowInFirstCall,
28216 : StopAndThrowInSecondCall,
28217 : StopFromThreadAndThrow,
28218 : KeepWaiting
28219 : };
28220 :
28221 : class StopAtomicsWaitThread;
28222 :
28223 10 : struct AtomicsWaitCallbackInfo {
28224 : v8::Isolate* isolate;
28225 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle;
28226 : std::unique_ptr<StopAtomicsWaitThread> stop_thread;
28227 : AtomicsWaitCallbackAction action;
28228 :
28229 : Local<v8::SharedArrayBuffer> expected_sab;
28230 : v8::Isolate::AtomicsWaitEvent expected_event;
28231 : double expected_timeout;
28232 : int64_t expected_value;
28233 : size_t expected_offset;
28234 :
28235 : size_t ncalls = 0;
28236 : };
28237 :
28238 5 : class StopAtomicsWaitThread : public v8::base::Thread {
28239 : public:
28240 : explicit StopAtomicsWaitThread(AtomicsWaitCallbackInfo* info)
28241 5 : : Thread(Options("StopAtomicsWaitThread")), info_(info) {}
28242 :
28243 5 : void Run() override {
28244 5 : CHECK_NOT_NULL(info_->wake_handle);
28245 5 : info_->wake_handle->Wake();
28246 5 : }
28247 :
28248 : private:
28249 : AtomicsWaitCallbackInfo* info_;
28250 : };
28251 :
28252 65 : void AtomicsWaitCallbackForTesting(
28253 : v8::Isolate::AtomicsWaitEvent event, Local<v8::SharedArrayBuffer> sab,
28254 : size_t offset_in_bytes, int64_t value, double timeout_in_ms,
28255 : v8::Isolate::AtomicsWaitWakeHandle* wake_handle, void* data) {
28256 65 : AtomicsWaitCallbackInfo* info = static_cast<AtomicsWaitCallbackInfo*>(data);
28257 65 : info->ncalls++;
28258 65 : info->wake_handle = wake_handle;
28259 65 : CHECK(sab->StrictEquals(info->expected_sab));
28260 65 : CHECK_EQ(timeout_in_ms, info->expected_timeout);
28261 65 : CHECK_EQ(value, info->expected_value);
28262 65 : CHECK_EQ(offset_in_bytes, info->expected_offset);
28263 :
28264 20 : auto ThrowSomething = [&]() {
28265 40 : info->isolate->ThrowException(v8::Integer::New(info->isolate, 42));
28266 85 : };
28267 :
28268 65 : if (event == v8::Isolate::AtomicsWaitEvent::kStartWait) {
28269 35 : CHECK_NOT_NULL(wake_handle);
28270 35 : switch (info->action) {
28271 : case AtomicsWaitCallbackAction::Interrupt:
28272 5 : info->isolate->TerminateExecution();
28273 5 : break;
28274 : case AtomicsWaitCallbackAction::StopAndThrowInFirstCall:
28275 5 : ThrowSomething();
28276 : V8_FALLTHROUGH;
28277 : case AtomicsWaitCallbackAction::StopAndThrowInSecondCall:
28278 15 : wake_handle->Wake();
28279 15 : break;
28280 : case AtomicsWaitCallbackAction::StopFromThreadAndThrow:
28281 10 : info->stop_thread = v8::base::make_unique<StopAtomicsWaitThread>(info);
28282 10 : info->stop_thread->Start();
28283 5 : break;
28284 : case AtomicsWaitCallbackAction::KeepWaiting:
28285 : break;
28286 : }
28287 : } else {
28288 30 : CHECK_EQ(event, info->expected_event);
28289 30 : CHECK_NULL(wake_handle);
28290 :
28291 30 : if (info->stop_thread) {
28292 5 : info->stop_thread->Join();
28293 5 : info->stop_thread.reset();
28294 : }
28295 :
28296 30 : if (info->action == AtomicsWaitCallbackAction::StopAndThrowInSecondCall ||
28297 : info->action == AtomicsWaitCallbackAction::StopFromThreadAndThrow) {
28298 15 : ThrowSomething();
28299 : }
28300 : }
28301 65 : }
28302 :
28303 28342 : TEST(AtomicsWaitCallback) {
28304 5 : LocalContext env;
28305 5 : v8::Isolate* isolate = env->GetIsolate();
28306 10 : v8::HandleScope scope(isolate);
28307 :
28308 : Local<Value> sab = CompileRun(
28309 : "sab = new SharedArrayBuffer(12);"
28310 : "int32arr = new Int32Array(sab, 4);"
28311 : "sab");
28312 5 : CHECK(sab->IsSharedArrayBuffer());
28313 :
28314 : AtomicsWaitCallbackInfo info;
28315 5 : info.isolate = isolate;
28316 5 : info.expected_sab = sab.As<v8::SharedArrayBuffer>();
28317 5 : isolate->SetAtomicsWaitCallback(AtomicsWaitCallbackForTesting, &info);
28318 :
28319 : {
28320 5 : v8::TryCatch try_catch(isolate);
28321 5 : info.expected_offset = 4;
28322 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28323 5 : info.expected_value = 0;
28324 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
28325 5 : info.action = AtomicsWaitCallbackAction::Interrupt;
28326 5 : info.ncalls = 0;
28327 : CompileRun("Atomics.wait(int32arr, 0, 0);");
28328 10 : CHECK_EQ(info.ncalls, 2);
28329 5 : CHECK(try_catch.HasTerminated());
28330 : }
28331 :
28332 : {
28333 5 : v8::TryCatch try_catch(isolate);
28334 5 : info.expected_offset = 8;
28335 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28336 5 : info.expected_value = 1;
28337 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
28338 5 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
28339 5 : info.ncalls = 0;
28340 : CompileRun("Atomics.wait(int32arr, 1, 1);"); // real value is 0 != 1
28341 10 : CHECK_EQ(info.ncalls, 2);
28342 5 : CHECK(!try_catch.HasCaught());
28343 : }
28344 :
28345 : {
28346 5 : v8::TryCatch try_catch(isolate);
28347 5 : info.expected_offset = 8;
28348 5 : info.expected_timeout = 0.125;
28349 5 : info.expected_value = 0;
28350 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
28351 5 : info.action = AtomicsWaitCallbackAction::KeepWaiting;
28352 5 : info.ncalls = 0;
28353 : CompileRun("Atomics.wait(int32arr, 1, 0, 0.125);"); // timeout
28354 10 : CHECK_EQ(info.ncalls, 2);
28355 5 : CHECK(!try_catch.HasCaught());
28356 : }
28357 :
28358 : {
28359 5 : v8::TryCatch try_catch(isolate);
28360 5 : info.expected_offset = 8;
28361 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28362 5 : info.expected_value = 0;
28363 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
28364 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
28365 5 : info.ncalls = 0;
28366 : CompileRun("Atomics.wait(int32arr, 1, 0);");
28367 10 : CHECK_EQ(info.ncalls, 1); // Only one extra call
28368 5 : CHECK(try_catch.HasCaught());
28369 10 : CHECK(try_catch.Exception()->IsInt32());
28370 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
28371 : }
28372 :
28373 : {
28374 5 : v8::TryCatch try_catch(isolate);
28375 5 : info.expected_offset = 8;
28376 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28377 5 : info.expected_value = 0;
28378 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
28379 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
28380 5 : info.ncalls = 0;
28381 : CompileRun("Atomics.wait(int32arr, 1, 0);");
28382 10 : CHECK_EQ(info.ncalls, 2);
28383 5 : CHECK(try_catch.HasCaught());
28384 10 : CHECK(try_catch.Exception()->IsInt32());
28385 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
28386 : }
28387 :
28388 : {
28389 : // Same test as before, but with a different `expected_value`.
28390 5 : v8::TryCatch try_catch(isolate);
28391 5 : info.expected_offset = 8;
28392 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28393 5 : info.expected_value = 200;
28394 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
28395 5 : info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
28396 5 : info.ncalls = 0;
28397 : CompileRun(
28398 : "int32arr[1] = 200;"
28399 : "Atomics.wait(int32arr, 1, 200);");
28400 10 : CHECK_EQ(info.ncalls, 2);
28401 5 : CHECK(try_catch.HasCaught());
28402 10 : CHECK(try_catch.Exception()->IsInt32());
28403 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
28404 : }
28405 :
28406 : {
28407 : // Wake the `Atomics.wait()` call from a thread.
28408 5 : v8::TryCatch try_catch(isolate);
28409 5 : info.expected_offset = 4;
28410 5 : info.expected_timeout = std::numeric_limits<double>::infinity();
28411 5 : info.expected_value = 0;
28412 5 : info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
28413 5 : info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
28414 5 : info.ncalls = 0;
28415 : CompileRun("Atomics.wait(int32arr, 0, 0);");
28416 10 : CHECK_EQ(info.ncalls, 2);
28417 5 : CHECK(try_catch.HasCaught());
28418 10 : CHECK(try_catch.Exception()->IsInt32());
28419 5 : CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
28420 5 : }
28421 5 : }
28422 :
28423 28342 : TEST(BigIntAPI) {
28424 5 : LocalContext env;
28425 5 : v8::Isolate* isolate = env->GetIsolate();
28426 10 : v8::HandleScope scope(isolate);
28427 : bool lossless;
28428 : uint64_t words1[10];
28429 : uint64_t words2[10];
28430 :
28431 : {
28432 : Local<Value> bi = CompileRun("12n");
28433 5 : CHECK(bi->IsBigInt());
28434 :
28435 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 12);
28436 10 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless), 12);
28437 5 : CHECK_EQ(lossless, true);
28438 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 12);
28439 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 12);
28440 5 : CHECK_EQ(lossless, true);
28441 : }
28442 :
28443 : {
28444 : Local<Value> bi = CompileRun("-12n");
28445 5 : CHECK(bi->IsBigInt());
28446 :
28447 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), static_cast<uint64_t>(-12));
28448 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
28449 : static_cast<uint64_t>(-12));
28450 10 : CHECK_EQ(lossless, false);
28451 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -12);
28452 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), -12);
28453 5 : CHECK_EQ(lossless, true);
28454 : }
28455 :
28456 : {
28457 : Local<Value> bi = CompileRun("123456789012345678901234567890n");
28458 5 : CHECK(bi->IsBigInt());
28459 :
28460 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 14083847773837265618ULL);
28461 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
28462 : 14083847773837265618ULL);
28463 10 : CHECK_EQ(lossless, false);
28464 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -4362896299872285998LL);
28465 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless),
28466 : -4362896299872285998LL);
28467 10 : CHECK_EQ(lossless, false);
28468 : }
28469 :
28470 : {
28471 : Local<Value> bi = CompileRun("-123456789012345678901234567890n");
28472 5 : CHECK(bi->IsBigInt());
28473 :
28474 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 4362896299872285998LL);
28475 5 : CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
28476 : 4362896299872285998LL);
28477 10 : CHECK_EQ(lossless, false);
28478 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 4362896299872285998LL);
28479 5 : CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 4362896299872285998LL);
28480 10 : CHECK_EQ(lossless, false);
28481 : }
28482 :
28483 : {
28484 : Local<v8::BigInt> bi =
28485 5 : v8::BigInt::NewFromWords(env.local(), 0, 0, words1).ToLocalChecked();
28486 10 : CHECK_EQ(bi->Uint64Value(), 0);
28487 5 : CHECK_EQ(bi->WordCount(), 0);
28488 : }
28489 :
28490 : {
28491 5 : TryCatch try_catch(isolate);
28492 : v8::MaybeLocal<v8::BigInt> bi = v8::BigInt::NewFromWords(
28493 5 : env.local(), 0, std::numeric_limits<int>::max(), words1);
28494 5 : CHECK(bi.IsEmpty());
28495 5 : CHECK(try_catch.HasCaught());
28496 : }
28497 :
28498 : {
28499 5 : TryCatch try_catch(isolate);
28500 : v8::MaybeLocal<v8::BigInt> bi =
28501 5 : v8::BigInt::NewFromWords(env.local(), 0, -1, words1);
28502 5 : CHECK(bi.IsEmpty());
28503 5 : CHECK(try_catch.HasCaught());
28504 : }
28505 :
28506 : {
28507 5 : TryCatch try_catch(isolate);
28508 : v8::MaybeLocal<v8::BigInt> bi =
28509 5 : v8::BigInt::NewFromWords(env.local(), 0, 1 << 30, words1);
28510 5 : CHECK(bi.IsEmpty());
28511 5 : CHECK(try_catch.HasCaught());
28512 : }
28513 :
28514 15 : for (int sign_bit = 0; sign_bit <= 1; sign_bit++) {
28515 10 : words1[0] = 0xffffffff00000000ULL;
28516 10 : words1[1] = 0x00000000ffffffffULL;
28517 : v8::Local<v8::BigInt> bi =
28518 10 : v8::BigInt::NewFromWords(env.local(), sign_bit, 2, words1)
28519 10 : .ToLocalChecked();
28520 10 : CHECK_EQ(bi->Uint64Value(&lossless),
28521 : sign_bit ? static_cast<uint64_t>(-static_cast<int64_t>(words1[0]))
28522 : : words1[0]);
28523 20 : CHECK_EQ(lossless, false);
28524 10 : CHECK_EQ(bi->Int64Value(&lossless), sign_bit
28525 : ? -static_cast<int64_t>(words1[0])
28526 : : static_cast<int64_t>(words1[0]));
28527 20 : CHECK_EQ(lossless, false);
28528 10 : CHECK_EQ(bi->WordCount(), 2);
28529 : int real_sign_bit;
28530 10 : int word_count = arraysize(words2);
28531 10 : bi->ToWordsArray(&real_sign_bit, &word_count, words2);
28532 10 : CHECK_EQ(real_sign_bit, sign_bit);
28533 10 : CHECK_EQ(word_count, 2);
28534 5 : }
28535 5 : }
28536 :
28537 : namespace {
28538 :
28539 : bool wasm_threads_enabled_value = false;
28540 :
28541 10 : bool MockWasmThreadsEnabledCallback(Local<Context>) {
28542 10 : return wasm_threads_enabled_value;
28543 : }
28544 :
28545 : } // namespace
28546 :
28547 28342 : TEST(TestSetWasmThreadsEnabledCallback) {
28548 5 : LocalContext env;
28549 5 : v8::Isolate* isolate = env->GetIsolate();
28550 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28551 10 : v8::HandleScope scope(isolate);
28552 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
28553 5 : i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context);
28554 :
28555 : // {Isolate::AreWasmThreadsEnabled} calls the callback set by the embedder if
28556 : // such a callback exists. Otherwise it returns
28557 : // {FLAG_experimental_wasm_threads}. First we test that the flag is returned
28558 : // correctly if no callback is set. Then we test that the flag is ignored if
28559 : // the callback is set.
28560 :
28561 5 : i::FLAG_experimental_wasm_threads = false;
28562 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28563 :
28564 5 : i::FLAG_experimental_wasm_threads = true;
28565 5 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28566 :
28567 5 : isolate->SetWasmThreadsEnabledCallback(MockWasmThreadsEnabledCallback);
28568 5 : wasm_threads_enabled_value = false;
28569 5 : CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28570 :
28571 5 : wasm_threads_enabled_value = true;
28572 5 : i::FLAG_experimental_wasm_threads = false;
28573 10 : CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28574 5 : }
28575 :
28576 28342 : TEST(TestGetUnwindState) {
28577 5 : LocalContext env;
28578 5 : v8::Isolate* isolate = env->GetIsolate();
28579 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28580 :
28581 5 : v8::UnwindState unwind_state = isolate->GetUnwindState();
28582 5 : v8::MemoryRange builtins_range = unwind_state.embedded_code_range;
28583 :
28584 : // Check that each off-heap builtin is within the builtins code range.
28585 : if (i::FLAG_embedded_builtins) {
28586 7560 : for (int id = 0; id < i::Builtins::builtin_count; id++) {
28587 : if (!i::Builtins::IsIsolateIndependent(id)) continue;
28588 7555 : i::Code builtin = i_isolate->builtins()->builtin(id);
28589 7555 : i::Address start = builtin->InstructionStart();
28590 7555 : i::Address end = start + builtin->InstructionSize();
28591 :
28592 : i::Address builtins_start =
28593 7555 : reinterpret_cast<i::Address>(builtins_range.start);
28594 7555 : CHECK(start >= builtins_start &&
28595 : end < builtins_start + builtins_range.length_in_bytes);
28596 : }
28597 : } else {
28598 : CHECK_EQ(nullptr, builtins_range.start);
28599 : CHECK_EQ(0, builtins_range.length_in_bytes);
28600 : }
28601 :
28602 5 : v8::JSEntryStub js_entry_stub = unwind_state.js_entry_stub;
28603 :
28604 5 : CHECK_EQ(
28605 : i_isolate->heap()->builtin(i::Builtins::kJSEntry)->InstructionStart(),
28606 5 : reinterpret_cast<i::Address>(js_entry_stub.code.start));
28607 5 : }
28608 :
28609 28342 : TEST(MicrotaskContextShouldBeNativeContext) {
28610 5 : LocalContext env;
28611 5 : v8::Isolate* isolate = env->GetIsolate();
28612 10 : v8::HandleScope scope(isolate);
28613 :
28614 15 : auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
28615 : v8::Isolate* isolate = info.GetIsolate();
28616 5 : v8::HandleScope scope(isolate);
28617 : i::Handle<i::Context> context =
28618 10 : v8::Utils::OpenHandle(*isolate->GetEnteredOrMicrotaskContext());
28619 :
28620 10 : CHECK(context->IsNativeContext());
28621 : info.GetReturnValue().SetUndefined();
28622 10 : };
28623 :
28624 5 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
28625 10 : desc->InstanceTemplate()->SetCallAsFunctionHandler(callback);
28626 5 : Local<v8::Object> obj = desc->GetFunction(env.local())
28627 5 : .ToLocalChecked()
28628 5 : ->NewInstance(env.local())
28629 : .ToLocalChecked();
28630 :
28631 25 : CHECK(env->Global()->Set(env.local(), v8_str("callback"), obj).FromJust());
28632 : CompileRun(
28633 : "with({}){(async ()=>{"
28634 : " await 42;"
28635 : "})().then(callback);}");
28636 :
28637 10 : isolate->RunMicrotasks();
28638 5 : }
28639 :
28640 28342 : TEST(PreviewSetIteratorEntriesWithDeleted) {
28641 5 : LocalContext env;
28642 10 : v8::HandleScope handle_scope(env->GetIsolate());
28643 5 : v8::Local<v8::Context> context = env.local();
28644 :
28645 : {
28646 : // Create set, delete entry, create iterator, preview.
28647 : v8::Local<v8::Object> iterator =
28648 : CompileRun("var set = new Set([1,2,3]); set.delete(1); set.keys()")
28649 : ->ToObject(context)
28650 5 : .ToLocalChecked();
28651 : bool is_key;
28652 : v8::Local<v8::Array> entries =
28653 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28654 5 : CHECK(!is_key);
28655 5 : CHECK_EQ(2, entries->Length());
28656 15 : CHECK_EQ(2, entries->Get(context, 0)
28657 : .ToLocalChecked()
28658 : ->Int32Value(context)
28659 : .FromJust());
28660 15 : CHECK_EQ(3, entries->Get(context, 1)
28661 : .ToLocalChecked()
28662 : ->Int32Value(context)
28663 : .FromJust());
28664 : }
28665 : {
28666 : // Create set, create iterator, delete entry, preview.
28667 : v8::Local<v8::Object> iterator =
28668 : CompileRun("var set = new Set([1,2,3]); set.keys()")
28669 : ->ToObject(context)
28670 5 : .ToLocalChecked();
28671 : CompileRun("set.delete(1);");
28672 : bool is_key;
28673 : v8::Local<v8::Array> entries =
28674 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28675 5 : CHECK(!is_key);
28676 5 : CHECK_EQ(2, entries->Length());
28677 15 : CHECK_EQ(2, entries->Get(context, 0)
28678 : .ToLocalChecked()
28679 : ->Int32Value(context)
28680 : .FromJust());
28681 15 : CHECK_EQ(3, entries->Get(context, 1)
28682 : .ToLocalChecked()
28683 : ->Int32Value(context)
28684 : .FromJust());
28685 : }
28686 : {
28687 : // Create set, create iterator, delete entry, iterate, preview.
28688 : v8::Local<v8::Object> iterator =
28689 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28690 : ->ToObject(context)
28691 5 : .ToLocalChecked();
28692 : CompileRun("set.delete(1); it.next();");
28693 : bool is_key;
28694 : v8::Local<v8::Array> entries =
28695 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28696 5 : CHECK(!is_key);
28697 5 : CHECK_EQ(1, entries->Length());
28698 15 : CHECK_EQ(3, entries->Get(context, 0)
28699 : .ToLocalChecked()
28700 : ->Int32Value(context)
28701 : .FromJust());
28702 : }
28703 : {
28704 : // Create set, create iterator, delete entry, iterate until empty, preview.
28705 : v8::Local<v8::Object> iterator =
28706 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28707 : ->ToObject(context)
28708 5 : .ToLocalChecked();
28709 : CompileRun("set.delete(1); it.next(); it.next();");
28710 : bool is_key;
28711 : v8::Local<v8::Array> entries =
28712 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28713 5 : CHECK(!is_key);
28714 5 : CHECK_EQ(0, entries->Length());
28715 : }
28716 : {
28717 : // Create set, create iterator, delete entry, iterate, trigger rehash,
28718 : // preview.
28719 : v8::Local<v8::Object> iterator =
28720 : CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28721 : ->ToObject(context)
28722 5 : .ToLocalChecked();
28723 : CompileRun("set.delete(1); it.next();");
28724 : CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28725 : bool is_key;
28726 : v8::Local<v8::Array> entries =
28727 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28728 5 : CHECK(!is_key);
28729 5 : CHECK_EQ(17, entries->Length());
28730 85 : for (uint32_t i = 0; i < 17; i++) {
28731 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28732 : .ToLocalChecked()
28733 : ->Int32Value(context)
28734 : .FromJust());
28735 : }
28736 5 : }
28737 5 : }
28738 :
28739 28342 : TEST(PreviewMapIteratorEntriesWithDeleted) {
28740 5 : LocalContext env;
28741 10 : v8::HandleScope handle_scope(env->GetIsolate());
28742 5 : v8::Local<v8::Context> context = env.local();
28743 :
28744 : {
28745 : // Create map, delete entry, create iterator, preview.
28746 : v8::Local<v8::Object> iterator = CompileRun(
28747 : "var map = new Map();"
28748 : "var key = {}; map.set(key, 1);"
28749 : "map.set({}, 2); map.set({}, 3);"
28750 : "map.delete(key);"
28751 : "map.values()")
28752 : ->ToObject(context)
28753 5 : .ToLocalChecked();
28754 : bool is_key;
28755 : v8::Local<v8::Array> entries =
28756 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28757 5 : CHECK(!is_key);
28758 5 : CHECK_EQ(2, entries->Length());
28759 15 : CHECK_EQ(2, entries->Get(context, 0)
28760 : .ToLocalChecked()
28761 : ->Int32Value(context)
28762 : .FromJust());
28763 15 : CHECK_EQ(3, entries->Get(context, 1)
28764 : .ToLocalChecked()
28765 : ->Int32Value(context)
28766 : .FromJust());
28767 : }
28768 : {
28769 : // Create map, create iterator, delete entry, preview.
28770 : v8::Local<v8::Object> iterator = CompileRun(
28771 : "var map = new Map();"
28772 : "var key = {}; map.set(key, 1);"
28773 : "map.set({}, 2); map.set({}, 3);"
28774 : "map.values()")
28775 : ->ToObject(context)
28776 5 : .ToLocalChecked();
28777 : CompileRun("map.delete(key);");
28778 : bool is_key;
28779 : v8::Local<v8::Array> entries =
28780 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28781 5 : CHECK(!is_key);
28782 5 : CHECK_EQ(2, entries->Length());
28783 15 : CHECK_EQ(2, entries->Get(context, 0)
28784 : .ToLocalChecked()
28785 : ->Int32Value(context)
28786 : .FromJust());
28787 15 : CHECK_EQ(3, entries->Get(context, 1)
28788 : .ToLocalChecked()
28789 : ->Int32Value(context)
28790 : .FromJust());
28791 : }
28792 : {
28793 : // Create map, create iterator, delete entry, iterate, preview.
28794 : v8::Local<v8::Object> iterator = CompileRun(
28795 : "var map = new Map();"
28796 : "var key = {}; map.set(key, 1);"
28797 : "map.set({}, 2); map.set({}, 3);"
28798 : "var it = map.values(); it")
28799 : ->ToObject(context)
28800 5 : .ToLocalChecked();
28801 : CompileRun("map.delete(key); it.next();");
28802 : bool is_key;
28803 : v8::Local<v8::Array> entries =
28804 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28805 5 : CHECK(!is_key);
28806 5 : CHECK_EQ(1, entries->Length());
28807 15 : CHECK_EQ(3, entries->Get(context, 0)
28808 : .ToLocalChecked()
28809 : ->Int32Value(context)
28810 : .FromJust());
28811 : }
28812 : {
28813 : // Create map, create iterator, delete entry, iterate until empty, preview.
28814 : v8::Local<v8::Object> iterator = CompileRun(
28815 : "var map = new Map();"
28816 : "var key = {}; map.set(key, 1);"
28817 : "map.set({}, 2); map.set({}, 3);"
28818 : "var it = map.values(); it")
28819 : ->ToObject(context)
28820 5 : .ToLocalChecked();
28821 : CompileRun("map.delete(key); it.next(); it.next();");
28822 : bool is_key;
28823 : v8::Local<v8::Array> entries =
28824 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28825 5 : CHECK(!is_key);
28826 5 : CHECK_EQ(0, entries->Length());
28827 : }
28828 : {
28829 : // Create map, create iterator, delete entry, iterate, trigger rehash,
28830 : // preview.
28831 : v8::Local<v8::Object> iterator = CompileRun(
28832 : "var map = new Map();"
28833 : "var key = {}; map.set(key, 1);"
28834 : "map.set({}, 2); map.set({}, 3);"
28835 : "var it = map.values(); it")
28836 : ->ToObject(context)
28837 5 : .ToLocalChecked();
28838 : CompileRun("map.delete(key); it.next();");
28839 : CompileRun("for (var i = 4; i < 20; i++) map.set({}, i);");
28840 : bool is_key;
28841 : v8::Local<v8::Array> entries =
28842 5 : iterator->PreviewEntries(&is_key).ToLocalChecked();
28843 5 : CHECK(!is_key);
28844 5 : CHECK_EQ(17, entries->Length());
28845 85 : for (uint32_t i = 0; i < 17; i++) {
28846 340 : CHECK_EQ(i + 3, entries->Get(context, i)
28847 : .ToLocalChecked()
28848 : ->Int32Value(context)
28849 : .FromJust());
28850 : }
28851 5 : }
28852 5 : }
28853 :
28854 : namespace {
28855 : static v8::Isolate* isolate_1;
28856 : static v8::Isolate* isolate_2;
28857 28337 : v8::Persistent<v8::Context> context_1;
28858 28337 : v8::Persistent<v8::Context> context_2;
28859 :
28860 20 : static void CallIsolate1(const v8::FunctionCallbackInfo<v8::Value>& args) {
28861 20 : v8::Isolate::Scope isolate_scope(isolate_1);
28862 40 : v8::HandleScope handle_scope(isolate_1);
28863 : v8::Local<v8::Context> context =
28864 20 : v8::Local<v8::Context>::New(isolate_1, context_1);
28865 : v8::Context::Scope context_scope(context);
28866 : CompileRun("f1() //# sourceURL=isolate1b");
28867 20 : }
28868 :
28869 20 : static void CallIsolate2(const v8::FunctionCallbackInfo<v8::Value>& args) {
28870 20 : v8::Isolate::Scope isolate_scope(isolate_2);
28871 40 : v8::HandleScope handle_scope(isolate_2);
28872 : v8::Local<v8::Context> context =
28873 20 : v8::Local<v8::Context>::New(isolate_2, context_2);
28874 : v8::Context::Scope context_scope(context);
28875 : reinterpret_cast<i::Isolate*>(isolate_2)->heap()->CollectAllGarbage(
28876 : i::Heap::kNoGCFlags, i::GarbageCollectionReason::kTesting,
28877 20 : v8::kGCCallbackFlagForced);
28878 : CompileRun("f2() //# sourceURL=isolate2b");
28879 20 : }
28880 :
28881 : } // anonymous namespace
28882 :
28883 28342 : UNINITIALIZED_TEST(NestedIsolates) {
28884 : #ifdef VERIFY_HEAP
28885 : i::FLAG_verify_heap = true;
28886 : #endif // VERIFY_HEAP
28887 : // Create two isolates and set up C++ functions via function templates that
28888 : // call into the other isolate. Recurse a few times, trigger GC along the way,
28889 : // and finally capture a stack trace. Check that the stack trace only includes
28890 : // frames from its own isolate.
28891 : v8::Isolate::CreateParams create_params;
28892 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
28893 5 : isolate_1 = v8::Isolate::New(create_params);
28894 5 : isolate_2 = v8::Isolate::New(create_params);
28895 :
28896 : {
28897 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28898 10 : v8::HandleScope handle_scope(isolate_1);
28899 :
28900 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_1);
28901 : v8::Context::Scope context_scope(context);
28902 :
28903 : v8::Local<v8::FunctionTemplate> fun_templ =
28904 5 : v8::FunctionTemplate::New(isolate_1, CallIsolate2);
28905 5 : fun_templ->SetClassName(v8_str(isolate_1, "call_isolate_2"));
28906 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28907 20 : CHECK(context->Global()
28908 : ->Set(context, v8_str(isolate_1, "call_isolate_2"), fun)
28909 : .FromJust());
28910 : CompileRun(
28911 : "let c = 0;"
28912 : "function f1() {"
28913 : " c++;"
28914 : " return call_isolate_2();"
28915 : "} //# sourceURL=isolate1a");
28916 5 : context_1.Reset(isolate_1, context);
28917 : }
28918 :
28919 : {
28920 5 : v8::Isolate::Scope isolate_scope(isolate_2);
28921 10 : v8::HandleScope handle_scope(isolate_2);
28922 :
28923 5 : v8::Local<v8::Context> context = v8::Context::New(isolate_2);
28924 : v8::Context::Scope context_scope(context);
28925 :
28926 : v8::Local<v8::FunctionTemplate> fun_templ =
28927 5 : v8::FunctionTemplate::New(isolate_2, CallIsolate1);
28928 5 : fun_templ->SetClassName(v8_str(isolate_2, "call_isolate_1"));
28929 5 : Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28930 :
28931 20 : CHECK(context->Global()
28932 : ->Set(context, v8_str(isolate_2, "call_isolate_1"), fun)
28933 : .FromJust());
28934 : CompileRun(
28935 : "let c = 4;"
28936 : "let result = undefined;"
28937 : "function f2() {"
28938 : " if (c-- > 0) return call_isolate_1();"
28939 : " else result = new Error().stack;"
28940 : "} //# sourceURL=isolate2a");
28941 5 : context_2.Reset(isolate_2, context);
28942 :
28943 : v8::Local<v8::String> result =
28944 : CompileRun("f2(); result //# sourceURL=isolate2c")
28945 : ->ToString(context)
28946 5 : .ToLocalChecked();
28947 : v8::Local<v8::String> expectation = v8_str(isolate_2,
28948 : "Error\n"
28949 : " at f2 (isolate2a:1:104)\n"
28950 : " at isolate2b:1:1\n"
28951 : " at f2 (isolate2a:1:71)\n"
28952 : " at isolate2b:1:1\n"
28953 : " at f2 (isolate2a:1:71)\n"
28954 : " at isolate2b:1:1\n"
28955 : " at f2 (isolate2a:1:71)\n"
28956 : " at isolate2b:1:1\n"
28957 : " at f2 (isolate2a:1:71)\n"
28958 5 : " at isolate2c:1:1");
28959 5 : CHECK(result->StrictEquals(expectation));
28960 : }
28961 :
28962 : {
28963 5 : v8::Isolate::Scope isolate_scope(isolate_1);
28964 10 : v8::HandleScope handle_scope(isolate_1);
28965 : v8::Local<v8::Context> context =
28966 5 : v8::Local<v8::Context>::New(isolate_1, context_1);
28967 : v8::Context::Scope context_scope(context);
28968 5 : ExpectInt32("c", 4);
28969 : }
28970 :
28971 5 : isolate_1->Dispose();
28972 5 : isolate_2->Dispose();
28973 85016 : }
|