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.h"
42 : #include "src/arguments.h"
43 : #include "src/base/platform/platform.h"
44 : #include "src/code-stubs.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/heap/incremental-marking.h"
50 : #include "src/heap/local-allocator.h"
51 : #include "src/lookup.h"
52 : #include "src/objects-inl.h"
53 : #include "src/parsing/preparse-data.h"
54 : #include "src/profiler/cpu-profiler.h"
55 : #include "src/unicode-inl.h"
56 : #include "src/utils.h"
57 : #include "src/vm-state.h"
58 : #include "test/cctest/heap/heap-tester.h"
59 : #include "test/cctest/heap/heap-utils.h"
60 :
61 : static const bool kLogThreading = false;
62 :
63 : using ::v8::Array;
64 : using ::v8::Boolean;
65 : using ::v8::BooleanObject;
66 : using ::v8::Context;
67 : using ::v8::Extension;
68 : using ::v8::Function;
69 : using ::v8::FunctionTemplate;
70 : using ::v8::HandleScope;
71 : using ::v8::Local;
72 : using ::v8::Maybe;
73 : using ::v8::Message;
74 : using ::v8::MessageCallback;
75 : using ::v8::Module;
76 : using ::v8::Name;
77 : using ::v8::None;
78 : using ::v8::Object;
79 : using ::v8::ObjectTemplate;
80 : using ::v8::Persistent;
81 : using ::v8::PropertyAttribute;
82 : using ::v8::Script;
83 : using ::v8::StackTrace;
84 : using ::v8::String;
85 : using ::v8::Symbol;
86 : using ::v8::TryCatch;
87 : using ::v8::Undefined;
88 : using ::v8::V8;
89 : using ::v8::Value;
90 :
91 :
92 : #define THREADED_PROFILED_TEST(Name) \
93 : static void Test##Name(); \
94 : TEST(Name##WithProfiler) { \
95 : RunWithProfiler(&Test##Name); \
96 : } \
97 : THREADED_TEST(Name)
98 :
99 :
100 75 : void RunWithProfiler(void (*test)()) {
101 75 : LocalContext env;
102 150 : v8::HandleScope scope(env->GetIsolate());
103 75 : v8::Local<v8::String> profile_name = v8_str("my_profile1");
104 75 : v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
105 75 : cpu_profiler->StartProfiling(profile_name);
106 75 : (*test)();
107 75 : reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
108 150 : cpu_profiler->Dispose();
109 75 : }
110 :
111 :
112 : static int signature_callback_count;
113 : static Local<Value> signature_expected_receiver;
114 3900 : static void IncrementingSignatureCallback(
115 28080 : const v8::FunctionCallbackInfo<v8::Value>& args) {
116 3900 : ApiTestFuzzer::Fuzz();
117 3900 : signature_callback_count++;
118 11700 : CHECK(signature_expected_receiver->Equals(
119 : args.GetIsolate()->GetCurrentContext(),
120 : args.Holder())
121 : .FromJust());
122 11700 : CHECK(signature_expected_receiver->Equals(
123 : args.GetIsolate()->GetCurrentContext(),
124 : args.This())
125 : .FromJust());
126 : v8::Local<v8::Array> result =
127 3900 : v8::Array::New(args.GetIsolate(), args.Length());
128 10920 : for (int i = 0; i < args.Length(); i++) {
129 6240 : CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
130 : v8::Integer::New(args.GetIsolate(), i), args[i])
131 : .FromJust());
132 : }
133 : args.GetReturnValue().Set(result);
134 3900 : }
135 :
136 :
137 215 : static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
138 : info.GetReturnValue().Set(42);
139 215 : }
140 :
141 :
142 : // Tests that call v8::V8::Dispose() cannot be threaded.
143 23723 : UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
144 5 : CHECK(v8::V8::Initialize());
145 5 : CHECK(v8::V8::Dispose());
146 5 : }
147 :
148 :
149 : // Tests that call v8::V8::Dispose() cannot be threaded.
150 23723 : UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
151 5 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
152 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
153 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
154 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
155 15 : for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
156 5 : }
157 :
158 : // Tests that Smi::kZero is set up properly.
159 23723 : UNINITIALIZED_TEST(SmiZero) { CHECK_EQ(i::Smi::kZero, i::Smi::kZero); }
160 :
161 23724 : THREADED_TEST(Handles) {
162 6 : v8::HandleScope scope(CcTest::isolate());
163 : Local<Context> local_env;
164 : {
165 6 : LocalContext env;
166 6 : local_env = env.local();
167 : }
168 :
169 : // Local context should still be live.
170 6 : CHECK(!local_env.IsEmpty());
171 6 : local_env->Enter();
172 :
173 6 : v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
174 6 : CHECK(!undef.IsEmpty());
175 6 : CHECK(undef->IsUndefined());
176 :
177 : const char* source = "1 + 2 + 3";
178 6 : Local<Script> script = v8_compile(source);
179 6 : CHECK_EQ(6, v8_run_int32value(script));
180 :
181 6 : local_env->Exit();
182 6 : }
183 :
184 :
185 23724 : THREADED_TEST(IsolateOfContext) {
186 6 : v8::HandleScope scope(CcTest::isolate());
187 6 : v8::Local<Context> env = Context::New(CcTest::isolate());
188 :
189 6 : CHECK(!env->GetIsolate()->InContext());
190 6 : CHECK(env->GetIsolate() == CcTest::isolate());
191 6 : env->Enter();
192 6 : CHECK(env->GetIsolate()->InContext());
193 6 : CHECK(env->GetIsolate() == CcTest::isolate());
194 6 : env->Exit();
195 6 : CHECK(!env->GetIsolate()->InContext());
196 6 : CHECK(env->GetIsolate() == CcTest::isolate());
197 6 : }
198 :
199 420 : static void TestSignatureLooped(const char* operation, Local<Value> receiver,
200 : v8::Isolate* isolate) {
201 : i::ScopedVector<char> source(200);
202 : i::SNPrintF(source,
203 : "for (var i = 0; i < 10; i++) {"
204 : " %s"
205 : "}",
206 420 : operation);
207 420 : signature_callback_count = 0;
208 420 : signature_expected_receiver = receiver;
209 : bool expected_to_throw = receiver.IsEmpty();
210 840 : v8::TryCatch try_catch(isolate);
211 : CompileRun(source.start());
212 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
213 420 : if (!expected_to_throw) {
214 300 : CHECK_EQ(10, signature_callback_count);
215 : } else {
216 600 : CHECK(v8_str("TypeError: Illegal invocation")
217 : ->Equals(isolate->GetCurrentContext(),
218 : try_catch.Exception()
219 : ->ToString(isolate->GetCurrentContext())
220 : .ToLocalChecked())
221 : .FromJust());
222 : }
223 420 : }
224 :
225 420 : static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
226 : v8::Isolate* isolate) {
227 : i::ScopedVector<char> source(200);
228 : i::SNPrintF(source,
229 : "function test() {"
230 : " %s"
231 : "}"
232 : "try { test() } catch(e) {}"
233 : "try { test() } catch(e) {}"
234 : "%%OptimizeFunctionOnNextCall(test);"
235 : "test()",
236 420 : operation);
237 420 : signature_callback_count = 0;
238 420 : signature_expected_receiver = receiver;
239 : bool expected_to_throw = receiver.IsEmpty();
240 840 : v8::TryCatch try_catch(isolate);
241 : CompileRun(source.start());
242 420 : CHECK_EQ(expected_to_throw, try_catch.HasCaught());
243 420 : if (!expected_to_throw) {
244 300 : CHECK_EQ(3, signature_callback_count);
245 : } else {
246 600 : CHECK(v8_str("TypeError: Illegal invocation")
247 : ->Equals(isolate->GetCurrentContext(),
248 : try_catch.Exception()
249 : ->ToString(isolate->GetCurrentContext())
250 : .ToLocalChecked())
251 : .FromJust());
252 : }
253 420 : }
254 :
255 420 : static void TestSignature(const char* operation, Local<Value> receiver,
256 : v8::Isolate* isolate) {
257 420 : TestSignatureLooped(operation, receiver, isolate);
258 420 : TestSignatureOptimized(operation, receiver, isolate);
259 420 : }
260 :
261 23724 : THREADED_TEST(ReceiverSignature) {
262 6 : i::FLAG_allow_natives_syntax = true;
263 6 : LocalContext env;
264 6 : v8::Isolate* isolate = env->GetIsolate();
265 12 : v8::HandleScope scope(isolate);
266 : // Setup templates.
267 6 : v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
268 6 : v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
269 : v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
270 6 : isolate, IncrementingSignatureCallback, Local<Value>(), sig);
271 : v8::Local<v8::FunctionTemplate> callback =
272 6 : v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
273 6 : v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
274 6 : sub_fun->Inherit(fun);
275 : v8::Local<v8::FunctionTemplate> direct_sub_fun =
276 6 : v8::FunctionTemplate::New(isolate);
277 6 : direct_sub_fun->Inherit(fun);
278 : v8::Local<v8::FunctionTemplate> unrel_fun =
279 6 : v8::FunctionTemplate::New(isolate);
280 : // Install properties.
281 6 : v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
282 12 : fun_proto->Set(v8_str("prop_sig"), callback_sig);
283 12 : fun_proto->Set(v8_str("prop"), callback);
284 : fun_proto->SetAccessorProperty(
285 12 : v8_str("accessor_sig"), callback_sig, callback_sig);
286 12 : fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
287 : // Instantiate templates.
288 : Local<Value> fun_instance =
289 18 : fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
290 : Local<Value> sub_fun_instance =
291 18 : sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
292 : // Instance template with properties.
293 : v8::Local<v8::ObjectTemplate> direct_instance_templ =
294 6 : direct_sub_fun->InstanceTemplate();
295 12 : direct_instance_templ->Set(v8_str("prop_sig"), callback_sig);
296 12 : direct_instance_templ->Set(v8_str("prop"), callback);
297 : direct_instance_templ->SetAccessorProperty(v8_str("accessor_sig"),
298 12 : callback_sig, callback_sig);
299 : direct_instance_templ->SetAccessorProperty(v8_str("accessor"), callback,
300 12 : callback);
301 : Local<Value> direct_instance =
302 6 : direct_instance_templ->NewInstance(env.local()).ToLocalChecked();
303 : // Setup global variables.
304 36 : CHECK(env->Global()
305 : ->Set(env.local(), v8_str("Fun"),
306 : fun->GetFunction(env.local()).ToLocalChecked())
307 : .FromJust());
308 42 : CHECK(env->Global()
309 : ->Set(env.local(), v8_str("UnrelFun"),
310 : unrel_fun->GetFunction(env.local()).ToLocalChecked())
311 : .FromJust());
312 30 : CHECK(env->Global()
313 : ->Set(env.local(), v8_str("fun_instance"), fun_instance)
314 : .FromJust());
315 30 : CHECK(env->Global()
316 : ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
317 : .FromJust());
318 30 : CHECK(env->Global()
319 : ->Set(env.local(), v8_str("direct_instance"), direct_instance)
320 : .FromJust());
321 : CompileRun(
322 : "var accessor_sig_key = 'accessor_sig';"
323 : "var accessor_key = 'accessor';"
324 : "var prop_sig_key = 'prop_sig';"
325 : "var prop_key = 'prop';"
326 : ""
327 : "function copy_props(obj) {"
328 : " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
329 : " var source = Fun.prototype;"
330 : " for (var i in keys) {"
331 : " var key = keys[i];"
332 : " var desc = Object.getOwnPropertyDescriptor(source, key);"
333 : " Object.defineProperty(obj, key, desc);"
334 : " }"
335 : "}"
336 : ""
337 : "var plain = {};"
338 : "copy_props(plain);"
339 : "var unrelated = new UnrelFun();"
340 : "copy_props(unrelated);"
341 : "var inherited = { __proto__: fun_instance };"
342 : "var inherited_direct = { __proto__: direct_instance };");
343 : // Test with and without ICs
344 : const char* test_objects[] = {
345 : "fun_instance", "sub_fun_instance", "direct_instance", "plain",
346 6 : "unrelated", "inherited", "inherited_direct"};
347 : unsigned bad_signature_start_offset = 3;
348 48 : for (unsigned i = 0; i < arraysize(test_objects); i++) {
349 : i::ScopedVector<char> source(200);
350 : i::SNPrintF(
351 42 : source, "var test_object = %s; test_object", test_objects[i]);
352 42 : Local<Value> test_object = CompileRun(source.start());
353 42 : TestSignature("test_object.prop();", test_object, isolate);
354 42 : TestSignature("test_object.accessor;", test_object, isolate);
355 42 : TestSignature("test_object[accessor_key];", test_object, isolate);
356 42 : TestSignature("test_object.accessor = 1;", test_object, isolate);
357 42 : TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
358 42 : if (i >= bad_signature_start_offset) test_object = Local<Value>();
359 42 : TestSignature("test_object.prop_sig();", test_object, isolate);
360 42 : TestSignature("test_object.accessor_sig;", test_object, isolate);
361 42 : TestSignature("test_object[accessor_sig_key];", test_object, isolate);
362 42 : TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
363 42 : TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
364 6 : }
365 6 : }
366 :
367 :
368 23724 : THREADED_TEST(HulIgennem) {
369 6 : LocalContext env;
370 6 : v8::Isolate* isolate = env->GetIsolate();
371 12 : v8::HandleScope scope(isolate);
372 : v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
373 6 : Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
374 6 : char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
375 6 : undef_str->WriteUtf8(value);
376 6 : CHECK_EQ(0, strcmp(value, "undefined"));
377 6 : i::DeleteArray(value);
378 6 : }
379 :
380 :
381 23724 : THREADED_TEST(Access) {
382 6 : LocalContext env;
383 6 : v8::Isolate* isolate = env->GetIsolate();
384 12 : v8::HandleScope scope(isolate);
385 6 : Local<v8::Object> obj = v8::Object::New(isolate);
386 : Local<Value> foo_before =
387 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
388 6 : CHECK(foo_before->IsUndefined());
389 6 : Local<String> bar_str = v8_str("bar");
390 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
391 : Local<Value> foo_after =
392 18 : obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
393 6 : CHECK(!foo_after->IsUndefined());
394 6 : CHECK(foo_after->IsString());
395 12 : CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
396 :
397 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).ToChecked());
398 : bool result;
399 18 : CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).To(&result));
400 12 : CHECK(result);
401 6 : }
402 :
403 :
404 23724 : THREADED_TEST(AccessElement) {
405 6 : LocalContext env;
406 12 : v8::HandleScope scope(env->GetIsolate());
407 6 : Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
408 6 : Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
409 6 : CHECK(before->IsUndefined());
410 6 : Local<String> bar_str = v8_str("bar");
411 12 : CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
412 6 : Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
413 6 : CHECK(!after->IsUndefined());
414 6 : CHECK(after->IsString());
415 12 : CHECK(bar_str->Equals(env.local(), after).FromJust());
416 :
417 : Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
418 24 : CHECK(v8_str("a")
419 : ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
420 : .FromJust());
421 24 : CHECK(v8_str("b")
422 : ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
423 6 : .FromJust());
424 6 : }
425 :
426 :
427 23724 : THREADED_TEST(Script) {
428 6 : LocalContext env;
429 12 : v8::HandleScope scope(env->GetIsolate());
430 : const char* source = "1 + 2 + 3";
431 6 : Local<Script> script = v8_compile(source);
432 12 : CHECK_EQ(6, v8_run_int32value(script));
433 6 : }
434 :
435 :
436 : class TestResource: public String::ExternalStringResource {
437 : public:
438 : explicit TestResource(uint16_t* data, int* counter = nullptr,
439 : bool owning_data = true)
440 17942 : : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
441 3064651 : while (data[length_]) ++length_;
442 : }
443 :
444 35878 : ~TestResource() {
445 17942 : if (owning_data_) i::DeleteArray(data_);
446 17942 : if (counter_ != nullptr) ++*counter_;
447 35878 : }
448 :
449 57060 : const uint16_t* data() const {
450 57060 : return data_;
451 : }
452 :
453 53760 : size_t length() const {
454 53760 : return length_;
455 : }
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 70 : length_(strlen(data) - offset),
472 150 : counter_(counter) {}
473 :
474 130 : ~TestOneByteResource() {
475 70 : i::DeleteArray(orig_data_);
476 70 : if (counter_ != nullptr) ++*counter_;
477 130 : }
478 :
479 202 : const char* data() const {
480 202 : return data_;
481 : }
482 :
483 117 : size_t length() const {
484 117 : return length_;
485 : }
486 :
487 : private:
488 : const char* orig_data_;
489 : const char* data_;
490 : size_t length_;
491 : int* counter_;
492 : };
493 :
494 :
495 23724 : THREADED_TEST(ScriptUsingStringResource) {
496 6 : int dispose_count = 0;
497 : const char* c_source = "1 + 2 * 3";
498 6 : uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
499 : {
500 6 : LocalContext env;
501 12 : v8::HandleScope scope(env->GetIsolate());
502 6 : TestResource* resource = new TestResource(two_byte_source, &dispose_count);
503 : Local<String> source =
504 6 : String::NewExternalTwoByte(env->GetIsolate(), resource)
505 6 : .ToLocalChecked();
506 6 : Local<Script> script = v8_compile(source);
507 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
508 6 : CHECK(value->IsNumber());
509 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
510 6 : CHECK(source->IsExternal());
511 6 : CHECK_EQ(resource,
512 : static_cast<TestResource*>(source->GetExternalStringResource()));
513 : String::Encoding encoding = String::UNKNOWN_ENCODING;
514 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
515 : source->GetExternalStringResourceBase(&encoding));
516 6 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
517 6 : CcTest::CollectAllGarbage();
518 12 : CHECK_EQ(0, dispose_count);
519 : }
520 6 : CcTest::i_isolate()->compilation_cache()->Clear();
521 6 : CcTest::CollectAllAvailableGarbage();
522 6 : CHECK_EQ(1, dispose_count);
523 6 : }
524 :
525 :
526 23724 : THREADED_TEST(ScriptUsingOneByteStringResource) {
527 6 : int dispose_count = 0;
528 : const char* c_source = "1 + 2 * 3";
529 : {
530 6 : LocalContext env;
531 12 : v8::HandleScope scope(env->GetIsolate());
532 : TestOneByteResource* resource =
533 6 : new TestOneByteResource(i::StrDup(c_source), &dispose_count);
534 : Local<String> source =
535 6 : String::NewExternalOneByte(env->GetIsolate(), resource)
536 6 : .ToLocalChecked();
537 6 : CHECK(source->IsExternalOneByte());
538 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
539 : source->GetExternalOneByteStringResource());
540 : String::Encoding encoding = String::UNKNOWN_ENCODING;
541 6 : CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
542 : source->GetExternalStringResourceBase(&encoding));
543 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
544 6 : Local<Script> script = v8_compile(source);
545 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
546 6 : CHECK(value->IsNumber());
547 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
548 6 : CcTest::CollectAllGarbage();
549 12 : CHECK_EQ(0, dispose_count);
550 : }
551 6 : CcTest::i_isolate()->compilation_cache()->Clear();
552 6 : CcTest::CollectAllAvailableGarbage();
553 6 : CHECK_EQ(1, dispose_count);
554 6 : }
555 :
556 :
557 23724 : THREADED_TEST(ScriptMakingExternalString) {
558 6 : int dispose_count = 0;
559 6 : uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
560 : {
561 6 : LocalContext env;
562 12 : v8::HandleScope scope(env->GetIsolate());
563 : Local<String> source =
564 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
565 6 : v8::NewStringType::kNormal)
566 6 : .ToLocalChecked();
567 : // Trigger GCs so that the newly allocated string moves to old gen.
568 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
569 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
570 6 : CHECK(!source->IsExternal());
571 6 : CHECK(!source->IsExternalOneByte());
572 : String::Encoding encoding = String::UNKNOWN_ENCODING;
573 6 : CHECK(!source->GetExternalStringResourceBase(&encoding));
574 6 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
575 : bool success = source->MakeExternal(new TestResource(two_byte_source,
576 12 : &dispose_count));
577 6 : CHECK(success);
578 6 : Local<Script> script = v8_compile(source);
579 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
580 6 : CHECK(value->IsNumber());
581 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
582 6 : CcTest::CollectAllGarbage();
583 12 : CHECK_EQ(0, dispose_count);
584 : }
585 6 : CcTest::i_isolate()->compilation_cache()->Clear();
586 6 : CcTest::CollectAllGarbage();
587 6 : CHECK_EQ(1, dispose_count);
588 6 : }
589 :
590 :
591 23724 : THREADED_TEST(ScriptMakingExternalOneByteString) {
592 6 : int dispose_count = 0;
593 : const char* c_source = "1 + 2 * 3";
594 : {
595 6 : LocalContext env;
596 12 : v8::HandleScope scope(env->GetIsolate());
597 6 : Local<String> source = v8_str(c_source);
598 : // Trigger GCs so that the newly allocated string moves to old gen.
599 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
600 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
601 : bool success = source->MakeExternal(
602 12 : new TestOneByteResource(i::StrDup(c_source), &dispose_count));
603 6 : CHECK(success);
604 6 : Local<Script> script = v8_compile(source);
605 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
606 6 : CHECK(value->IsNumber());
607 12 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
608 6 : CcTest::CollectAllGarbage();
609 12 : CHECK_EQ(0, dispose_count);
610 : }
611 6 : CcTest::i_isolate()->compilation_cache()->Clear();
612 6 : CcTest::CollectAllGarbage();
613 6 : CHECK_EQ(1, dispose_count);
614 6 : }
615 :
616 :
617 23723 : TEST(MakingExternalStringConditions) {
618 5 : LocalContext env;
619 10 : v8::HandleScope scope(env->GetIsolate());
620 :
621 : // Free some space in the new space so that we can check freshness.
622 5 : CcTest::CollectGarbage(i::NEW_SPACE);
623 5 : CcTest::CollectGarbage(i::NEW_SPACE);
624 :
625 5 : uint16_t* two_byte_string = AsciiToTwoByteString("s1");
626 : Local<String> local_string =
627 : String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
628 5 : v8::NewStringType::kNormal)
629 5 : .ToLocalChecked();
630 : i::DeleteArray(two_byte_string);
631 :
632 : // We should refuse to externalize new space strings.
633 5 : CHECK(!local_string->CanMakeExternal());
634 : // Trigger GCs so that the newly allocated string moves to old gen.
635 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
636 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
637 : // Old space strings should be accepted.
638 10 : CHECK(local_string->CanMakeExternal());
639 5 : }
640 :
641 :
642 23723 : TEST(MakingExternalOneByteStringConditions) {
643 5 : LocalContext env;
644 10 : v8::HandleScope scope(env->GetIsolate());
645 :
646 : // Free some space in the new space so that we can check freshness.
647 5 : CcTest::CollectGarbage(i::NEW_SPACE);
648 5 : CcTest::CollectGarbage(i::NEW_SPACE);
649 :
650 5 : Local<String> local_string = v8_str("s1");
651 : // We should refuse to externalize new space strings.
652 5 : CHECK(!local_string->CanMakeExternal());
653 : // Trigger GCs so that the newly allocated string moves to old gen.
654 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
655 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
656 : // Old space strings should be accepted.
657 10 : CHECK(local_string->CanMakeExternal());
658 5 : }
659 :
660 :
661 23723 : TEST(MakingExternalUnalignedOneByteString) {
662 5 : LocalContext env;
663 10 : v8::HandleScope scope(env->GetIsolate());
664 :
665 : CompileRun("function cons(a, b) { return a + b; }"
666 : "function slice(a) { return a.substring(1); }");
667 : // Create a cons string that will land in old pointer space.
668 : Local<String> cons = Local<String>::Cast(CompileRun(
669 : "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
670 : // Create a sliced string that will land in old pointer space.
671 : Local<String> slice = Local<String>::Cast(CompileRun(
672 : "slice('abcdefghijklmnopqrstuvwxyz');"));
673 :
674 : // Trigger GCs so that the newly allocated string moves to old gen.
675 5 : i::heap::SimulateFullSpace(CcTest::heap()->old_space());
676 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
677 5 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
678 :
679 : // Turn into external string with unaligned resource data.
680 : const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
681 : bool success = cons->MakeExternal(
682 10 : new TestOneByteResource(i::StrDup(c_cons), nullptr, 1));
683 5 : CHECK(success);
684 : const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
685 : success = slice->MakeExternal(
686 10 : new TestOneByteResource(i::StrDup(c_slice), nullptr, 1));
687 5 : CHECK(success);
688 :
689 : // Trigger GCs and force evacuation.
690 5 : CcTest::CollectAllGarbage();
691 10 : CcTest::CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
692 5 : }
693 :
694 :
695 23724 : THREADED_TEST(UsingExternalString) {
696 : i::Factory* factory = CcTest::i_isolate()->factory();
697 : {
698 6 : v8::HandleScope scope(CcTest::isolate());
699 6 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
700 : Local<String> string =
701 : String::NewExternalTwoByte(CcTest::isolate(),
702 12 : new TestResource(two_byte_string))
703 6 : .ToLocalChecked();
704 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
705 : // Trigger GCs so that the newly allocated string moves to old gen.
706 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
707 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
708 : i::Handle<i::String> isymbol =
709 6 : factory->InternalizeString(istring);
710 6 : CHECK(isymbol->IsInternalizedString());
711 : }
712 6 : CcTest::CollectAllGarbage();
713 6 : CcTest::CollectAllGarbage();
714 6 : }
715 :
716 :
717 23724 : THREADED_TEST(UsingExternalOneByteString) {
718 : i::Factory* factory = CcTest::i_isolate()->factory();
719 : {
720 6 : v8::HandleScope scope(CcTest::isolate());
721 : const char* one_byte_string = "test string";
722 : Local<String> string =
723 : String::NewExternalOneByte(
724 : CcTest::isolate(),
725 12 : new TestOneByteResource(i::StrDup(one_byte_string)))
726 6 : .ToLocalChecked();
727 6 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
728 : // Trigger GCs so that the newly allocated string moves to old gen.
729 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
730 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
731 : i::Handle<i::String> isymbol =
732 6 : factory->InternalizeString(istring);
733 6 : CHECK(isymbol->IsInternalizedString());
734 : }
735 6 : CcTest::CollectAllGarbage();
736 6 : CcTest::CollectAllGarbage();
737 6 : }
738 :
739 :
740 6 : class RandomLengthResource : public v8::String::ExternalStringResource {
741 : public:
742 6 : explicit RandomLengthResource(int length) : length_(length) {}
743 6 : virtual const uint16_t* data() const { return string_; }
744 6 : virtual size_t length() const { return length_; }
745 :
746 : private:
747 : uint16_t string_[10];
748 : int length_;
749 : };
750 :
751 :
752 16 : class RandomLengthOneByteResource
753 : : public v8::String::ExternalOneByteStringResource {
754 : public:
755 11 : explicit RandomLengthOneByteResource(int length) : length_(length) {}
756 16 : virtual const char* data() const { return string_; }
757 21 : virtual size_t length() const { return length_; }
758 :
759 : private:
760 : char string_[10];
761 : int length_;
762 : };
763 :
764 :
765 23724 : THREADED_TEST(NewExternalForVeryLongString) {
766 6 : auto isolate = CcTest::isolate();
767 : {
768 6 : v8::HandleScope scope(isolate);
769 12 : v8::TryCatch try_catch(isolate);
770 : RandomLengthOneByteResource r(1 << 30);
771 : v8::MaybeLocal<v8::String> maybe_str =
772 6 : v8::String::NewExternalOneByte(isolate, &r);
773 6 : CHECK(maybe_str.IsEmpty());
774 12 : CHECK(!try_catch.HasCaught());
775 : }
776 :
777 : {
778 6 : v8::HandleScope scope(isolate);
779 12 : v8::TryCatch try_catch(isolate);
780 : RandomLengthResource r(1 << 30);
781 : v8::MaybeLocal<v8::String> maybe_str =
782 6 : v8::String::NewExternalTwoByte(isolate, &r);
783 6 : CHECK(maybe_str.IsEmpty());
784 12 : CHECK(!try_catch.HasCaught());
785 : }
786 6 : }
787 :
788 :
789 23724 : THREADED_TEST(ScavengeExternalString) {
790 6 : i::FLAG_stress_compaction = false;
791 6 : i::FLAG_gc_global = false;
792 6 : int dispose_count = 0;
793 : bool in_new_space = false;
794 : {
795 6 : v8::HandleScope scope(CcTest::isolate());
796 6 : uint16_t* two_byte_string = AsciiToTwoByteString("test string");
797 : Local<String> string =
798 : String::NewExternalTwoByte(
799 : CcTest::isolate(),
800 12 : new TestResource(two_byte_string, &dispose_count))
801 6 : .ToLocalChecked();
802 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
803 6 : CcTest::CollectGarbage(i::NEW_SPACE);
804 6 : in_new_space = CcTest::heap()->InNewSpace(*istring);
805 6 : CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
806 6 : CHECK_EQ(0, dispose_count);
807 : }
808 6 : CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
809 6 : CHECK_EQ(1, dispose_count);
810 6 : }
811 :
812 :
813 23724 : THREADED_TEST(ScavengeExternalOneByteString) {
814 6 : i::FLAG_stress_compaction = false;
815 6 : i::FLAG_gc_global = false;
816 6 : int dispose_count = 0;
817 : bool in_new_space = false;
818 : {
819 6 : v8::HandleScope scope(CcTest::isolate());
820 : const char* one_byte_string = "test string";
821 : Local<String> string =
822 : String::NewExternalOneByte(
823 : CcTest::isolate(),
824 12 : new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
825 6 : .ToLocalChecked();
826 : i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
827 6 : CcTest::CollectGarbage(i::NEW_SPACE);
828 6 : in_new_space = CcTest::heap()->InNewSpace(*istring);
829 6 : CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
830 6 : CHECK_EQ(0, dispose_count);
831 : }
832 6 : CcTest::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
833 6 : CHECK_EQ(1, dispose_count);
834 6 : }
835 :
836 :
837 10 : class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
838 : public:
839 : // Only used by non-threaded tests, so it can use static fields.
840 : static int dispose_calls;
841 : static int dispose_count;
842 :
843 : TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
844 10 : : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
845 :
846 10 : void Dispose() {
847 10 : ++dispose_calls;
848 10 : if (dispose_) delete this;
849 10 : }
850 : private:
851 : bool dispose_;
852 : };
853 :
854 :
855 : int TestOneByteResourceWithDisposeControl::dispose_count = 0;
856 : int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
857 :
858 :
859 23723 : TEST(ExternalStringWithDisposeHandling) {
860 : const char* c_source = "1 + 2 * 3";
861 :
862 : // Use a stack allocated external string resource allocated object.
863 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
864 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
865 5 : TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
866 : {
867 5 : LocalContext env;
868 10 : v8::HandleScope scope(env->GetIsolate());
869 : Local<String> source =
870 5 : String::NewExternalOneByte(env->GetIsolate(), &res_stack)
871 10 : .ToLocalChecked();
872 5 : Local<Script> script = v8_compile(source);
873 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
874 5 : CHECK(value->IsNumber());
875 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
876 5 : CcTest::CollectAllAvailableGarbage();
877 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
878 : }
879 5 : CcTest::i_isolate()->compilation_cache()->Clear();
880 5 : CcTest::CollectAllAvailableGarbage();
881 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
882 5 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
883 :
884 : // Use a heap allocated external string resource allocated object.
885 5 : TestOneByteResourceWithDisposeControl::dispose_count = 0;
886 5 : TestOneByteResourceWithDisposeControl::dispose_calls = 0;
887 : TestOneByteResource* res_heap =
888 5 : new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
889 : {
890 5 : LocalContext env;
891 10 : v8::HandleScope scope(env->GetIsolate());
892 : Local<String> source =
893 5 : String::NewExternalOneByte(env->GetIsolate(), res_heap)
894 10 : .ToLocalChecked();
895 5 : Local<Script> script = v8_compile(source);
896 10 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
897 5 : CHECK(value->IsNumber());
898 10 : CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
899 5 : CcTest::CollectAllAvailableGarbage();
900 10 : CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
901 : }
902 5 : CcTest::i_isolate()->compilation_cache()->Clear();
903 5 : CcTest::CollectAllAvailableGarbage();
904 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
905 5 : CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
906 5 : }
907 :
908 :
909 23724 : THREADED_TEST(StringConcat) {
910 : {
911 6 : LocalContext env;
912 12 : v8::HandleScope scope(env->GetIsolate());
913 : const char* one_byte_string_1 = "function a_times_t";
914 : const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
915 : const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
916 : const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
917 : const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918 : const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
919 : const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
920 6 : Local<String> left = v8_str(one_byte_string_1);
921 :
922 6 : uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
923 : Local<String> right =
924 : String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
925 6 : v8::NewStringType::kNormal)
926 12 : .ToLocalChecked();
927 : i::DeleteArray(two_byte_source);
928 :
929 6 : Local<String> source = String::Concat(left, right);
930 : right = String::NewExternalOneByte(
931 : env->GetIsolate(),
932 12 : new TestOneByteResource(i::StrDup(one_byte_extern_1)))
933 12 : .ToLocalChecked();
934 6 : source = String::Concat(source, right);
935 : right = String::NewExternalTwoByte(
936 : env->GetIsolate(),
937 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
938 12 : .ToLocalChecked();
939 6 : source = String::Concat(source, right);
940 6 : right = v8_str(one_byte_string_2);
941 6 : source = String::Concat(source, right);
942 :
943 6 : two_byte_source = AsciiToTwoByteString(two_byte_string_2);
944 : right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
945 6 : v8::NewStringType::kNormal)
946 12 : .ToLocalChecked();
947 : i::DeleteArray(two_byte_source);
948 :
949 6 : source = String::Concat(source, right);
950 : right = String::NewExternalTwoByte(
951 : env->GetIsolate(),
952 12 : new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
953 12 : .ToLocalChecked();
954 6 : source = String::Concat(source, right);
955 6 : Local<Script> script = v8_compile(source);
956 12 : Local<Value> value = script->Run(env.local()).ToLocalChecked();
957 6 : CHECK(value->IsNumber());
958 18 : CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
959 : }
960 6 : CcTest::i_isolate()->compilation_cache()->Clear();
961 6 : CcTest::CollectAllGarbage();
962 6 : CcTest::CollectAllGarbage();
963 6 : }
964 :
965 :
966 23724 : THREADED_TEST(GlobalProperties) {
967 6 : LocalContext env;
968 12 : v8::HandleScope scope(env->GetIsolate());
969 6 : v8::Local<v8::Object> global = env->Global();
970 18 : CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
971 18 : Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
972 18 : CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
973 6 : }
974 :
975 :
976 1980 : static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
977 : i::Address callback) {
978 660 : ApiTestFuzzer::Fuzz();
979 660 : CheckReturnValue(info, callback);
980 660 : info.GetReturnValue().Set(v8_str("bad value"));
981 660 : info.GetReturnValue().Set(v8_num(102));
982 660 : }
983 :
984 :
985 330 : static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
986 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
987 : }
988 :
989 :
990 330 : static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
991 330 : return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
992 : }
993 :
994 22 : static void construct_callback(
995 154 : const v8::FunctionCallbackInfo<Value>& info) {
996 22 : ApiTestFuzzer::Fuzz();
997 22 : CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
998 88 : CHECK(
999 : info.This()
1000 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
1001 : .FromJust());
1002 88 : CHECK(
1003 : info.This()
1004 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
1005 : .FromJust());
1006 22 : info.GetReturnValue().Set(v8_str("bad value"));
1007 : info.GetReturnValue().Set(info.This());
1008 22 : }
1009 :
1010 :
1011 330 : static void Return239Callback(
1012 : Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1013 330 : ApiTestFuzzer::Fuzz();
1014 330 : CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1015 330 : info.GetReturnValue().Set(v8_str("bad value"));
1016 330 : info.GetReturnValue().Set(v8_num(239));
1017 330 : }
1018 :
1019 :
1020 : template<typename Handler>
1021 11 : static void TestFunctionTemplateInitializer(Handler handler,
1022 : Handler handler_2) {
1023 : // Test constructor calls.
1024 : {
1025 11 : LocalContext env;
1026 11 : v8::Isolate* isolate = env->GetIsolate();
1027 22 : v8::HandleScope scope(isolate);
1028 :
1029 : Local<v8::FunctionTemplate> fun_templ =
1030 11 : v8::FunctionTemplate::New(isolate, handler);
1031 22 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1032 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1033 11 : Local<Script> script = v8_compile("obj()");
1034 341 : for (int i = 0; i < 30; i++) {
1035 330 : CHECK_EQ(102, v8_run_int32value(script));
1036 11 : }
1037 : }
1038 : // Use SetCallHandler to initialize a function template, should work like
1039 : // the previous one.
1040 : {
1041 11 : LocalContext env;
1042 11 : v8::Isolate* isolate = env->GetIsolate();
1043 22 : v8::HandleScope scope(isolate);
1044 :
1045 11 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1046 11 : fun_templ->SetCallHandler(handler_2);
1047 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1048 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1049 11 : Local<Script> script = v8_compile("obj()");
1050 341 : for (int i = 0; i < 30; i++) {
1051 330 : CHECK_EQ(102, v8_run_int32value(script));
1052 11 : }
1053 : }
1054 11 : }
1055 :
1056 :
1057 : template<typename Constructor, typename Accessor>
1058 11 : static void TestFunctionTemplateAccessor(Constructor constructor,
1059 : Accessor accessor) {
1060 11 : LocalContext env;
1061 22 : v8::HandleScope scope(env->GetIsolate());
1062 :
1063 : Local<v8::FunctionTemplate> fun_templ =
1064 11 : v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1065 11 : fun_templ->SetClassName(v8_str("funky"));
1066 22 : fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1067 11 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1068 55 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1069 : Local<Value> result =
1070 33 : v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1071 33 : CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1072 : CompileRun("var obj_instance = new obj();");
1073 : Local<Script> script;
1074 11 : script = v8_compile("obj_instance.x");
1075 341 : for (int i = 0; i < 30; i++) {
1076 330 : CHECK_EQ(1, v8_run_int32value(script));
1077 : }
1078 11 : script = v8_compile("obj_instance.m");
1079 341 : for (int i = 0; i < 30; i++) {
1080 330 : CHECK_EQ(239, v8_run_int32value(script));
1081 11 : }
1082 11 : }
1083 :
1084 :
1085 47452 : THREADED_PROFILED_TEST(FunctionTemplate) {
1086 11 : TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1087 11 : TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1088 11 : }
1089 :
1090 :
1091 1980 : static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1092 660 : ApiTestFuzzer::Fuzz();
1093 660 : CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1094 660 : info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1095 660 : }
1096 :
1097 :
1098 : template<typename Callback>
1099 11 : static void TestSimpleCallback(Callback callback) {
1100 11 : LocalContext env;
1101 11 : v8::Isolate* isolate = env->GetIsolate();
1102 22 : v8::HandleScope scope(isolate);
1103 :
1104 : v8::Local<v8::ObjectTemplate> object_template =
1105 11 : v8::ObjectTemplate::New(isolate);
1106 22 : object_template->Set(isolate, "callback",
1107 : v8::FunctionTemplate::New(isolate, callback));
1108 : v8::Local<v8::Object> object =
1109 11 : object_template->NewInstance(env.local()).ToLocalChecked();
1110 55 : CHECK((*env)
1111 : ->Global()
1112 : ->Set(env.local(), v8_str("callback_object"), object)
1113 : .FromJust());
1114 : v8::Local<v8::Script> script;
1115 11 : script = v8_compile("callback_object.callback(17)");
1116 341 : for (int i = 0; i < 30; i++) {
1117 330 : CHECK_EQ(51424, v8_run_int32value(script));
1118 : }
1119 11 : script = v8_compile("callback_object.callback(17, 24)");
1120 341 : for (int i = 0; i < 30; i++) {
1121 330 : CHECK_EQ(51425, v8_run_int32value(script));
1122 11 : }
1123 11 : }
1124 :
1125 :
1126 47452 : THREADED_PROFILED_TEST(SimpleCallback) {
1127 11 : TestSimpleCallback(SimpleCallback);
1128 11 : }
1129 :
1130 :
1131 : template<typename T>
1132 : void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1133 :
1134 : // constant return values
1135 : static int32_t fast_return_value_int32 = 471;
1136 : static uint32_t fast_return_value_uint32 = 571;
1137 : static const double kFastReturnValueDouble = 2.7;
1138 : // variable return values
1139 : static bool fast_return_value_bool = false;
1140 : enum ReturnValueOddball {
1141 : kNullReturnValue,
1142 : kUndefinedReturnValue,
1143 : kEmptyStringReturnValue
1144 : };
1145 : static ReturnValueOddball fast_return_value_void;
1146 : static bool fast_return_value_object_is_empty = false;
1147 :
1148 : // Helper function to avoid compiler error: insufficient contextual information
1149 : // to determine type when applying FUNCTION_ADDR to a template function.
1150 : static i::Address address_of(v8::FunctionCallback callback) {
1151 : return FUNCTION_ADDR(callback);
1152 : }
1153 :
1154 : template<>
1155 165 : void FastReturnValueCallback<int32_t>(
1156 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1157 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1158 165 : info.GetReturnValue().Set(fast_return_value_int32);
1159 165 : }
1160 :
1161 : template<>
1162 165 : void FastReturnValueCallback<uint32_t>(
1163 165 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1164 165 : CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1165 165 : info.GetReturnValue().Set(fast_return_value_uint32);
1166 165 : }
1167 :
1168 : template<>
1169 11 : void FastReturnValueCallback<double>(
1170 11 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1171 11 : CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1172 : info.GetReturnValue().Set(kFastReturnValueDouble);
1173 11 : }
1174 :
1175 : template<>
1176 22 : void FastReturnValueCallback<bool>(
1177 22 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1178 22 : CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1179 22 : info.GetReturnValue().Set(fast_return_value_bool);
1180 22 : }
1181 :
1182 : template<>
1183 33 : void FastReturnValueCallback<void>(
1184 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1185 33 : CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1186 33 : switch (fast_return_value_void) {
1187 : case kNullReturnValue:
1188 : info.GetReturnValue().SetNull();
1189 11 : break;
1190 : case kUndefinedReturnValue:
1191 : info.GetReturnValue().SetUndefined();
1192 11 : break;
1193 : case kEmptyStringReturnValue:
1194 : info.GetReturnValue().SetEmptyString();
1195 11 : break;
1196 : }
1197 33 : }
1198 :
1199 : template<>
1200 22 : void FastReturnValueCallback<Object>(
1201 33 : const v8::FunctionCallbackInfo<v8::Value>& info) {
1202 : v8::Local<v8::Object> object;
1203 22 : if (!fast_return_value_object_is_empty) {
1204 11 : object = Object::New(info.GetIsolate());
1205 : }
1206 : info.GetReturnValue().Set(object);
1207 22 : }
1208 :
1209 : template <typename T>
1210 418 : Local<Value> TestFastReturnValues() {
1211 418 : LocalContext env;
1212 418 : v8::Isolate* isolate = env->GetIsolate();
1213 418 : v8::EscapableHandleScope scope(isolate);
1214 : v8::Local<v8::ObjectTemplate> object_template =
1215 418 : v8::ObjectTemplate::New(isolate);
1216 : v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1217 : object_template->Set(isolate, "callback",
1218 836 : v8::FunctionTemplate::New(isolate, callback));
1219 : v8::Local<v8::Object> object =
1220 418 : object_template->NewInstance(env.local()).ToLocalChecked();
1221 2090 : CHECK((*env)
1222 : ->Global()
1223 : ->Set(env.local(), v8_str("callback_object"), object)
1224 : .FromJust());
1225 418 : return scope.Escape(CompileRun("callback_object.callback()"));
1226 : }
1227 :
1228 :
1229 47452 : THREADED_PROFILED_TEST(FastReturnValues) {
1230 11 : LocalContext env;
1231 11 : v8::Isolate* isolate = env->GetIsolate();
1232 22 : v8::HandleScope scope(isolate);
1233 : v8::Local<v8::Value> value;
1234 : // check int32_t and uint32_t
1235 : int32_t int_values[] = {
1236 : 0, 234, -723,
1237 : i::Smi::kMinValue, i::Smi::kMaxValue
1238 11 : };
1239 66 : for (size_t i = 0; i < arraysize(int_values); i++) {
1240 165 : for (int modifier = -1; modifier <= 1; modifier++) {
1241 165 : int int_value = int_values[i] + modifier;
1242 : // check int32_t
1243 165 : fast_return_value_int32 = int_value;
1244 165 : value = TestFastReturnValues<int32_t>();
1245 165 : CHECK(value->IsInt32());
1246 330 : CHECK_EQ(fast_return_value_int32,
1247 : value->Int32Value(env.local()).FromJust());
1248 : // check uint32_t
1249 165 : fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1250 165 : value = TestFastReturnValues<uint32_t>();
1251 165 : CHECK(value->IsUint32());
1252 330 : CHECK_EQ(fast_return_value_uint32,
1253 : value->Uint32Value(env.local()).FromJust());
1254 : }
1255 : }
1256 : // check double
1257 11 : value = TestFastReturnValues<double>();
1258 11 : CHECK(value->IsNumber());
1259 22 : CHECK_EQ(kFastReturnValueDouble,
1260 : value->ToNumber(env.local()).ToLocalChecked()->Value());
1261 : // check bool values
1262 22 : for (int i = 0; i < 2; i++) {
1263 22 : fast_return_value_bool = i == 0;
1264 22 : value = TestFastReturnValues<bool>();
1265 22 : CHECK(value->IsBoolean());
1266 44 : CHECK_EQ(fast_return_value_bool,
1267 : value->ToBoolean(env.local()).ToLocalChecked()->Value());
1268 : }
1269 : // check oddballs
1270 : ReturnValueOddball oddballs[] = {
1271 : kNullReturnValue,
1272 : kUndefinedReturnValue,
1273 : kEmptyStringReturnValue
1274 11 : };
1275 44 : for (size_t i = 0; i < arraysize(oddballs); i++) {
1276 33 : fast_return_value_void = oddballs[i];
1277 33 : value = TestFastReturnValues<void>();
1278 33 : switch (fast_return_value_void) {
1279 : case kNullReturnValue:
1280 11 : CHECK(value->IsNull());
1281 : break;
1282 : case kUndefinedReturnValue:
1283 11 : CHECK(value->IsUndefined());
1284 : break;
1285 : case kEmptyStringReturnValue:
1286 11 : CHECK(value->IsString());
1287 11 : CHECK_EQ(0, v8::String::Cast(*value)->Length());
1288 : break;
1289 : }
1290 : }
1291 : // check handles
1292 11 : fast_return_value_object_is_empty = false;
1293 11 : value = TestFastReturnValues<Object>();
1294 11 : CHECK(value->IsObject());
1295 11 : fast_return_value_object_is_empty = true;
1296 11 : value = TestFastReturnValues<Object>();
1297 22 : CHECK(value->IsUndefined());
1298 11 : }
1299 :
1300 :
1301 23724 : THREADED_TEST(FunctionTemplateSetLength) {
1302 6 : LocalContext env;
1303 6 : v8::Isolate* isolate = env->GetIsolate();
1304 12 : v8::HandleScope scope(isolate);
1305 : {
1306 : Local<v8::FunctionTemplate> fun_templ =
1307 : v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1308 6 : Local<v8::Signature>(), 23);
1309 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1310 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1311 6 : Local<Script> script = v8_compile("obj.length");
1312 6 : CHECK_EQ(23, v8_run_int32value(script));
1313 : }
1314 : {
1315 : Local<v8::FunctionTemplate> fun_templ =
1316 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1317 6 : fun_templ->SetLength(22);
1318 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1319 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1320 6 : Local<Script> script = v8_compile("obj.length");
1321 6 : CHECK_EQ(22, v8_run_int32value(script));
1322 : }
1323 : {
1324 : // Without setting length it defaults to 0.
1325 : Local<v8::FunctionTemplate> fun_templ =
1326 6 : v8::FunctionTemplate::New(isolate, handle_callback);
1327 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1328 30 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1329 6 : Local<Script> script = v8_compile("obj.length");
1330 6 : CHECK_EQ(0, v8_run_int32value(script));
1331 6 : }
1332 6 : }
1333 :
1334 :
1335 : static void* expected_ptr;
1336 16848 : static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1337 8424 : void* ptr = v8::External::Cast(*args.Data())->Value();
1338 8424 : CHECK_EQ(expected_ptr, ptr);
1339 : args.GetReturnValue().Set(true);
1340 8424 : }
1341 :
1342 :
1343 648 : static void TestExternalPointerWrapping() {
1344 648 : LocalContext env;
1345 648 : v8::Isolate* isolate = env->GetIsolate();
1346 1296 : v8::HandleScope scope(isolate);
1347 :
1348 648 : v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1349 :
1350 648 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
1351 4536 : CHECK(obj->Set(env.local(), v8_str("func"),
1352 : v8::FunctionTemplate::New(isolate, callback, data)
1353 : ->GetFunction(env.local())
1354 : .ToLocalChecked())
1355 : .FromJust());
1356 3240 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1357 :
1358 1944 : CHECK(CompileRun("function foo() {\n"
1359 : " for (var i = 0; i < 13; i++) obj.func();\n"
1360 : "}\n"
1361 : "foo(), true")
1362 : ->BooleanValue(env.local())
1363 648 : .FromJust());
1364 648 : }
1365 :
1366 :
1367 23724 : THREADED_TEST(ExternalWrap) {
1368 : // Check heap allocated object.
1369 6 : int* ptr = new int;
1370 6 : expected_ptr = ptr;
1371 6 : TestExternalPointerWrapping();
1372 6 : delete ptr;
1373 :
1374 : // Check stack allocated object.
1375 : int foo;
1376 6 : expected_ptr = &foo;
1377 6 : TestExternalPointerWrapping();
1378 :
1379 : // Check not aligned addresses.
1380 : const int n = 100;
1381 6 : char* s = new char[n];
1382 606 : for (int i = 0; i < n; i++) {
1383 600 : expected_ptr = s + i;
1384 600 : TestExternalPointerWrapping();
1385 : }
1386 :
1387 6 : delete[] s;
1388 :
1389 : // Check several invalid addresses.
1390 6 : expected_ptr = reinterpret_cast<void*>(1);
1391 6 : TestExternalPointerWrapping();
1392 :
1393 6 : expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1394 6 : TestExternalPointerWrapping();
1395 :
1396 6 : expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1397 6 : TestExternalPointerWrapping();
1398 :
1399 : #if defined(V8_HOST_ARCH_X64)
1400 : // Check a value with a leading 1 bit in x64 Smi encoding.
1401 6 : expected_ptr = reinterpret_cast<void*>(0x400000000);
1402 6 : TestExternalPointerWrapping();
1403 :
1404 6 : expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1405 6 : TestExternalPointerWrapping();
1406 :
1407 6 : expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1408 6 : TestExternalPointerWrapping();
1409 : #endif
1410 6 : }
1411 :
1412 :
1413 23724 : THREADED_TEST(FindInstanceInPrototypeChain) {
1414 6 : LocalContext env;
1415 6 : v8::Isolate* isolate = env->GetIsolate();
1416 12 : v8::HandleScope scope(isolate);
1417 :
1418 6 : Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1419 6 : Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1420 6 : Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1421 6 : derived->Inherit(base);
1422 :
1423 : Local<v8::Function> base_function =
1424 12 : base->GetFunction(env.local()).ToLocalChecked();
1425 : Local<v8::Function> derived_function =
1426 6 : derived->GetFunction(env.local()).ToLocalChecked();
1427 : Local<v8::Function> other_function =
1428 12 : other->GetFunction(env.local()).ToLocalChecked();
1429 :
1430 : Local<v8::Object> base_instance =
1431 6 : base_function->NewInstance(env.local()).ToLocalChecked();
1432 : Local<v8::Object> derived_instance =
1433 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1434 : Local<v8::Object> derived_instance2 =
1435 6 : derived_function->NewInstance(env.local()).ToLocalChecked();
1436 : Local<v8::Object> other_instance =
1437 6 : other_function->NewInstance(env.local()).ToLocalChecked();
1438 18 : CHECK(
1439 : derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1440 : .FromJust());
1441 18 : CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1442 : .FromJust());
1443 :
1444 : // base_instance is only an instance of base.
1445 18 : CHECK(base_instance->Equals(env.local(),
1446 : base_instance->FindInstanceInPrototypeChain(base))
1447 : .FromJust());
1448 12 : CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1449 12 : CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1450 :
1451 : // derived_instance is an instance of base and derived.
1452 18 : CHECK(derived_instance->Equals(env.local(),
1453 : derived_instance->FindInstanceInPrototypeChain(
1454 : base))
1455 : .FromJust());
1456 18 : CHECK(derived_instance->Equals(env.local(),
1457 : derived_instance->FindInstanceInPrototypeChain(
1458 : derived))
1459 : .FromJust());
1460 12 : CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1461 :
1462 : // other_instance is an instance of other and its immediate
1463 : // prototype derived_instance2 is an instance of base and derived.
1464 : // Note, derived_instance is an instance of base and derived too,
1465 : // but it comes after derived_instance2 in the prototype chain of
1466 : // other_instance.
1467 18 : CHECK(derived_instance2->Equals(
1468 : env.local(),
1469 : other_instance->FindInstanceInPrototypeChain(base))
1470 : .FromJust());
1471 18 : CHECK(derived_instance2->Equals(env.local(),
1472 : other_instance->FindInstanceInPrototypeChain(
1473 : derived))
1474 : .FromJust());
1475 18 : CHECK(other_instance->Equals(
1476 : env.local(),
1477 : other_instance->FindInstanceInPrototypeChain(other))
1478 6 : .FromJust());
1479 6 : }
1480 :
1481 :
1482 23724 : THREADED_TEST(TinyInteger) {
1483 6 : LocalContext env;
1484 6 : v8::Isolate* isolate = env->GetIsolate();
1485 12 : v8::HandleScope scope(isolate);
1486 :
1487 : int32_t value = 239;
1488 6 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1489 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1490 :
1491 6 : value_obj = v8::Integer::New(isolate, value);
1492 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1493 6 : }
1494 :
1495 :
1496 23724 : THREADED_TEST(BigSmiInteger) {
1497 6 : LocalContext env;
1498 12 : v8::HandleScope scope(env->GetIsolate());
1499 6 : v8::Isolate* isolate = CcTest::isolate();
1500 :
1501 : int32_t value = i::Smi::kMaxValue;
1502 : // We cannot add one to a Smi::kMaxValue without wrapping.
1503 : if (i::SmiValuesAre31Bits()) {
1504 : CHECK(i::Smi::IsValid(value));
1505 : CHECK(!i::Smi::IsValid(value + 1));
1506 :
1507 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1508 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509 :
1510 : value_obj = v8::Integer::New(isolate, value);
1511 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512 6 : }
1513 6 : }
1514 :
1515 :
1516 23724 : THREADED_TEST(BigInteger) {
1517 6 : LocalContext env;
1518 12 : v8::HandleScope scope(env->GetIsolate());
1519 6 : v8::Isolate* isolate = CcTest::isolate();
1520 :
1521 : // We cannot add one to a Smi::kMaxValue without wrapping.
1522 : if (i::SmiValuesAre31Bits()) {
1523 : // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1524 : // The code will not be run in that case, due to the "if" guard.
1525 : int32_t value =
1526 : static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1527 : CHECK_GT(value, i::Smi::kMaxValue);
1528 : CHECK(!i::Smi::IsValid(value));
1529 :
1530 : Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1531 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1532 :
1533 : value_obj = v8::Integer::New(isolate, value);
1534 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1535 6 : }
1536 6 : }
1537 :
1538 :
1539 23724 : THREADED_TEST(TinyUnsignedInteger) {
1540 6 : LocalContext env;
1541 12 : v8::HandleScope scope(env->GetIsolate());
1542 6 : v8::Isolate* isolate = CcTest::isolate();
1543 :
1544 : uint32_t value = 239;
1545 :
1546 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1547 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1548 :
1549 6 : value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1550 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1551 6 : }
1552 :
1553 :
1554 23724 : THREADED_TEST(BigUnsignedSmiInteger) {
1555 6 : LocalContext env;
1556 12 : v8::HandleScope scope(env->GetIsolate());
1557 6 : v8::Isolate* isolate = CcTest::isolate();
1558 :
1559 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1560 : CHECK(i::Smi::IsValid(value));
1561 : CHECK(!i::Smi::IsValid(value + 1));
1562 :
1563 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1564 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1565 :
1566 6 : value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1567 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1568 6 : }
1569 :
1570 :
1571 23724 : THREADED_TEST(BigUnsignedInteger) {
1572 6 : LocalContext env;
1573 12 : v8::HandleScope scope(env->GetIsolate());
1574 6 : v8::Isolate* isolate = CcTest::isolate();
1575 :
1576 : uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1577 : CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1578 : CHECK(!i::Smi::IsValid(value));
1579 :
1580 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1581 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1582 :
1583 6 : value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1584 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1585 6 : }
1586 :
1587 :
1588 23724 : THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1589 6 : LocalContext env;
1590 12 : v8::HandleScope scope(env->GetIsolate());
1591 6 : v8::Isolate* isolate = CcTest::isolate();
1592 :
1593 : uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1594 : uint32_t value = INT32_MAX_AS_UINT + 1;
1595 : CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1596 :
1597 6 : Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1598 6 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1599 :
1600 6 : value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1601 12 : CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1602 6 : }
1603 :
1604 :
1605 23724 : THREADED_TEST(IsNativeError) {
1606 6 : LocalContext env;
1607 12 : v8::HandleScope scope(env->GetIsolate());
1608 : v8::Local<Value> syntax_error = CompileRun(
1609 : "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1610 6 : CHECK(syntax_error->IsNativeError());
1611 : v8::Local<Value> not_error = CompileRun("{a:42}");
1612 6 : CHECK(!not_error->IsNativeError());
1613 : v8::Local<Value> not_object = CompileRun("42");
1614 12 : CHECK(!not_object->IsNativeError());
1615 6 : }
1616 :
1617 :
1618 23724 : THREADED_TEST(IsGeneratorFunctionOrObject) {
1619 6 : LocalContext env;
1620 12 : v8::HandleScope scope(env->GetIsolate());
1621 :
1622 : CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1623 : v8::Local<Value> gen = CompileRun("gen");
1624 : v8::Local<Value> genObj = CompileRun("gen()");
1625 : v8::Local<Value> object = CompileRun("{a:42}");
1626 : v8::Local<Value> func = CompileRun("func");
1627 :
1628 6 : CHECK(gen->IsGeneratorFunction());
1629 6 : CHECK(gen->IsFunction());
1630 6 : CHECK(!gen->IsGeneratorObject());
1631 :
1632 6 : CHECK(!genObj->IsGeneratorFunction());
1633 6 : CHECK(!genObj->IsFunction());
1634 6 : CHECK(genObj->IsGeneratorObject());
1635 :
1636 6 : CHECK(!object->IsGeneratorFunction());
1637 6 : CHECK(!object->IsFunction());
1638 6 : CHECK(!object->IsGeneratorObject());
1639 :
1640 6 : CHECK(!func->IsGeneratorFunction());
1641 6 : CHECK(func->IsFunction());
1642 12 : CHECK(!func->IsGeneratorObject());
1643 6 : }
1644 :
1645 23724 : THREADED_TEST(IsAsyncFunction) {
1646 6 : LocalContext env;
1647 6 : v8::Isolate* isolate = env->GetIsolate();
1648 12 : v8::HandleScope scope(isolate);
1649 :
1650 : CompileRun("async function foo() {}");
1651 : v8::Local<Value> foo = CompileRun("foo");
1652 :
1653 6 : CHECK(foo->IsAsyncFunction());
1654 6 : CHECK(foo->IsFunction());
1655 6 : CHECK(!foo->IsGeneratorFunction());
1656 6 : CHECK(!foo->IsGeneratorObject());
1657 :
1658 : CompileRun("function bar() {}");
1659 : v8::Local<Value> bar = CompileRun("bar");
1660 :
1661 6 : CHECK(!bar->IsAsyncFunction());
1662 12 : CHECK(bar->IsFunction());
1663 6 : }
1664 :
1665 23724 : THREADED_TEST(ArgumentsObject) {
1666 6 : LocalContext env;
1667 12 : v8::HandleScope scope(env->GetIsolate());
1668 : v8::Local<Value> arguments_object =
1669 : CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1670 6 : CHECK(arguments_object->IsArgumentsObject());
1671 : v8::Local<Value> array = CompileRun("[1,2,3]");
1672 6 : CHECK(!array->IsArgumentsObject());
1673 : v8::Local<Value> object = CompileRun("{a:42}");
1674 12 : CHECK(!object->IsArgumentsObject());
1675 6 : }
1676 :
1677 :
1678 23724 : THREADED_TEST(IsMapOrSet) {
1679 6 : LocalContext env;
1680 12 : v8::HandleScope scope(env->GetIsolate());
1681 : v8::Local<Value> map = CompileRun("new Map()");
1682 : v8::Local<Value> set = CompileRun("new Set()");
1683 : v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1684 : v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1685 6 : CHECK(map->IsMap());
1686 6 : CHECK(set->IsSet());
1687 6 : CHECK(weak_map->IsWeakMap());
1688 6 : CHECK(weak_set->IsWeakSet());
1689 :
1690 6 : CHECK(!map->IsSet());
1691 6 : CHECK(!map->IsWeakMap());
1692 6 : CHECK(!map->IsWeakSet());
1693 :
1694 6 : CHECK(!set->IsMap());
1695 6 : CHECK(!set->IsWeakMap());
1696 6 : CHECK(!set->IsWeakSet());
1697 :
1698 6 : CHECK(!weak_map->IsMap());
1699 6 : CHECK(!weak_map->IsSet());
1700 6 : CHECK(!weak_map->IsWeakSet());
1701 :
1702 6 : CHECK(!weak_set->IsMap());
1703 6 : CHECK(!weak_set->IsSet());
1704 6 : CHECK(!weak_set->IsWeakMap());
1705 :
1706 : v8::Local<Value> object = CompileRun("{a:42}");
1707 6 : CHECK(!object->IsMap());
1708 6 : CHECK(!object->IsSet());
1709 6 : CHECK(!object->IsWeakMap());
1710 12 : CHECK(!object->IsWeakSet());
1711 6 : }
1712 :
1713 :
1714 23724 : THREADED_TEST(StringObject) {
1715 6 : LocalContext env;
1716 12 : v8::HandleScope scope(env->GetIsolate());
1717 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1718 6 : CHECK(boxed_string->IsStringObject());
1719 : v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1720 6 : CHECK(!unboxed_string->IsStringObject());
1721 : v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1722 6 : CHECK(!boxed_not_string->IsStringObject());
1723 : v8::Local<Value> not_object = CompileRun("0");
1724 6 : CHECK(!not_object->IsStringObject());
1725 : v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1726 6 : CHECK(!as_boxed.IsEmpty());
1727 6 : Local<v8::String> the_string = as_boxed->ValueOf();
1728 6 : CHECK(!the_string.IsEmpty());
1729 6 : ExpectObject("\"test\"", the_string);
1730 6 : v8::Local<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1731 6 : CHECK(new_boxed_string->IsStringObject());
1732 : as_boxed = new_boxed_string.As<v8::StringObject>();
1733 6 : the_string = as_boxed->ValueOf();
1734 6 : CHECK(!the_string.IsEmpty());
1735 12 : ExpectObject("\"test\"", the_string);
1736 6 : }
1737 :
1738 :
1739 23723 : TEST(StringObjectDelete) {
1740 5 : LocalContext context;
1741 10 : v8::HandleScope scope(context->GetIsolate());
1742 : v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1743 5 : CHECK(boxed_string->IsStringObject());
1744 : v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1745 10 : CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1746 15 : CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1747 5 : }
1748 :
1749 :
1750 23724 : THREADED_TEST(NumberObject) {
1751 6 : LocalContext env;
1752 12 : v8::HandleScope scope(env->GetIsolate());
1753 : v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1754 6 : CHECK(boxed_number->IsNumberObject());
1755 : v8::Local<Value> unboxed_number = CompileRun("42");
1756 6 : CHECK(!unboxed_number->IsNumberObject());
1757 : v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1758 6 : CHECK(!boxed_not_number->IsNumberObject());
1759 : v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1760 6 : CHECK(!as_boxed.IsEmpty());
1761 6 : double the_number = as_boxed->ValueOf();
1762 6 : CHECK_EQ(42.0, the_number);
1763 : v8::Local<v8::Value> new_boxed_number =
1764 6 : v8::NumberObject::New(env->GetIsolate(), 43);
1765 6 : CHECK(new_boxed_number->IsNumberObject());
1766 : as_boxed = new_boxed_number.As<v8::NumberObject>();
1767 6 : the_number = as_boxed->ValueOf();
1768 12 : CHECK_EQ(43.0, the_number);
1769 6 : }
1770 :
1771 :
1772 23724 : THREADED_TEST(BooleanObject) {
1773 6 : LocalContext env;
1774 12 : v8::HandleScope scope(env->GetIsolate());
1775 : v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1776 6 : CHECK(boxed_boolean->IsBooleanObject());
1777 : v8::Local<Value> unboxed_boolean = CompileRun("true");
1778 6 : CHECK(!unboxed_boolean->IsBooleanObject());
1779 : v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1780 6 : CHECK(!boxed_not_boolean->IsBooleanObject());
1781 : v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1782 6 : CHECK(!as_boxed.IsEmpty());
1783 6 : bool the_boolean = as_boxed->ValueOf();
1784 6 : CHECK(the_boolean);
1785 : v8::Local<v8::Value> boxed_true =
1786 6 : v8::BooleanObject::New(env->GetIsolate(), true);
1787 : v8::Local<v8::Value> boxed_false =
1788 6 : v8::BooleanObject::New(env->GetIsolate(), false);
1789 6 : CHECK(boxed_true->IsBooleanObject());
1790 6 : CHECK(boxed_false->IsBooleanObject());
1791 : as_boxed = boxed_true.As<v8::BooleanObject>();
1792 6 : CHECK(as_boxed->ValueOf());
1793 : as_boxed = boxed_false.As<v8::BooleanObject>();
1794 12 : CHECK(!as_boxed->ValueOf());
1795 6 : }
1796 :
1797 :
1798 23724 : THREADED_TEST(PrimitiveAndWrappedBooleans) {
1799 6 : LocalContext env;
1800 12 : v8::HandleScope scope(env->GetIsolate());
1801 :
1802 6 : Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1803 6 : CHECK(primitive_false->IsBoolean());
1804 6 : CHECK(!primitive_false->IsBooleanObject());
1805 12 : CHECK(!primitive_false->BooleanValue(env.local()).FromJust());
1806 6 : CHECK(!primitive_false->IsTrue());
1807 6 : CHECK(primitive_false->IsFalse());
1808 :
1809 6 : Local<Value> false_value = BooleanObject::New(env->GetIsolate(), false);
1810 6 : CHECK(!false_value->IsBoolean());
1811 6 : CHECK(false_value->IsBooleanObject());
1812 12 : CHECK(false_value->BooleanValue(env.local()).FromJust());
1813 6 : CHECK(!false_value->IsTrue());
1814 6 : CHECK(!false_value->IsFalse());
1815 :
1816 : Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1817 6 : CHECK(!false_boolean_object->IsBoolean());
1818 6 : CHECK(false_boolean_object->IsBooleanObject());
1819 12 : CHECK(false_boolean_object->BooleanValue(env.local()).FromJust());
1820 6 : CHECK(!false_boolean_object->ValueOf());
1821 6 : CHECK(!false_boolean_object->IsTrue());
1822 6 : CHECK(!false_boolean_object->IsFalse());
1823 :
1824 6 : Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1825 6 : CHECK(primitive_true->IsBoolean());
1826 6 : CHECK(!primitive_true->IsBooleanObject());
1827 12 : CHECK(primitive_true->BooleanValue(env.local()).FromJust());
1828 6 : CHECK(primitive_true->IsTrue());
1829 6 : CHECK(!primitive_true->IsFalse());
1830 :
1831 6 : Local<Value> true_value = BooleanObject::New(env->GetIsolate(), true);
1832 6 : CHECK(!true_value->IsBoolean());
1833 6 : CHECK(true_value->IsBooleanObject());
1834 12 : CHECK(true_value->BooleanValue(env.local()).FromJust());
1835 6 : CHECK(!true_value->IsTrue());
1836 6 : CHECK(!true_value->IsFalse());
1837 :
1838 : Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1839 6 : CHECK(!true_boolean_object->IsBoolean());
1840 6 : CHECK(true_boolean_object->IsBooleanObject());
1841 12 : CHECK(true_boolean_object->BooleanValue(env.local()).FromJust());
1842 6 : CHECK(true_boolean_object->ValueOf());
1843 6 : CHECK(!true_boolean_object->IsTrue());
1844 12 : CHECK(!true_boolean_object->IsFalse());
1845 6 : }
1846 :
1847 :
1848 23724 : THREADED_TEST(Number) {
1849 6 : LocalContext env;
1850 12 : v8::HandleScope scope(env->GetIsolate());
1851 : double PI = 3.1415926;
1852 6 : Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1853 24 : CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1854 6 : }
1855 :
1856 :
1857 23724 : THREADED_TEST(ToNumber) {
1858 6 : LocalContext env;
1859 6 : v8::Isolate* isolate = CcTest::isolate();
1860 12 : v8::HandleScope scope(isolate);
1861 6 : Local<String> str = v8_str("3.1415926");
1862 18 : CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1863 : v8::Local<v8::Boolean> t = v8::True(isolate);
1864 12 : CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1865 : v8::Local<v8::Boolean> f = v8::False(isolate);
1866 18 : CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1867 6 : }
1868 :
1869 :
1870 23724 : THREADED_TEST(Date) {
1871 6 : LocalContext env;
1872 12 : v8::HandleScope scope(env->GetIsolate());
1873 : double PI = 3.1415926;
1874 6 : Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1875 12 : CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1876 24 : CHECK(date.As<v8::Date>()
1877 : ->Set(env.local(), v8_str("property"),
1878 : v8::Integer::New(env->GetIsolate(), 42))
1879 : .FromJust());
1880 24 : CHECK_EQ(42, date.As<v8::Date>()
1881 : ->Get(env.local(), v8_str("property"))
1882 : .ToLocalChecked()
1883 : ->Int32Value(env.local())
1884 6 : .FromJust());
1885 6 : }
1886 :
1887 :
1888 23724 : THREADED_TEST(Boolean) {
1889 6 : LocalContext env;
1890 6 : v8::Isolate* isolate = env->GetIsolate();
1891 12 : v8::HandleScope scope(isolate);
1892 : v8::Local<v8::Boolean> t = v8::True(isolate);
1893 6 : CHECK(t->Value());
1894 : v8::Local<v8::Boolean> f = v8::False(isolate);
1895 6 : CHECK(!f->Value());
1896 : v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1897 12 : CHECK(!u->BooleanValue(env.local()).FromJust());
1898 : v8::Local<v8::Primitive> n = v8::Null(isolate);
1899 12 : CHECK(!n->BooleanValue(env.local()).FromJust());
1900 6 : v8::Local<String> str1 = v8_str("");
1901 18 : CHECK(!str1->BooleanValue(env.local()).FromJust());
1902 6 : v8::Local<String> str2 = v8_str("x");
1903 18 : CHECK(str2->BooleanValue(env.local()).FromJust());
1904 18 : CHECK(!v8::Number::New(isolate, 0)->BooleanValue(env.local()).FromJust());
1905 18 : CHECK(v8::Number::New(isolate, -1)->BooleanValue(env.local()).FromJust());
1906 18 : CHECK(v8::Number::New(isolate, 1)->BooleanValue(env.local()).FromJust());
1907 18 : CHECK(v8::Number::New(isolate, 42)->BooleanValue(env.local()).FromJust());
1908 24 : CHECK(!v8_compile("NaN")
1909 : ->Run(env.local())
1910 : .ToLocalChecked()
1911 : ->BooleanValue(env.local())
1912 6 : .FromJust());
1913 6 : }
1914 :
1915 :
1916 12 : static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1917 6 : ApiTestFuzzer::Fuzz();
1918 6 : args.GetReturnValue().Set(v8_num(13.4));
1919 6 : }
1920 :
1921 :
1922 6 : static void GetM(Local<String> name,
1923 : const v8::PropertyCallbackInfo<v8::Value>& info) {
1924 6 : ApiTestFuzzer::Fuzz();
1925 6 : info.GetReturnValue().Set(v8_num(876));
1926 6 : }
1927 :
1928 :
1929 23724 : THREADED_TEST(GlobalPrototype) {
1930 6 : v8::Isolate* isolate = CcTest::isolate();
1931 6 : v8::HandleScope scope(isolate);
1932 : v8::Local<v8::FunctionTemplate> func_templ =
1933 6 : v8::FunctionTemplate::New(isolate);
1934 12 : func_templ->PrototypeTemplate()->Set(
1935 12 : isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1936 6 : v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1937 6 : templ->Set(isolate, "x", v8_num(200));
1938 6 : templ->SetAccessor(v8_str("m"), GetM);
1939 12 : LocalContext env(0, templ);
1940 : v8::Local<Script> script(v8_compile("dummy()"));
1941 6 : v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1942 12 : CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
1943 6 : CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
1944 12 : CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
1945 6 : }
1946 :
1947 :
1948 23724 : THREADED_TEST(ObjectTemplate) {
1949 6 : LocalContext env;
1950 6 : v8::Isolate* isolate = CcTest::isolate();
1951 12 : v8::HandleScope scope(isolate);
1952 : Local<v8::FunctionTemplate> acc =
1953 6 : v8::FunctionTemplate::New(isolate, Returns42);
1954 42 : CHECK(env->Global()
1955 : ->Set(env.local(), v8_str("acc"),
1956 : acc->GetFunction(env.local()).ToLocalChecked())
1957 : .FromJust());
1958 :
1959 6 : Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1960 6 : v8::Local<v8::String> class_name = v8_str("the_class_name");
1961 6 : fun->SetClassName(class_name);
1962 6 : Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
1963 6 : templ1->Set(isolate, "x", v8_num(10));
1964 6 : templ1->Set(isolate, "y", v8_num(13));
1965 12 : templ1->Set(v8_str("foo"), acc);
1966 : Local<v8::Object> instance1 =
1967 6 : templ1->NewInstance(env.local()).ToLocalChecked();
1968 12 : CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
1969 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
1970 18 : CHECK(CompileRun("(p.x == 10)")->BooleanValue(env.local()).FromJust());
1971 18 : CHECK(CompileRun("(p.y == 13)")->BooleanValue(env.local()).FromJust());
1972 18 : CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(env.local()).FromJust());
1973 18 : CHECK(CompileRun("(p.foo == acc)")->BooleanValue(env.local()).FromJust());
1974 : // Ensure that foo become a data field.
1975 : CompileRun("p.foo = function() {}");
1976 6 : Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
1977 12 : fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1978 6 : Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
1979 6 : templ2->Set(isolate, "a", v8_num(12));
1980 : templ2->Set(isolate, "b", templ1);
1981 12 : templ2->Set(v8_str("bar"), acc);
1982 12 : templ2->SetAccessorProperty(v8_str("acc"), acc);
1983 : Local<v8::Object> instance2 =
1984 6 : templ2->NewInstance(env.local()).ToLocalChecked();
1985 30 : CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
1986 18 : CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(env.local()).FromJust());
1987 18 : CHECK(CompileRun("(q.a == 12)")->BooleanValue(env.local()).FromJust());
1988 18 : CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(env.local()).FromJust());
1989 18 : CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(env.local()).FromJust());
1990 18 : CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
1991 18 : CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(env.local()).FromJust());
1992 18 : CHECK(CompileRun("(q.b !== p)")->BooleanValue(env.local()).FromJust());
1993 18 : CHECK(CompileRun("(q.acc == 42)")->BooleanValue(env.local()).FromJust());
1994 18 : CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(env.local()).FromJust());
1995 18 : CHECK(CompileRun("(q.bar == acc)")->BooleanValue(env.local()).FromJust());
1996 :
1997 6 : instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
1998 30 : CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
1999 18 : CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(env.local()).FromJust());
2000 18 : CHECK(CompileRun("(q2.a == 12)")->BooleanValue(env.local()).FromJust());
2001 18 : CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(env.local()).FromJust());
2002 18 : CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(env.local()).FromJust());
2003 18 : CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
2004 18 : CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(env.local()).FromJust());
2005 18 : CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(env.local()).FromJust());
2006 18 : CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(env.local()).FromJust());
2007 18 : CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(env.local()).FromJust());
2008 :
2009 18 : CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(env.local()).FromJust());
2010 18 : CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")
2011 : ->BooleanValue(env.local())
2012 : .FromJust());
2013 18 : CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
2014 : "(desc1.get === acc)")
2015 : ->BooleanValue(env.local())
2016 : .FromJust());
2017 18 : CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
2018 : "(desc2.get === acc)")
2019 : ->BooleanValue(env.local())
2020 6 : .FromJust());
2021 6 : }
2022 :
2023 23724 : THREADED_TEST(IntegerValue) {
2024 6 : LocalContext env;
2025 6 : v8::Isolate* isolate = CcTest::isolate();
2026 12 : v8::HandleScope scope(isolate);
2027 :
2028 24 : CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
2029 6 : }
2030 :
2031 126 : static void GetNirk(Local<String> name,
2032 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2033 126 : ApiTestFuzzer::Fuzz();
2034 126 : info.GetReturnValue().Set(v8_num(900));
2035 126 : }
2036 :
2037 126 : static void GetRino(Local<String> name,
2038 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2039 126 : ApiTestFuzzer::Fuzz();
2040 126 : info.GetReturnValue().Set(v8_num(560));
2041 126 : }
2042 :
2043 : enum ObjectInstantiationMode {
2044 : // Create object using ObjectTemplate::NewInstance.
2045 : ObjectTemplate_NewInstance,
2046 : // Create object using FunctionTemplate::NewInstance on constructor.
2047 : Constructor_GetFunction_NewInstance,
2048 : // Create object using new operator on constructor.
2049 : Constructor_GetFunction_New
2050 : };
2051 :
2052 : // Test object instance creation using a function template with an instance
2053 : // template inherited from another function template with accessors and data
2054 : // properties in prototype template.
2055 18 : static void TestObjectTemplateInheritedWithPrototype(
2056 : ObjectInstantiationMode mode) {
2057 18 : LocalContext env;
2058 18 : v8::Isolate* isolate = CcTest::isolate();
2059 36 : v8::HandleScope scope(isolate);
2060 :
2061 18 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2062 18 : fun_A->SetClassName(v8_str("A"));
2063 18 : v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
2064 18 : prototype_templ->Set(isolate, "a", v8_num(113));
2065 18 : prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2066 18 : prototype_templ->Set(isolate, "b", v8_num(153));
2067 :
2068 18 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2069 18 : v8::Local<v8::String> class_name = v8_str("B");
2070 18 : fun_B->SetClassName(class_name);
2071 18 : fun_B->Inherit(fun_A);
2072 18 : prototype_templ = fun_B->PrototypeTemplate();
2073 18 : prototype_templ->Set(isolate, "c", v8_num(713));
2074 18 : prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
2075 18 : prototype_templ->Set(isolate, "d", v8_num(753));
2076 :
2077 18 : Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
2078 18 : templ->Set(isolate, "x", v8_num(10));
2079 18 : templ->Set(isolate, "y", v8_num(13));
2080 :
2081 : // Perform several iterations to trigger creation from cached boilerplate.
2082 72 : for (int i = 0; i < 3; i++) {
2083 : Local<v8::Object> instance;
2084 54 : switch (mode) {
2085 : case ObjectTemplate_NewInstance:
2086 18 : instance = templ->NewInstance(env.local()).ToLocalChecked();
2087 18 : break;
2088 :
2089 : case Constructor_GetFunction_NewInstance: {
2090 : Local<v8::Function> function_B =
2091 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2092 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2093 : break;
2094 : }
2095 : case Constructor_GetFunction_New: {
2096 : Local<v8::Function> function_B =
2097 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2098 18 : if (i == 0) {
2099 24 : CHECK(env->Global()
2100 : ->Set(env.local(), class_name, function_B)
2101 : .FromJust());
2102 : }
2103 : instance =
2104 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2105 : break;
2106 : }
2107 : default:
2108 0 : UNREACHABLE();
2109 : }
2110 :
2111 108 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2112 270 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2113 :
2114 162 : CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2115 162 : CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2116 :
2117 162 : CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2118 162 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2119 162 : CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2120 162 : CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2121 162 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2122 162 : CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2123 18 : }
2124 18 : }
2125 :
2126 23724 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2127 6 : TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2128 6 : }
2129 :
2130 23724 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2131 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2132 6 : }
2133 :
2134 23724 : THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2135 6 : TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2136 6 : }
2137 :
2138 : // Test object instance creation using a function template without an instance
2139 : // template inherited from another function template.
2140 12 : static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2141 : ObjectInstantiationMode mode) {
2142 12 : LocalContext env;
2143 12 : v8::Isolate* isolate = CcTest::isolate();
2144 24 : v8::HandleScope scope(isolate);
2145 :
2146 12 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2147 12 : fun_A->SetClassName(v8_str("A"));
2148 :
2149 12 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2150 12 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2151 12 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2152 :
2153 12 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2154 12 : v8::Local<v8::String> class_name = v8_str("B");
2155 12 : fun_B->SetClassName(class_name);
2156 12 : fun_B->Inherit(fun_A);
2157 :
2158 : // Perform several iterations to trigger creation from cached boilerplate.
2159 48 : for (int i = 0; i < 3; i++) {
2160 : Local<v8::Object> instance;
2161 36 : switch (mode) {
2162 : case Constructor_GetFunction_NewInstance: {
2163 : Local<v8::Function> function_B =
2164 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2165 18 : instance = function_B->NewInstance(env.local()).ToLocalChecked();
2166 : break;
2167 : }
2168 : case Constructor_GetFunction_New: {
2169 : Local<v8::Function> function_B =
2170 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2171 18 : if (i == 0) {
2172 24 : CHECK(env->Global()
2173 : ->Set(env.local(), class_name, function_B)
2174 : .FromJust());
2175 : }
2176 : instance =
2177 36 : CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2178 : break;
2179 : }
2180 : default:
2181 0 : UNREACHABLE();
2182 : }
2183 :
2184 72 : CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2185 180 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2186 :
2187 108 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2188 108 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2189 12 : }
2190 12 : }
2191 :
2192 23724 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2193 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2194 6 : Constructor_GetFunction_NewInstance);
2195 6 : }
2196 :
2197 23724 : THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2198 : TestObjectTemplateInheritedWithoutInstanceTemplate(
2199 6 : Constructor_GetFunction_New);
2200 6 : }
2201 :
2202 23724 : THREADED_TEST(TestObjectTemplateClassInheritance) {
2203 6 : LocalContext env;
2204 6 : v8::Isolate* isolate = CcTest::isolate();
2205 12 : v8::HandleScope scope(isolate);
2206 :
2207 6 : Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2208 6 : fun_A->SetClassName(v8_str("A"));
2209 :
2210 6 : Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2211 6 : templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2212 6 : templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2213 :
2214 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2215 6 : v8::Local<v8::String> class_name = v8_str("B");
2216 6 : fun_B->SetClassName(class_name);
2217 6 : fun_B->Inherit(fun_A);
2218 :
2219 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2220 : v8::Local<v8::Object> b_proto;
2221 : v8::Local<v8::Object> c_proto;
2222 : // Perform several iterations to make sure the cache doesn't break
2223 : // subclassing.
2224 24 : for (int i = 0; i < 3; i++) {
2225 : Local<v8::Function> function_B =
2226 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2227 18 : if (i == 0) {
2228 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2229 : CompileRun("class C extends B {}");
2230 : b_proto =
2231 12 : CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2232 : c_proto =
2233 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2234 12 : CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2235 : }
2236 : Local<v8::Object> instance =
2237 36 : CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2238 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2239 :
2240 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2241 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2242 :
2243 54 : CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2244 54 : CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2245 6 : }
2246 6 : }
2247 :
2248 276 : static void NamedPropertyGetterWhichReturns42(
2249 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2250 276 : info.GetReturnValue().Set(v8_num(42));
2251 276 : }
2252 :
2253 23724 : THREADED_TEST(TestObjectTemplateReflectConstruct) {
2254 6 : LocalContext env;
2255 6 : v8::Isolate* isolate = CcTest::isolate();
2256 12 : v8::HandleScope scope(isolate);
2257 :
2258 6 : Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2259 : fun_B->InstanceTemplate()->SetHandler(
2260 12 : v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2261 6 : v8::Local<v8::String> class_name = v8_str("B");
2262 6 : fun_B->SetClassName(class_name);
2263 :
2264 6 : v8::Local<v8::String> subclass_name = v8_str("C");
2265 : v8::Local<v8::Object> b_proto;
2266 : v8::Local<v8::Object> c_proto;
2267 : // Perform several iterations to make sure the cache doesn't break
2268 : // subclassing.
2269 24 : for (int i = 0; i < 3; i++) {
2270 : Local<v8::Function> function_B =
2271 18 : fun_B->GetFunction(env.local()).ToLocalChecked();
2272 18 : if (i == 0) {
2273 24 : CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2274 : CompileRun("function C() {}");
2275 : c_proto =
2276 12 : CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2277 : }
2278 : Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2279 18 : ->ToObject(env.local())
2280 18 : .ToLocalChecked();
2281 36 : CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2282 :
2283 36 : CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2284 90 : CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2285 :
2286 54 : CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2287 54 : CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2288 6 : }
2289 6 : }
2290 :
2291 24 : static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2292 12 : ApiTestFuzzer::Fuzz();
2293 12 : args.GetReturnValue().Set(v8_num(17.2));
2294 12 : }
2295 :
2296 :
2297 30 : static void GetKnurd(Local<String> property,
2298 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2299 30 : ApiTestFuzzer::Fuzz();
2300 30 : info.GetReturnValue().Set(v8_num(15.2));
2301 30 : }
2302 :
2303 :
2304 23724 : THREADED_TEST(DescriptorInheritance) {
2305 6 : v8::Isolate* isolate = CcTest::isolate();
2306 6 : v8::HandleScope scope(isolate);
2307 6 : v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2308 12 : super->PrototypeTemplate()->Set(isolate, "flabby",
2309 : v8::FunctionTemplate::New(isolate,
2310 12 : GetFlabby));
2311 12 : super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2312 :
2313 12 : super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2314 :
2315 6 : v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2316 6 : base1->Inherit(super);
2317 12 : base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2318 :
2319 6 : v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2320 6 : base2->Inherit(super);
2321 12 : base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2322 :
2323 12 : LocalContext env;
2324 :
2325 36 : CHECK(env->Global()
2326 : ->Set(env.local(), v8_str("s"),
2327 : super->GetFunction(env.local()).ToLocalChecked())
2328 : .FromJust());
2329 36 : CHECK(env->Global()
2330 : ->Set(env.local(), v8_str("base1"),
2331 : base1->GetFunction(env.local()).ToLocalChecked())
2332 : .FromJust());
2333 36 : CHECK(env->Global()
2334 : ->Set(env.local(), v8_str("base2"),
2335 : base2->GetFunction(env.local()).ToLocalChecked())
2336 : .FromJust());
2337 :
2338 : // Checks right __proto__ chain.
2339 18 : CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2340 : ->BooleanValue(env.local())
2341 : .FromJust());
2342 18 : CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2343 : ->BooleanValue(env.local())
2344 : .FromJust());
2345 :
2346 24 : CHECK(v8_compile("s.prototype.PI == 3.14")
2347 : ->Run(env.local())
2348 : .ToLocalChecked()
2349 : ->BooleanValue(env.local())
2350 : .FromJust());
2351 :
2352 : // Instance accessor should not be visible on function object or its prototype
2353 18 : CHECK(
2354 : CompileRun("s.knurd == undefined")->BooleanValue(env.local()).FromJust());
2355 18 : CHECK(CompileRun("s.prototype.knurd == undefined")
2356 : ->BooleanValue(env.local())
2357 : .FromJust());
2358 18 : CHECK(CompileRun("base1.prototype.knurd == undefined")
2359 : ->BooleanValue(env.local())
2360 : .FromJust());
2361 :
2362 36 : CHECK(env->Global()
2363 : ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2364 : .ToLocalChecked()
2365 : ->NewInstance(env.local())
2366 : .ToLocalChecked())
2367 : .FromJust());
2368 18 : CHECK_EQ(17.2,
2369 : CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2370 18 : CHECK(CompileRun("'flabby' in obj")->BooleanValue(env.local()).FromJust());
2371 18 : CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2372 18 : CHECK(CompileRun("'knurd' in obj")->BooleanValue(env.local()).FromJust());
2373 18 : CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2374 :
2375 36 : CHECK(env->Global()
2376 : ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2377 : .ToLocalChecked()
2378 : ->NewInstance(env.local())
2379 : .ToLocalChecked())
2380 : .FromJust());
2381 18 : CHECK_EQ(17.2,
2382 : CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2383 18 : CHECK(CompileRun("'flabby' in obj2")->BooleanValue(env.local()).FromJust());
2384 18 : CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2385 18 : CHECK(CompileRun("'knurd' in obj2")->BooleanValue(env.local()).FromJust());
2386 18 : CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2387 :
2388 : // base1 and base2 cannot cross reference to each's prototype
2389 6 : CHECK(CompileRun("obj.v2")->IsUndefined());
2390 12 : CHECK(CompileRun("obj2.v1")->IsUndefined());
2391 6 : }
2392 :
2393 23724 : THREADED_TEST(DescriptorInheritance2) {
2394 6 : LocalContext env;
2395 6 : v8::Isolate* isolate = CcTest::isolate();
2396 12 : v8::HandleScope scope(isolate);
2397 6 : v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2398 6 : fun_A->SetClassName(v8_str("A"));
2399 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2400 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2401 12 : fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2402 :
2403 6 : v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2404 6 : fun_B->SetClassName(v8_str("B"));
2405 6 : fun_B->Inherit(fun_A);
2406 :
2407 6 : v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2408 6 : fun_C->SetClassName(v8_str("C"));
2409 6 : fun_C->Inherit(fun_B);
2410 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2411 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2412 12 : fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2413 :
2414 6 : v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2415 6 : fun_D->SetClassName(v8_str("D"));
2416 6 : fun_D->Inherit(fun_C);
2417 :
2418 6 : v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2419 6 : fun_E->SetClassName(v8_str("E"));
2420 6 : fun_E->Inherit(fun_D);
2421 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2422 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2423 12 : fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2424 :
2425 6 : v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2426 6 : fun_F->SetClassName(v8_str("F"));
2427 6 : fun_F->Inherit(fun_E);
2428 6 : v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2429 : const int kDataPropertiesNumber = 100;
2430 606 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2431 600 : v8::Local<v8::Value> val = v8_num(i);
2432 1200 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2433 600 : v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
2434 :
2435 600 : templ->Set(name, val);
2436 600 : templ->Set(val_str, val);
2437 : }
2438 :
2439 36 : CHECK(env->Global()
2440 : ->Set(env.local(), v8_str("F"),
2441 : fun_F->GetFunction(env.local()).ToLocalChecked())
2442 : .FromJust());
2443 :
2444 : v8::Local<v8::Script> script = v8_compile("o = new F()");
2445 :
2446 606 : for (int i = 0; i < 100; i++) {
2447 600 : v8::HandleScope scope(isolate);
2448 600 : script->Run(env.local()).ToLocalChecked();
2449 600 : }
2450 6 : v8::Local<v8::Object> object = script->Run(env.local())
2451 6 : .ToLocalChecked()
2452 6 : ->ToObject(env.local())
2453 6 : .ToLocalChecked();
2454 :
2455 18 : CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2456 18 : CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2457 18 : CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2458 :
2459 18 : CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2460 18 : CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2461 18 : CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2462 :
2463 18 : CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2464 18 : CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2465 18 : CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2466 :
2467 600 : for (int i = 0; i < kDataPropertiesNumber; i++) {
2468 600 : v8::Local<v8::Value> val = v8_num(i);
2469 1800 : v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2470 600 : v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
2471 :
2472 2400 : CHECK_EQ(i, object->Get(env.local(), name)
2473 : .ToLocalChecked()
2474 : ->IntegerValue(env.local())
2475 : .FromJust());
2476 1800 : CHECK_EQ(i, object->Get(env.local(), val)
2477 : .ToLocalChecked()
2478 : ->IntegerValue(env.local())
2479 : .FromJust());
2480 6 : }
2481 6 : }
2482 :
2483 :
2484 : // Helper functions for Interceptor/Accessor interaction tests
2485 :
2486 36 : void SimpleAccessorGetter(Local<String> name,
2487 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2488 : Local<Object> self = Local<Object>::Cast(info.This());
2489 : info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(),
2490 108 : String::Concat(v8_str("accessor_"), name))
2491 36 : .ToLocalChecked());
2492 36 : }
2493 :
2494 6 : void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2495 : const v8::PropertyCallbackInfo<void>& info) {
2496 : Local<Object> self = Local<Object>::Cast(info.This());
2497 18 : CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2498 : String::Concat(v8_str("accessor_"), name), value)
2499 : .FromJust());
2500 6 : }
2501 :
2502 36 : void SymbolAccessorGetter(Local<Name> name,
2503 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2504 36 : CHECK(name->IsSymbol());
2505 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2506 72 : if (sym->Name()->IsUndefined())
2507 36 : return;
2508 36 : SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2509 : }
2510 :
2511 6 : void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2512 : const v8::PropertyCallbackInfo<void>& info) {
2513 6 : CHECK(name->IsSymbol());
2514 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2515 12 : if (sym->Name()->IsUndefined())
2516 6 : return;
2517 6 : SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2518 : }
2519 :
2520 5 : void SymbolAccessorGetterReturnsDefault(
2521 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2522 5 : CHECK(name->IsSymbol());
2523 : Local<Symbol> sym = Local<Symbol>::Cast(name);
2524 15 : if (sym->Name()->IsUndefined()) return;
2525 : info.GetReturnValue().Set(info.Data());
2526 : }
2527 :
2528 5 : static void ThrowingSymbolAccessorGetter(
2529 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2530 10 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2531 5 : }
2532 :
2533 :
2534 23724 : THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2535 6 : v8::Isolate* isolate = CcTest::isolate();
2536 6 : v8::HandleScope scope(isolate);
2537 12 : LocalContext env;
2538 : v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2539 : i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2540 6 : CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
2541 : CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2542 6 : CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
2543 : // But we should still have an AccessorInfo.
2544 12 : i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2545 6 : i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2546 6 : CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2547 18 : CHECK(it.GetAccessors()->IsAccessorInfo());
2548 6 : }
2549 :
2550 :
2551 23724 : THREADED_TEST(UndefinedIsNotEnumerable) {
2552 6 : LocalContext env;
2553 12 : v8::HandleScope scope(env->GetIsolate());
2554 : v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2555 12 : CHECK(result->IsFalse());
2556 6 : }
2557 :
2558 :
2559 : v8::Local<Script> call_recursively_script;
2560 : static const int kTargetRecursionDepth = 100; // near maximum
2561 :
2562 606 : static void CallScriptRecursivelyCall(
2563 3012 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2564 606 : ApiTestFuzzer::Fuzz();
2565 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2566 : int depth = args.This()
2567 1212 : ->Get(context, v8_str("depth"))
2568 606 : .ToLocalChecked()
2569 : ->Int32Value(context)
2570 1212 : .FromJust();
2571 612 : if (depth == kTargetRecursionDepth) return;
2572 3000 : CHECK(args.This()
2573 : ->Set(context, v8_str("depth"),
2574 : v8::Integer::New(args.GetIsolate(), depth + 1))
2575 : .FromJust());
2576 : args.GetReturnValue().Set(
2577 600 : call_recursively_script->Run(context).ToLocalChecked());
2578 : }
2579 :
2580 :
2581 606 : static void CallFunctionRecursivelyCall(
2582 4212 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2583 606 : ApiTestFuzzer::Fuzz();
2584 606 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2585 : int depth = args.This()
2586 1212 : ->Get(context, v8_str("depth"))
2587 606 : .ToLocalChecked()
2588 : ->Int32Value(context)
2589 1212 : .FromJust();
2590 606 : if (depth == kTargetRecursionDepth) {
2591 : printf("[depth = %d]\n", depth);
2592 612 : return;
2593 : }
2594 3000 : CHECK(args.This()
2595 : ->Set(context, v8_str("depth"),
2596 : v8::Integer::New(args.GetIsolate(), depth + 1))
2597 : .FromJust());
2598 : v8::Local<Value> function =
2599 : args.This()
2600 1200 : ->Get(context, v8_str("callFunctionRecursively"))
2601 600 : .ToLocalChecked();
2602 : args.GetReturnValue().Set(function.As<Function>()
2603 600 : ->Call(context, args.This(), 0, nullptr)
2604 600 : .ToLocalChecked());
2605 : }
2606 :
2607 :
2608 23724 : THREADED_TEST(DeepCrossLanguageRecursion) {
2609 6 : v8::Isolate* isolate = CcTest::isolate();
2610 6 : v8::HandleScope scope(isolate);
2611 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2612 : global->Set(v8_str("callScriptRecursively"),
2613 18 : v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2614 : global->Set(v8_str("callFunctionRecursively"),
2615 18 : v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2616 12 : LocalContext env(nullptr, global);
2617 :
2618 36 : CHECK(env->Global()
2619 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2620 : .FromJust());
2621 6 : call_recursively_script = v8_compile("callScriptRecursively()");
2622 12 : call_recursively_script->Run(env.local()).ToLocalChecked();
2623 6 : call_recursively_script = v8::Local<Script>();
2624 :
2625 36 : CHECK(env->Global()
2626 : ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2627 : .FromJust());
2628 6 : CompileRun("callFunctionRecursively()");
2629 6 : }
2630 :
2631 :
2632 24 : static void ThrowingPropertyHandlerGet(
2633 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2634 : // Since this interceptor is used on "with" objects, the runtime will look up
2635 : // @@unscopables. Punt.
2636 48 : if (key->IsSymbol()) return;
2637 12 : ApiTestFuzzer::Fuzz();
2638 24 : info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2639 : }
2640 :
2641 :
2642 0 : static void ThrowingPropertyHandlerSet(
2643 : Local<Name> key, Local<Value>,
2644 : const v8::PropertyCallbackInfo<v8::Value>& info) {
2645 0 : info.GetIsolate()->ThrowException(key);
2646 : info.GetReturnValue().SetUndefined(); // not the same as empty handle
2647 0 : }
2648 :
2649 :
2650 23724 : THREADED_TEST(CallbackExceptionRegression) {
2651 6 : v8::Isolate* isolate = CcTest::isolate();
2652 6 : v8::HandleScope scope(isolate);
2653 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2654 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2655 6 : ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2656 12 : LocalContext env;
2657 36 : CHECK(env->Global()
2658 : ->Set(env.local(), v8_str("obj"),
2659 : obj->NewInstance(env.local()).ToLocalChecked())
2660 : .FromJust());
2661 : v8::Local<Value> otto =
2662 6 : CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2663 18 : CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2664 : v8::Local<Value> netto =
2665 6 : CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2666 24 : CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2667 6 : }
2668 :
2669 :
2670 23724 : THREADED_TEST(FunctionPrototype) {
2671 6 : v8::Isolate* isolate = CcTest::isolate();
2672 6 : v8::HandleScope scope(isolate);
2673 6 : Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2674 24 : Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2675 12 : LocalContext env;
2676 36 : CHECK(env->Global()
2677 : ->Set(env.local(), v8_str("Foo"),
2678 : Foo->GetFunction(env.local()).ToLocalChecked())
2679 : .FromJust());
2680 6 : Local<Script> script = v8_compile("Foo.prototype.plak");
2681 12 : CHECK_EQ(v8_run_int32value(script), 321);
2682 6 : }
2683 :
2684 23724 : THREADED_TEST(InternalFields) {
2685 6 : LocalContext env;
2686 6 : v8::Isolate* isolate = env->GetIsolate();
2687 12 : v8::HandleScope scope(isolate);
2688 :
2689 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2690 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2691 6 : instance_templ->SetInternalFieldCount(1);
2692 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2693 6 : .ToLocalChecked()
2694 6 : ->NewInstance(env.local())
2695 : .ToLocalChecked();
2696 6 : CHECK_EQ(1, obj->InternalFieldCount());
2697 6 : CHECK(obj->GetInternalField(0)->IsUndefined());
2698 6 : obj->SetInternalField(0, v8_num(17));
2699 24 : CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2700 6 : }
2701 :
2702 23724 : THREADED_TEST(InternalFieldsOfRegularObjects) {
2703 6 : LocalContext env;
2704 6 : v8::Isolate* isolate = env->GetIsolate();
2705 12 : v8::HandleScope scope(isolate);
2706 :
2707 6 : const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"};
2708 24 : for (size_t i = 0; i < arraysize(sources); ++i) {
2709 : i::ScopedVector<char> source(128);
2710 18 : i::SNPrintF(source, "(function() { return %s })()", sources[i]);
2711 : v8::Local<v8::Object> obj = CompileRun(source.start()).As<v8::Object>();
2712 18 : CHECK_EQ(0, obj->InternalFieldCount());
2713 6 : }
2714 6 : }
2715 :
2716 23724 : THREADED_TEST(GlobalObjectInternalFields) {
2717 6 : v8::Isolate* isolate = CcTest::isolate();
2718 6 : v8::HandleScope scope(isolate);
2719 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2720 6 : global_template->SetInternalFieldCount(1);
2721 12 : LocalContext env(nullptr, global_template);
2722 6 : v8::Local<v8::Object> global_proxy = env->Global();
2723 6 : v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2724 6 : CHECK_EQ(1, global->InternalFieldCount());
2725 6 : CHECK(global->GetInternalField(0)->IsUndefined());
2726 6 : global->SetInternalField(0, v8_num(17));
2727 24 : CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2728 6 : }
2729 :
2730 :
2731 23724 : THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2732 6 : LocalContext env;
2733 12 : v8::HandleScope scope(CcTest::isolate());
2734 :
2735 6 : v8::Local<v8::Object> global = env->Global();
2736 18 : CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2737 18 : CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2738 6 : }
2739 :
2740 24 : static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2741 : void* value) {
2742 24 : CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2743 24 : obj->SetAlignedPointerInInternalField(0, value);
2744 24 : CcTest::CollectAllGarbage();
2745 24 : CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2746 24 : }
2747 :
2748 23724 : THREADED_TEST(InternalFieldsAlignedPointers) {
2749 6 : LocalContext env;
2750 6 : v8::Isolate* isolate = env->GetIsolate();
2751 12 : v8::HandleScope scope(isolate);
2752 :
2753 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2754 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2755 6 : instance_templ->SetInternalFieldCount(1);
2756 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2757 6 : .ToLocalChecked()
2758 6 : ->NewInstance(env.local())
2759 : .ToLocalChecked();
2760 6 : CHECK_EQ(1, obj->InternalFieldCount());
2761 :
2762 6 : CheckAlignedPointerInInternalField(obj, nullptr);
2763 :
2764 6 : int* heap_allocated = new int[100];
2765 6 : CheckAlignedPointerInInternalField(obj, heap_allocated);
2766 6 : delete[] heap_allocated;
2767 :
2768 : int stack_allocated[100];
2769 6 : CheckAlignedPointerInInternalField(obj, stack_allocated);
2770 :
2771 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2772 6 : CheckAlignedPointerInInternalField(obj, huge);
2773 :
2774 : v8::Global<v8::Object> persistent(isolate, obj);
2775 6 : CHECK_EQ(1, Object::InternalFieldCount(persistent));
2776 12 : CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2777 6 : }
2778 :
2779 23724 : THREADED_TEST(SetAlignedPointerInInternalFields) {
2780 6 : LocalContext env;
2781 6 : v8::Isolate* isolate = env->GetIsolate();
2782 12 : v8::HandleScope scope(isolate);
2783 :
2784 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2785 6 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2786 6 : instance_templ->SetInternalFieldCount(2);
2787 6 : Local<v8::Object> obj = templ->GetFunction(env.local())
2788 6 : .ToLocalChecked()
2789 6 : ->NewInstance(env.local())
2790 : .ToLocalChecked();
2791 6 : CHECK_EQ(2, obj->InternalFieldCount());
2792 :
2793 6 : int* heap_allocated_1 = new int[100];
2794 6 : int* heap_allocated_2 = new int[100];
2795 6 : int indices[] = {0, 1};
2796 6 : void* values[] = {heap_allocated_1, heap_allocated_2};
2797 :
2798 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2799 6 : CcTest::CollectAllGarbage();
2800 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0));
2801 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1));
2802 :
2803 6 : indices[0] = 1;
2804 6 : indices[1] = 0;
2805 6 : obj->SetAlignedPointerInInternalFields(2, indices, values);
2806 6 : CcTest::CollectAllGarbage();
2807 6 : CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0));
2808 6 : CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1));
2809 :
2810 6 : delete[] heap_allocated_1;
2811 12 : delete[] heap_allocated_2;
2812 6 : }
2813 :
2814 24 : static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2815 : void* value) {
2816 24 : CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2817 24 : (*env)->SetAlignedPointerInEmbedderData(index, value);
2818 24 : CcTest::CollectAllGarbage();
2819 24 : CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2820 24 : }
2821 :
2822 :
2823 : static void* AlignedTestPointer(int i) {
2824 1200 : return reinterpret_cast<void*>(i * 1234);
2825 : }
2826 :
2827 :
2828 23724 : THREADED_TEST(EmbedderDataAlignedPointers) {
2829 6 : LocalContext env;
2830 12 : v8::HandleScope scope(env->GetIsolate());
2831 :
2832 6 : CheckAlignedPointerInEmbedderData(&env, 0, nullptr);
2833 :
2834 6 : int* heap_allocated = new int[100];
2835 6 : CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2836 6 : delete[] heap_allocated;
2837 :
2838 : int stack_allocated[100];
2839 6 : CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2840 :
2841 : void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2842 6 : CheckAlignedPointerInEmbedderData(&env, 3, huge);
2843 :
2844 : // Test growing of the embedder data's backing store.
2845 606 : for (int i = 0; i < 100; i++) {
2846 600 : env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2847 : }
2848 6 : CcTest::CollectAllGarbage();
2849 606 : for (int i = 0; i < 100; i++) {
2850 600 : CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2851 6 : }
2852 6 : }
2853 :
2854 24 : static void CheckEmbedderData(LocalContext* env, int index,
2855 : v8::Local<Value> data) {
2856 24 : (*env)->SetEmbedderData(index, data);
2857 24 : CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2858 24 : }
2859 :
2860 :
2861 23724 : THREADED_TEST(EmbedderData) {
2862 6 : LocalContext env;
2863 6 : v8::Isolate* isolate = env->GetIsolate();
2864 12 : v8::HandleScope scope(isolate);
2865 :
2866 12 : CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
2867 12 : CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
2868 12 : CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2869 12 : CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2870 6 : }
2871 :
2872 :
2873 23724 : THREADED_TEST(IdentityHash) {
2874 6 : LocalContext env;
2875 6 : v8::Isolate* isolate = env->GetIsolate();
2876 12 : v8::HandleScope scope(isolate);
2877 :
2878 : // Ensure that the test starts with an fresh heap to test whether the hash
2879 : // code is based on the address.
2880 6 : CcTest::CollectAllGarbage();
2881 6 : Local<v8::Object> obj = v8::Object::New(isolate);
2882 6 : int hash = obj->GetIdentityHash();
2883 6 : int hash1 = obj->GetIdentityHash();
2884 6 : CHECK_EQ(hash, hash1);
2885 12 : int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2886 : // Since the identity hash is essentially a random number two consecutive
2887 : // objects should not be assigned the same hash code. If the test below fails
2888 : // the random number generator should be evaluated.
2889 6 : CHECK_NE(hash, hash2);
2890 6 : CcTest::CollectAllGarbage();
2891 12 : int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2892 : // Make sure that the identity hash is not based on the initial address of
2893 : // the object alone. If the test below fails the random number generator
2894 : // should be evaluated.
2895 6 : CHECK_NE(hash, hash3);
2896 6 : int hash4 = obj->GetIdentityHash();
2897 6 : CHECK_EQ(hash, hash4);
2898 :
2899 : // Check identity hashes behaviour in the presence of JS accessors.
2900 : // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2901 : {
2902 : CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2903 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
2904 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
2905 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2906 : }
2907 : {
2908 : CompileRun(
2909 : "function cnst() { return 42; };\n"
2910 : "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2911 6 : Local<v8::Object> o1 = v8::Object::New(isolate);
2912 6 : Local<v8::Object> o2 = v8::Object::New(isolate);
2913 12 : CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2914 6 : }
2915 6 : }
2916 :
2917 :
2918 12 : void GlobalProxyIdentityHash(bool set_in_js) {
2919 12 : LocalContext env;
2920 12 : v8::Isolate* isolate = env->GetIsolate();
2921 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2922 24 : v8::HandleScope scope(isolate);
2923 12 : Local<Object> global_proxy = env->Global();
2924 : i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
2925 60 : CHECK(env->Global()
2926 : ->Set(env.local(), v8_str("global"), global_proxy)
2927 : .FromJust());
2928 : int32_t hash1;
2929 12 : if (set_in_js) {
2930 : CompileRun("var m = new Set(); m.add(global);");
2931 6 : i::Object* original_hash = i_global_proxy->GetHash();
2932 6 : CHECK(original_hash->IsSmi());
2933 : hash1 = i::Smi::ToInt(original_hash);
2934 : } else {
2935 6 : hash1 = i_global_proxy->GetOrCreateHash(i_isolate)->value();
2936 : }
2937 : // Hash should be retained after being detached.
2938 12 : env->DetachGlobal();
2939 12 : int hash2 = global_proxy->GetIdentityHash();
2940 12 : CHECK_EQ(hash1, hash2);
2941 : {
2942 : // Re-attach global proxy to a new context, hash should stay the same.
2943 12 : LocalContext env2(nullptr, Local<ObjectTemplate>(), global_proxy);
2944 12 : int hash3 = global_proxy->GetIdentityHash();
2945 12 : CHECK_EQ(hash1, hash3);
2946 12 : }
2947 12 : }
2948 :
2949 :
2950 23724 : THREADED_TEST(GlobalProxyIdentityHash) {
2951 6 : GlobalProxyIdentityHash(true);
2952 6 : GlobalProxyIdentityHash(false);
2953 6 : }
2954 :
2955 :
2956 23723 : TEST(SymbolIdentityHash) {
2957 5 : LocalContext env;
2958 5 : v8::Isolate* isolate = env->GetIsolate();
2959 10 : v8::HandleScope scope(isolate);
2960 :
2961 : {
2962 5 : Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2963 5 : int hash = symbol->GetIdentityHash();
2964 5 : int hash1 = symbol->GetIdentityHash();
2965 5 : CHECK_EQ(hash, hash1);
2966 5 : CcTest::CollectAllGarbage();
2967 5 : int hash3 = symbol->GetIdentityHash();
2968 5 : CHECK_EQ(hash, hash3);
2969 : }
2970 :
2971 : {
2972 : v8::Local<v8::Symbol> js_symbol =
2973 : CompileRun("Symbol('foo')").As<v8::Symbol>();
2974 5 : int hash = js_symbol->GetIdentityHash();
2975 5 : int hash1 = js_symbol->GetIdentityHash();
2976 5 : CHECK_EQ(hash, hash1);
2977 5 : CcTest::CollectAllGarbage();
2978 5 : int hash3 = js_symbol->GetIdentityHash();
2979 5 : CHECK_EQ(hash, hash3);
2980 5 : }
2981 5 : }
2982 :
2983 :
2984 23723 : TEST(StringIdentityHash) {
2985 5 : LocalContext env;
2986 5 : v8::Isolate* isolate = env->GetIsolate();
2987 10 : v8::HandleScope scope(isolate);
2988 :
2989 5 : Local<v8::String> str = v8_str("str1");
2990 5 : int hash = str->GetIdentityHash();
2991 5 : int hash1 = str->GetIdentityHash();
2992 5 : CHECK_EQ(hash, hash1);
2993 5 : CcTest::CollectAllGarbage();
2994 5 : int hash3 = str->GetIdentityHash();
2995 5 : CHECK_EQ(hash, hash3);
2996 :
2997 5 : Local<v8::String> str2 = v8_str("str1");
2998 5 : int hash4 = str2->GetIdentityHash();
2999 10 : CHECK_EQ(hash, hash4);
3000 5 : }
3001 :
3002 :
3003 23724 : THREADED_TEST(SymbolProperties) {
3004 6 : LocalContext env;
3005 6 : v8::Isolate* isolate = env->GetIsolate();
3006 12 : v8::HandleScope scope(isolate);
3007 :
3008 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3009 6 : v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3010 6 : v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
3011 6 : v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
3012 6 : v8::Local<v8::Symbol> sym4 = v8::Symbol::New(isolate, v8_str("native"));
3013 :
3014 6 : CcTest::CollectAllGarbage();
3015 :
3016 : // Check basic symbol functionality.
3017 6 : CHECK(sym1->IsSymbol());
3018 6 : CHECK(sym2->IsSymbol());
3019 6 : CHECK(!obj->IsSymbol());
3020 :
3021 12 : CHECK(sym1->Equals(env.local(), sym1).FromJust());
3022 12 : CHECK(sym2->Equals(env.local(), sym2).FromJust());
3023 12 : CHECK(!sym1->Equals(env.local(), sym2).FromJust());
3024 12 : CHECK(!sym2->Equals(env.local(), sym1).FromJust());
3025 6 : CHECK(sym1->StrictEquals(sym1));
3026 6 : CHECK(sym2->StrictEquals(sym2));
3027 6 : CHECK(!sym1->StrictEquals(sym2));
3028 6 : CHECK(!sym2->StrictEquals(sym1));
3029 :
3030 24 : CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
3031 :
3032 : v8::Local<v8::Value> sym_val = sym2;
3033 6 : CHECK(sym_val->IsSymbol());
3034 12 : CHECK(sym_val->Equals(env.local(), sym2).FromJust());
3035 6 : CHECK(sym_val->StrictEquals(sym2));
3036 12 : CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
3037 :
3038 6 : v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3039 6 : CHECK(sym_obj->IsSymbolObject());
3040 6 : CHECK(!sym2->IsSymbolObject());
3041 6 : CHECK(!obj->IsSymbolObject());
3042 12 : CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
3043 6 : CHECK(!sym_obj->StrictEquals(sym2));
3044 12 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3045 : ->Equals(env.local(), sym_obj)
3046 : .FromJust());
3047 18 : CHECK(v8::SymbolObject::Cast(*sym_obj)
3048 : ->ValueOf()
3049 : ->Equals(env.local(), sym2)
3050 : .FromJust());
3051 :
3052 : // Make sure delete of a non-existent symbol property works.
3053 12 : CHECK(obj->Delete(env.local(), sym1).FromJust());
3054 12 : CHECK(!obj->Has(env.local(), sym1).FromJust());
3055 :
3056 18 : CHECK(
3057 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
3058 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3059 24 : CHECK_EQ(1503, obj->Get(env.local(), sym1)
3060 : .ToLocalChecked()
3061 : ->Int32Value(env.local())
3062 : .FromJust());
3063 18 : CHECK(
3064 : obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
3065 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3066 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3067 : .ToLocalChecked()
3068 : ->Int32Value(env.local())
3069 : .FromJust());
3070 12 : CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
3071 :
3072 12 : CHECK_EQ(0u,
3073 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3074 : unsigned num_props =
3075 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3076 24 : CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
3077 : .FromJust());
3078 12 : CHECK_EQ(1u,
3079 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3080 12 : CHECK_EQ(num_props + 1,
3081 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3082 :
3083 6 : CcTest::CollectAllGarbage();
3084 :
3085 12 : CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
3086 : SymbolAccessorSetter)
3087 : .FromJust());
3088 12 : CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
3089 18 : CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
3090 30 : CHECK(obj->Get(env.local(), sym3)
3091 : .ToLocalChecked()
3092 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3093 : .FromJust());
3094 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3095 : .ToLocalChecked()
3096 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3097 : .FromJust());
3098 :
3099 12 : CHECK(obj->SetNativeDataProperty(env.local(), sym4, SymbolAccessorGetter)
3100 : .FromJust());
3101 12 : CHECK(obj->Get(env.local(), sym4).ToLocalChecked()->IsUndefined());
3102 24 : CHECK(obj->Set(env.local(), v8_str("accessor_native"),
3103 : v8::Integer::New(isolate, 123))
3104 : .FromJust());
3105 24 : CHECK_EQ(123, obj->Get(env.local(), sym4)
3106 : .ToLocalChecked()
3107 : ->Int32Value(env.local())
3108 : .FromJust());
3109 18 : CHECK(obj->Set(env.local(), sym4, v8::Integer::New(isolate, 314)).FromJust());
3110 30 : CHECK(obj->Get(env.local(), sym4)
3111 : .ToLocalChecked()
3112 : ->Equals(env.local(), v8::Integer::New(isolate, 314))
3113 : .FromJust());
3114 18 : CHECK(obj->Delete(env.local(), v8_str("accessor_native")).FromJust());
3115 :
3116 : // Add another property and delete it afterwards to force the object in
3117 : // slow case.
3118 18 : CHECK(
3119 : obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
3120 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3121 : .ToLocalChecked()
3122 : ->Int32Value(env.local())
3123 : .FromJust());
3124 24 : CHECK_EQ(2008, obj->Get(env.local(), sym2)
3125 : .ToLocalChecked()
3126 : ->Int32Value(env.local())
3127 : .FromJust());
3128 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3129 : .ToLocalChecked()
3130 : ->Int32Value(env.local())
3131 : .FromJust());
3132 12 : CHECK_EQ(2u,
3133 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3134 :
3135 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3136 12 : CHECK(obj->Has(env.local(), sym2).FromJust());
3137 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3138 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3139 12 : CHECK(obj->Delete(env.local(), sym2).FromJust());
3140 12 : CHECK(obj->Has(env.local(), sym1).FromJust());
3141 12 : CHECK(!obj->Has(env.local(), sym2).FromJust());
3142 12 : CHECK(obj->Has(env.local(), sym3).FromJust());
3143 18 : CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3144 24 : CHECK_EQ(2002, obj->Get(env.local(), sym1)
3145 : .ToLocalChecked()
3146 : ->Int32Value(env.local())
3147 : .FromJust());
3148 30 : CHECK(obj->Get(env.local(), sym3)
3149 : .ToLocalChecked()
3150 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3151 : .FromJust());
3152 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3153 : .ToLocalChecked()
3154 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3155 : .FromJust());
3156 12 : CHECK_EQ(2u,
3157 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3158 :
3159 : // Symbol properties are inherited.
3160 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3161 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3162 12 : CHECK(child->Has(env.local(), sym1).FromJust());
3163 24 : CHECK_EQ(2002, child->Get(env.local(), sym1)
3164 : .ToLocalChecked()
3165 : ->Int32Value(env.local())
3166 : .FromJust());
3167 30 : CHECK(obj->Get(env.local(), sym3)
3168 : .ToLocalChecked()
3169 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3170 : .FromJust());
3171 30 : CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3172 : .ToLocalChecked()
3173 : ->Equals(env.local(), v8::Integer::New(isolate, 42))
3174 : .FromJust());
3175 12 : CHECK_EQ(0u,
3176 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3177 6 : }
3178 :
3179 :
3180 23724 : THREADED_TEST(SymbolTemplateProperties) {
3181 6 : LocalContext env;
3182 6 : v8::Isolate* isolate = env->GetIsolate();
3183 12 : v8::HandleScope scope(isolate);
3184 6 : v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3185 6 : v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3186 6 : CHECK(!name.IsEmpty());
3187 18 : foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3188 : v8::Local<v8::Object> new_instance =
3189 18 : foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3190 6 : CHECK(!new_instance.IsEmpty());
3191 18 : CHECK(new_instance->Has(env.local(), name).FromJust());
3192 6 : }
3193 :
3194 :
3195 23724 : THREADED_TEST(PrivatePropertiesOnProxies) {
3196 6 : LocalContext env;
3197 6 : v8::Isolate* isolate = env->GetIsolate();
3198 12 : v8::HandleScope scope(isolate);
3199 :
3200 6 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3201 6 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3202 :
3203 : v8::Local<v8::Proxy> proxy =
3204 6 : v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3205 :
3206 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3207 : v8::Local<v8::Private> priv2 =
3208 6 : v8::Private::New(isolate, v8_str("my-private"));
3209 :
3210 6 : CcTest::CollectAllGarbage();
3211 :
3212 30 : CHECK(priv2->Name()
3213 : ->Equals(env.local(),
3214 : v8::String::NewFromUtf8(isolate, "my-private",
3215 : v8::NewStringType::kNormal)
3216 : .ToLocalChecked())
3217 : .FromJust());
3218 :
3219 : // Make sure delete of a non-existent private symbol property works.
3220 12 : proxy->DeletePrivate(env.local(), priv1).FromJust();
3221 12 : CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3222 :
3223 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3224 : .FromJust());
3225 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3226 18 : CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3227 : .ToLocalChecked()
3228 : ->Int32Value(env.local())
3229 : .FromJust());
3230 18 : CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3231 : .FromJust());
3232 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3233 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3234 : .ToLocalChecked()
3235 : ->Int32Value(env.local())
3236 : .FromJust());
3237 :
3238 12 : CHECK_EQ(0u,
3239 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3240 : unsigned num_props =
3241 12 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3242 24 : CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3243 : isolate, "bla", v8::NewStringType::kNormal)
3244 : .ToLocalChecked(),
3245 : v8::Integer::New(isolate, 20))
3246 : .FromJust());
3247 12 : CHECK_EQ(1u,
3248 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3249 12 : CHECK_EQ(num_props + 1,
3250 : proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3251 :
3252 6 : CcTest::CollectAllGarbage();
3253 :
3254 : // Add another property and delete it afterwards to force the object in
3255 : // slow case.
3256 18 : CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3257 : .FromJust());
3258 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3259 : .ToLocalChecked()
3260 : ->Int32Value(env.local())
3261 : .FromJust());
3262 18 : CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3263 : .ToLocalChecked()
3264 : ->Int32Value(env.local())
3265 : .FromJust());
3266 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3267 : .ToLocalChecked()
3268 : ->Int32Value(env.local())
3269 : .FromJust());
3270 12 : CHECK_EQ(1u,
3271 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3272 :
3273 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3274 12 : CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3275 12 : CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3276 12 : CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3277 12 : CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3278 18 : CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3279 : .ToLocalChecked()
3280 : ->Int32Value(env.local())
3281 : .FromJust());
3282 12 : CHECK_EQ(1u,
3283 : proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3284 :
3285 : // Private properties are not inherited (for the time being).
3286 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3287 12 : CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3288 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3289 12 : CHECK_EQ(0u,
3290 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3291 6 : }
3292 :
3293 :
3294 23724 : THREADED_TEST(PrivateProperties) {
3295 6 : LocalContext env;
3296 6 : v8::Isolate* isolate = env->GetIsolate();
3297 12 : v8::HandleScope scope(isolate);
3298 :
3299 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3300 6 : v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3301 : v8::Local<v8::Private> priv2 =
3302 6 : v8::Private::New(isolate, v8_str("my-private"));
3303 :
3304 6 : CcTest::CollectAllGarbage();
3305 :
3306 30 : CHECK(priv2->Name()
3307 : ->Equals(env.local(),
3308 : v8::String::NewFromUtf8(isolate, "my-private",
3309 : v8::NewStringType::kNormal)
3310 : .ToLocalChecked())
3311 : .FromJust());
3312 :
3313 : // Make sure delete of a non-existent private symbol property works.
3314 12 : obj->DeletePrivate(env.local(), priv1).FromJust();
3315 12 : CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3316 :
3317 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3318 : .FromJust());
3319 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3320 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3321 : .ToLocalChecked()
3322 : ->Int32Value(env.local())
3323 : .FromJust());
3324 18 : CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3325 : .FromJust());
3326 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3327 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3328 : .ToLocalChecked()
3329 : ->Int32Value(env.local())
3330 : .FromJust());
3331 :
3332 12 : CHECK_EQ(0u,
3333 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3334 : unsigned num_props =
3335 12 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3336 24 : CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3337 : isolate, "bla", v8::NewStringType::kNormal)
3338 : .ToLocalChecked(),
3339 : v8::Integer::New(isolate, 20))
3340 : .FromJust());
3341 12 : CHECK_EQ(1u,
3342 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3343 12 : CHECK_EQ(num_props + 1,
3344 : obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3345 :
3346 6 : CcTest::CollectAllGarbage();
3347 :
3348 : // Add another property and delete it afterwards to force the object in
3349 : // slow case.
3350 18 : CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3351 : .FromJust());
3352 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3353 : .ToLocalChecked()
3354 : ->Int32Value(env.local())
3355 : .FromJust());
3356 18 : CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3357 : .ToLocalChecked()
3358 : ->Int32Value(env.local())
3359 : .FromJust());
3360 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3361 : .ToLocalChecked()
3362 : ->Int32Value(env.local())
3363 : .FromJust());
3364 12 : CHECK_EQ(1u,
3365 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3366 :
3367 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3368 12 : CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3369 12 : CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3370 12 : CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3371 12 : CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3372 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3373 : .ToLocalChecked()
3374 : ->Int32Value(env.local())
3375 : .FromJust());
3376 12 : CHECK_EQ(1u,
3377 : obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3378 :
3379 : // Private properties are not inherited (for the time being).
3380 6 : v8::Local<v8::Object> child = v8::Object::New(isolate);
3381 12 : CHECK(child->SetPrototype(env.local(), obj).FromJust());
3382 12 : CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3383 12 : CHECK_EQ(0u,
3384 6 : child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3385 6 : }
3386 :
3387 :
3388 23724 : THREADED_TEST(GlobalSymbols) {
3389 6 : LocalContext env;
3390 6 : v8::Isolate* isolate = env->GetIsolate();
3391 12 : v8::HandleScope scope(isolate);
3392 :
3393 6 : v8::Local<String> name = v8_str("my-symbol");
3394 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3395 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3396 6 : CHECK(glob2->SameValue(glob));
3397 :
3398 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3399 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3400 6 : CHECK(glob_api2->SameValue(glob_api));
3401 6 : CHECK(!glob_api->SameValue(glob));
3402 :
3403 6 : v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3404 6 : CHECK(!sym->SameValue(glob));
3405 :
3406 : CompileRun("var sym2 = Symbol.for('my-symbol')");
3407 : v8::Local<Value> sym2 =
3408 30 : env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3409 6 : CHECK(sym2->SameValue(glob));
3410 12 : CHECK(!sym2->SameValue(glob_api));
3411 6 : }
3412 :
3413 23724 : THREADED_TEST(GlobalSymbolsNoContext) {
3414 6 : v8::Isolate* isolate = CcTest::isolate();
3415 6 : v8::HandleScope scope(isolate);
3416 :
3417 6 : v8::Local<String> name = v8_str("my-symbol");
3418 6 : v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3419 6 : v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3420 6 : CHECK(glob2->SameValue(glob));
3421 :
3422 6 : v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3423 6 : v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3424 6 : CHECK(glob_api2->SameValue(glob_api));
3425 6 : CHECK(!glob_api->SameValue(glob));
3426 6 : }
3427 :
3428 60 : static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3429 : const char* name) {
3430 60 : LocalContext env;
3431 60 : v8::Isolate* isolate = env->GetIsolate();
3432 120 : v8::HandleScope scope(isolate);
3433 :
3434 60 : v8::Local<v8::Symbol> symbol = getter(isolate);
3435 120 : std::string script = std::string("var sym = ") + name;
3436 : CompileRun(script.c_str());
3437 : v8::Local<Value> value =
3438 300 : env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3439 :
3440 60 : CHECK(!value.IsEmpty());
3441 60 : CHECK(!symbol.IsEmpty());
3442 120 : CHECK(value->SameValue(symbol));
3443 60 : }
3444 :
3445 :
3446 23724 : THREADED_TEST(WellKnownSymbols) {
3447 6 : CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3448 6 : CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3449 6 : CheckWellKnownSymbol(v8::Symbol::GetHasInstance, "Symbol.hasInstance");
3450 : CheckWellKnownSymbol(v8::Symbol::GetIsConcatSpreadable,
3451 6 : "Symbol.isConcatSpreadable");
3452 6 : CheckWellKnownSymbol(v8::Symbol::GetMatch, "Symbol.match");
3453 6 : CheckWellKnownSymbol(v8::Symbol::GetReplace, "Symbol.replace");
3454 6 : CheckWellKnownSymbol(v8::Symbol::GetSearch, "Symbol.search");
3455 6 : CheckWellKnownSymbol(v8::Symbol::GetSplit, "Symbol.split");
3456 6 : CheckWellKnownSymbol(v8::Symbol::GetToPrimitive, "Symbol.toPrimitive");
3457 6 : CheckWellKnownSymbol(v8::Symbol::GetToStringTag, "Symbol.toStringTag");
3458 6 : }
3459 :
3460 :
3461 23724 : THREADED_TEST(GlobalPrivates) {
3462 6 : i::FLAG_allow_natives_syntax = true;
3463 6 : LocalContext env;
3464 6 : v8::Isolate* isolate = env->GetIsolate();
3465 12 : v8::HandleScope scope(isolate);
3466 :
3467 6 : v8::Local<String> name = v8_str("my-private");
3468 6 : v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3469 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
3470 18 : CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3471 : .FromJust());
3472 :
3473 6 : v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3474 12 : CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3475 :
3476 6 : v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3477 12 : CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3478 :
3479 : CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3480 : v8::Local<Value> intern =
3481 30 : env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3482 18 : CHECK(!obj->Has(env.local(), intern).FromJust());
3483 6 : }
3484 :
3485 :
3486 : class ScopedArrayBufferContents {
3487 : public:
3488 : explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3489 30 : : contents_(contents) {}
3490 30 : ~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
3491 : void* Data() const { return contents_.Data(); }
3492 : size_t ByteLength() const { return contents_.ByteLength(); }
3493 :
3494 : void* AllocationBase() const { return contents_.AllocationBase(); }
3495 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3496 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3497 : return contents_.AllocationMode();
3498 : }
3499 :
3500 : private:
3501 : const v8::ArrayBuffer::Contents contents_;
3502 : };
3503 :
3504 : template <typename T>
3505 276 : static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3506 276 : CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3507 552 : for (int i = 0; i < value->InternalFieldCount(); i++) {
3508 1656 : CHECK_EQ(0, value->GetInternalField(i)
3509 : ->Int32Value(CcTest::isolate()->GetCurrentContext())
3510 : .FromJust());
3511 : }
3512 276 : }
3513 :
3514 :
3515 23724 : THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3516 6 : LocalContext env;
3517 6 : v8::Isolate* isolate = env->GetIsolate();
3518 12 : v8::HandleScope handle_scope(isolate);
3519 :
3520 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3521 6 : CheckInternalFieldsAreZero(ab);
3522 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3523 6 : CHECK(!ab->IsExternal());
3524 6 : CcTest::CollectAllGarbage();
3525 :
3526 12 : ScopedArrayBufferContents ab_contents(ab->Externalize());
3527 6 : CHECK(ab->IsExternal());
3528 :
3529 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3530 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3531 6 : CHECK_NOT_NULL(data);
3532 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3533 :
3534 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3535 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3536 :
3537 : result = CompileRun(
3538 : "var u8 = new Uint8Array(ab);"
3539 : "u8[0] = 0xFF;"
3540 : "u8[1] = 0xAA;"
3541 : "u8.length");
3542 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3543 12 : CHECK_EQ(0xFF, data[0]);
3544 12 : CHECK_EQ(0xAA, data[1]);
3545 6 : data[0] = 0xCC;
3546 6 : data[1] = 0x11;
3547 : result = CompileRun("u8[0] + u8[1]");
3548 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3549 6 : }
3550 :
3551 :
3552 23724 : THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3553 6 : LocalContext env;
3554 6 : v8::Isolate* isolate = env->GetIsolate();
3555 12 : v8::HandleScope handle_scope(isolate);
3556 :
3557 :
3558 : v8::Local<v8::Value> result = CompileRun(
3559 : "var ab1 = new ArrayBuffer(2);"
3560 : "var u8_a = new Uint8Array(ab1);"
3561 : "u8_a[0] = 0xAA;"
3562 : "u8_a[1] = 0xFF; u8_a.buffer");
3563 : Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3564 6 : CheckInternalFieldsAreZero(ab1);
3565 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3566 6 : CHECK(!ab1->IsExternal());
3567 12 : ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3568 6 : CHECK(ab1->IsExternal());
3569 :
3570 : result = CompileRun("ab1.byteLength");
3571 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3572 : result = CompileRun("u8_a[0]");
3573 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3574 : result = CompileRun("u8_a[1]");
3575 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3576 : result = CompileRun(
3577 : "var u8_b = new Uint8Array(ab1);"
3578 : "u8_b[0] = 0xBB;"
3579 : "u8_a[0]");
3580 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3581 : result = CompileRun("u8_b[1]");
3582 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3583 :
3584 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3585 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3586 12 : CHECK_EQ(0xBB, ab1_data[0]);
3587 12 : CHECK_EQ(0xFF, ab1_data[1]);
3588 6 : ab1_data[0] = 0xCC;
3589 6 : ab1_data[1] = 0x11;
3590 : result = CompileRun("u8_a[0] + u8_a[1]");
3591 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3592 6 : }
3593 :
3594 :
3595 23724 : THREADED_TEST(ArrayBuffer_External) {
3596 6 : LocalContext env;
3597 6 : v8::Isolate* isolate = env->GetIsolate();
3598 12 : v8::HandleScope handle_scope(isolate);
3599 :
3600 : i::ScopedVector<uint8_t> my_data(100);
3601 : memset(my_data.start(), 0, 100);
3602 : Local<v8::ArrayBuffer> ab3 =
3603 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3604 6 : CheckInternalFieldsAreZero(ab3);
3605 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3606 6 : CHECK(ab3->IsExternal());
3607 :
3608 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3609 :
3610 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3611 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3612 :
3613 : result = CompileRun(
3614 : "var u8_b = new Uint8Array(ab3);"
3615 : "u8_b[0] = 0xBB;"
3616 : "u8_b[1] = 0xCC;"
3617 : "u8_b.length");
3618 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3619 12 : CHECK_EQ(0xBB, my_data[0]);
3620 12 : CHECK_EQ(0xCC, my_data[1]);
3621 6 : my_data[0] = 0xCC;
3622 6 : my_data[1] = 0x11;
3623 : result = CompileRun("u8_b[0] + u8_b[1]");
3624 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3625 6 : }
3626 :
3627 :
3628 23724 : THREADED_TEST(ArrayBuffer_DisableNeuter) {
3629 6 : LocalContext env;
3630 6 : v8::Isolate* isolate = env->GetIsolate();
3631 12 : v8::HandleScope handle_scope(isolate);
3632 :
3633 : i::ScopedVector<uint8_t> my_data(100);
3634 : memset(my_data.start(), 0, 100);
3635 : Local<v8::ArrayBuffer> ab =
3636 6 : v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3637 6 : CHECK(ab->IsNeuterable());
3638 :
3639 : i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3640 : buf->set_is_neuterable(false);
3641 :
3642 12 : CHECK(!ab->IsNeuterable());
3643 6 : }
3644 :
3645 :
3646 12 : static void CheckDataViewIsNeutered(v8::Local<v8::DataView> dv) {
3647 12 : CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3648 12 : CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3649 12 : }
3650 :
3651 :
3652 108 : static void CheckIsNeutered(v8::Local<v8::TypedArray> ta) {
3653 108 : CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3654 108 : CHECK_EQ(0, static_cast<int>(ta->Length()));
3655 108 : CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3656 108 : }
3657 :
3658 :
3659 54 : static void CheckIsTypedArrayVarNeutered(const char* name) {
3660 : i::ScopedVector<char> source(1024);
3661 : i::SNPrintF(source,
3662 : "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3663 54 : name, name, name);
3664 54 : CHECK(CompileRun(source.start())->IsTrue());
3665 : v8::Local<v8::TypedArray> ta =
3666 54 : v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3667 54 : CheckIsNeutered(ta);
3668 54 : }
3669 :
3670 :
3671 : template <typename TypedArray, int kElementSize>
3672 54 : static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3673 : int byteOffset, int length) {
3674 54 : v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3675 54 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3676 54 : CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3677 54 : CHECK_EQ(length, static_cast<int>(ta->Length()));
3678 54 : CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3679 54 : return ta;
3680 : }
3681 :
3682 :
3683 23724 : THREADED_TEST(ArrayBuffer_NeuteringApi) {
3684 6 : LocalContext env;
3685 6 : v8::Isolate* isolate = env->GetIsolate();
3686 12 : v8::HandleScope handle_scope(isolate);
3687 :
3688 6 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3689 :
3690 : v8::Local<v8::Uint8Array> u8a =
3691 6 : CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3692 : v8::Local<v8::Uint8ClampedArray> u8c =
3693 6 : CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3694 : v8::Local<v8::Int8Array> i8a =
3695 6 : CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3696 :
3697 : v8::Local<v8::Uint16Array> u16a =
3698 6 : CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3699 : v8::Local<v8::Int16Array> i16a =
3700 6 : CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3701 :
3702 : v8::Local<v8::Uint32Array> u32a =
3703 6 : CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3704 : v8::Local<v8::Int32Array> i32a =
3705 6 : CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3706 :
3707 : v8::Local<v8::Float32Array> f32a =
3708 6 : CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3709 : v8::Local<v8::Float64Array> f64a =
3710 6 : CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3711 :
3712 6 : v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3713 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3714 6 : CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3715 6 : CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3716 :
3717 12 : ScopedArrayBufferContents contents(buffer->Externalize());
3718 6 : buffer->Neuter();
3719 6 : CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3720 6 : CheckIsNeutered(u8a);
3721 6 : CheckIsNeutered(u8c);
3722 6 : CheckIsNeutered(i8a);
3723 6 : CheckIsNeutered(u16a);
3724 6 : CheckIsNeutered(i16a);
3725 6 : CheckIsNeutered(u32a);
3726 6 : CheckIsNeutered(i32a);
3727 6 : CheckIsNeutered(f32a);
3728 6 : CheckIsNeutered(f64a);
3729 12 : CheckDataViewIsNeutered(dv);
3730 6 : }
3731 :
3732 :
3733 23724 : THREADED_TEST(ArrayBuffer_NeuteringScript) {
3734 6 : LocalContext env;
3735 6 : v8::Isolate* isolate = env->GetIsolate();
3736 12 : v8::HandleScope handle_scope(isolate);
3737 :
3738 : CompileRun(
3739 : "var ab = new ArrayBuffer(1024);"
3740 : "var u8a = new Uint8Array(ab, 1, 1023);"
3741 : "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3742 : "var i8a = new Int8Array(ab, 1, 1023);"
3743 : "var u16a = new Uint16Array(ab, 2, 511);"
3744 : "var i16a = new Int16Array(ab, 2, 511);"
3745 : "var u32a = new Uint32Array(ab, 4, 255);"
3746 : "var i32a = new Int32Array(ab, 4, 255);"
3747 : "var f32a = new Float32Array(ab, 4, 255);"
3748 : "var f64a = new Float64Array(ab, 8, 127);"
3749 : "var dv = new DataView(ab, 1, 1023);");
3750 :
3751 : v8::Local<v8::ArrayBuffer> ab =
3752 : Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3753 :
3754 6 : v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3755 :
3756 12 : ScopedArrayBufferContents contents(ab->Externalize());
3757 6 : ab->Neuter();
3758 6 : CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3759 6 : CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3760 :
3761 6 : CheckIsTypedArrayVarNeutered("u8a");
3762 6 : CheckIsTypedArrayVarNeutered("u8c");
3763 6 : CheckIsTypedArrayVarNeutered("i8a");
3764 6 : CheckIsTypedArrayVarNeutered("u16a");
3765 6 : CheckIsTypedArrayVarNeutered("i16a");
3766 6 : CheckIsTypedArrayVarNeutered("u32a");
3767 6 : CheckIsTypedArrayVarNeutered("i32a");
3768 6 : CheckIsTypedArrayVarNeutered("f32a");
3769 6 : CheckIsTypedArrayVarNeutered("f64a");
3770 :
3771 6 : CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3772 12 : CheckDataViewIsNeutered(dv);
3773 6 : }
3774 :
3775 23724 : THREADED_TEST(ArrayBuffer_AllocationInformation) {
3776 6 : LocalContext env;
3777 6 : v8::Isolate* isolate = env->GetIsolate();
3778 12 : v8::HandleScope handle_scope(isolate);
3779 :
3780 : const size_t ab_size = 1024;
3781 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
3782 12 : ScopedArrayBufferContents contents(ab->Externalize());
3783 :
3784 : // Array buffers should have normal allocation mode.
3785 6 : CHECK_EQ(contents.AllocationMode(),
3786 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
3787 : // The allocation must contain the buffer (normally they will be equal, but
3788 : // this is not required by the contract).
3789 6 : CHECK_NOT_NULL(contents.AllocationBase());
3790 : const uintptr_t alloc =
3791 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
3792 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
3793 6 : CHECK_LE(alloc, data);
3794 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
3795 6 : }
3796 :
3797 : class ScopedSharedArrayBufferContents {
3798 : public:
3799 : explicit ScopedSharedArrayBufferContents(
3800 : const v8::SharedArrayBuffer::Contents& contents)
3801 18 : : contents_(contents) {}
3802 18 : ~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
3803 : void* Data() const { return contents_.Data(); }
3804 : size_t ByteLength() const { return contents_.ByteLength(); }
3805 :
3806 : void* AllocationBase() const { return contents_.AllocationBase(); }
3807 : size_t AllocationLength() const { return contents_.AllocationLength(); }
3808 : v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3809 : return contents_.AllocationMode();
3810 : }
3811 :
3812 : private:
3813 : const v8::SharedArrayBuffer::Contents contents_;
3814 : };
3815 :
3816 :
3817 23724 : THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
3818 6 : i::FLAG_harmony_sharedarraybuffer = true;
3819 6 : LocalContext env;
3820 6 : v8::Isolate* isolate = env->GetIsolate();
3821 12 : v8::HandleScope handle_scope(isolate);
3822 :
3823 6 : Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
3824 6 : CheckInternalFieldsAreZero(ab);
3825 6 : CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3826 6 : CHECK(!ab->IsExternal());
3827 6 : CcTest::CollectAllGarbage();
3828 :
3829 12 : ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
3830 6 : CHECK(ab->IsExternal());
3831 :
3832 6 : CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3833 : uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3834 6 : CHECK_NOT_NULL(data);
3835 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3836 :
3837 : v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3838 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3839 :
3840 : result = CompileRun(
3841 : "var u8 = new Uint8Array(ab);"
3842 : "u8[0] = 0xFF;"
3843 : "u8[1] = 0xAA;"
3844 : "u8.length");
3845 12 : CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3846 12 : CHECK_EQ(0xFF, data[0]);
3847 12 : CHECK_EQ(0xAA, data[1]);
3848 6 : data[0] = 0xCC;
3849 6 : data[1] = 0x11;
3850 : result = CompileRun("u8[0] + u8[1]");
3851 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3852 6 : }
3853 :
3854 :
3855 23724 : THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
3856 6 : i::FLAG_harmony_sharedarraybuffer = true;
3857 6 : LocalContext env;
3858 6 : v8::Isolate* isolate = env->GetIsolate();
3859 12 : v8::HandleScope handle_scope(isolate);
3860 :
3861 :
3862 : v8::Local<v8::Value> result = CompileRun(
3863 : "var ab1 = new SharedArrayBuffer(2);"
3864 : "var u8_a = new Uint8Array(ab1);"
3865 : "u8_a[0] = 0xAA;"
3866 : "u8_a[1] = 0xFF; u8_a.buffer");
3867 : Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
3868 6 : CheckInternalFieldsAreZero(ab1);
3869 6 : CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3870 6 : CHECK(!ab1->IsExternal());
3871 12 : ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
3872 6 : CHECK(ab1->IsExternal());
3873 :
3874 : result = CompileRun("ab1.byteLength");
3875 12 : CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3876 : result = CompileRun("u8_a[0]");
3877 12 : CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3878 : result = CompileRun("u8_a[1]");
3879 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3880 : result = CompileRun(
3881 : "var u8_b = new Uint8Array(ab1);"
3882 : "u8_b[0] = 0xBB;"
3883 : "u8_a[0]");
3884 12 : CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3885 : result = CompileRun("u8_b[1]");
3886 12 : CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3887 :
3888 6 : CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3889 : uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3890 12 : CHECK_EQ(0xBB, ab1_data[0]);
3891 12 : CHECK_EQ(0xFF, ab1_data[1]);
3892 6 : ab1_data[0] = 0xCC;
3893 6 : ab1_data[1] = 0x11;
3894 : result = CompileRun("u8_a[0] + u8_a[1]");
3895 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3896 6 : }
3897 :
3898 :
3899 23724 : THREADED_TEST(SharedArrayBuffer_External) {
3900 6 : i::FLAG_harmony_sharedarraybuffer = true;
3901 6 : LocalContext env;
3902 6 : v8::Isolate* isolate = env->GetIsolate();
3903 12 : v8::HandleScope handle_scope(isolate);
3904 :
3905 : i::ScopedVector<uint8_t> my_data(100);
3906 : memset(my_data.start(), 0, 100);
3907 : Local<v8::SharedArrayBuffer> ab3 =
3908 6 : v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
3909 6 : CheckInternalFieldsAreZero(ab3);
3910 6 : CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3911 6 : CHECK(ab3->IsExternal());
3912 :
3913 30 : CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3914 :
3915 : v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3916 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3917 :
3918 : result = CompileRun(
3919 : "var u8_b = new Uint8Array(ab3);"
3920 : "u8_b[0] = 0xBB;"
3921 : "u8_b[1] = 0xCC;"
3922 : "u8_b.length");
3923 12 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3924 12 : CHECK_EQ(0xBB, my_data[0]);
3925 12 : CHECK_EQ(0xCC, my_data[1]);
3926 6 : my_data[0] = 0xCC;
3927 6 : my_data[1] = 0x11;
3928 : result = CompileRun("u8_b[0] + u8_b[1]");
3929 18 : CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3930 6 : }
3931 :
3932 :
3933 23724 : THREADED_TEST(HiddenProperties) {
3934 6 : LocalContext env;
3935 6 : v8::Isolate* isolate = env->GetIsolate();
3936 12 : v8::HandleScope scope(isolate);
3937 :
3938 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3939 : v8::Local<v8::Private> key =
3940 6 : v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
3941 6 : v8::Local<v8::String> empty = v8_str("");
3942 6 : v8::Local<v8::String> prop_name = v8_str("prop_name");
3943 :
3944 6 : CcTest::CollectAllGarbage();
3945 :
3946 : // Make sure delete of a non-existent hidden value works
3947 12 : obj->DeletePrivate(env.local(), key).FromJust();
3948 :
3949 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
3950 : .FromJust());
3951 18 : CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
3952 : .ToLocalChecked()
3953 : ->Int32Value(env.local())
3954 : .FromJust());
3955 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
3956 : .FromJust());
3957 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3958 : .ToLocalChecked()
3959 : ->Int32Value(env.local())
3960 : .FromJust());
3961 :
3962 6 : CcTest::CollectAllGarbage();
3963 :
3964 : // Make sure we do not find the hidden property.
3965 12 : CHECK(!obj->Has(env.local(), empty).FromJust());
3966 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3967 : .ToLocalChecked()
3968 : ->Int32Value(env.local())
3969 : .FromJust());
3970 12 : CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
3971 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3972 : .ToLocalChecked()
3973 : ->Int32Value(env.local())
3974 : .FromJust());
3975 18 : CHECK(
3976 : obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
3977 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3978 : .ToLocalChecked()
3979 : ->Int32Value(env.local())
3980 : .FromJust());
3981 24 : CHECK_EQ(2003, obj->Get(env.local(), empty)
3982 : .ToLocalChecked()
3983 : ->Int32Value(env.local())
3984 : .FromJust());
3985 :
3986 6 : CcTest::CollectAllGarbage();
3987 :
3988 : // Add another property and delete it afterwards to force the object in
3989 : // slow case.
3990 18 : CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
3991 : .FromJust());
3992 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3993 : .ToLocalChecked()
3994 : ->Int32Value(env.local())
3995 : .FromJust());
3996 24 : CHECK_EQ(2008, obj->Get(env.local(), prop_name)
3997 : .ToLocalChecked()
3998 : ->Int32Value(env.local())
3999 : .FromJust());
4000 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4001 : .ToLocalChecked()
4002 : ->Int32Value(env.local())
4003 : .FromJust());
4004 12 : CHECK(obj->Delete(env.local(), prop_name).FromJust());
4005 18 : CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4006 : .ToLocalChecked()
4007 : ->Int32Value(env.local())
4008 : .FromJust());
4009 :
4010 6 : CcTest::CollectAllGarbage();
4011 :
4012 18 : CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4013 : .FromJust());
4014 12 : CHECK(obj->DeletePrivate(env.local(), key).FromJust());
4015 18 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4016 6 : }
4017 :
4018 :
4019 23724 : THREADED_TEST(Regress97784) {
4020 : // Regression test for crbug.com/97784
4021 : // Messing with the Object.prototype should not have effect on
4022 : // hidden properties.
4023 6 : LocalContext env;
4024 12 : v8::HandleScope scope(env->GetIsolate());
4025 :
4026 6 : v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4027 : v8::Local<v8::Private> key =
4028 12 : v8::Private::New(env->GetIsolate(), v8_str("hidden"));
4029 :
4030 : CompileRun(
4031 : "set_called = false;"
4032 : "Object.defineProperty("
4033 : " Object.prototype,"
4034 : " 'hidden',"
4035 : " {get: function() { return 45; },"
4036 : " set: function() { set_called = true; }})");
4037 :
4038 12 : CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4039 : // Make sure that the getter and setter from Object.prototype is not invoked.
4040 : // If it did we would have full access to the hidden properties in
4041 : // the accessor.
4042 18 : CHECK(
4043 : obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
4044 : .FromJust());
4045 : ExpectFalse("set_called");
4046 18 : CHECK_EQ(42, obj->GetPrivate(env.local(), key)
4047 : .ToLocalChecked()
4048 : ->Int32Value(env.local())
4049 6 : .FromJust());
4050 6 : }
4051 :
4052 :
4053 23724 : THREADED_TEST(External) {
4054 6 : v8::HandleScope scope(CcTest::isolate());
4055 6 : int x = 3;
4056 6 : Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
4057 12 : LocalContext env;
4058 30 : CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
4059 : Local<Value> reext_obj = CompileRun("this.ext");
4060 : v8::Local<v8::External> reext = reext_obj.As<v8::External>();
4061 6 : int* ptr = static_cast<int*>(reext->Value());
4062 6 : CHECK_EQ(3, x);
4063 6 : *ptr = 10;
4064 6 : CHECK_EQ(x, 10);
4065 :
4066 : {
4067 : i::Handle<i::Object> obj = v8::Utils::OpenHandle(*ext);
4068 12 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4069 6 : CHECK(ext->IsExternal());
4070 6 : CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty());
4071 12 : CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4072 6 : CHECK(ext->IsExternal());
4073 : }
4074 :
4075 : // Make sure unaligned pointers are wrapped properly.
4076 6 : char* data = i::StrDup("0123456789");
4077 6 : Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
4078 6 : Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
4079 6 : Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
4080 6 : Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
4081 :
4082 6 : char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
4083 6 : CHECK_EQ('0', *char_ptr);
4084 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
4085 6 : CHECK_EQ('1', *char_ptr);
4086 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
4087 6 : CHECK_EQ('2', *char_ptr);
4088 6 : char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
4089 6 : CHECK_EQ('3', *char_ptr);
4090 6 : i::DeleteArray(data);
4091 6 : }
4092 :
4093 :
4094 23724 : THREADED_TEST(GlobalHandle) {
4095 6 : v8::Isolate* isolate = CcTest::isolate();
4096 : v8::Persistent<String> global;
4097 : {
4098 6 : v8::HandleScope scope(isolate);
4099 12 : global.Reset(isolate, v8_str("str"));
4100 : }
4101 : {
4102 6 : v8::HandleScope scope(isolate);
4103 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4104 : }
4105 : global.Reset();
4106 : {
4107 6 : v8::HandleScope scope(isolate);
4108 12 : global.Reset(isolate, v8_str("str"));
4109 : }
4110 : {
4111 6 : v8::HandleScope scope(isolate);
4112 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4113 : }
4114 : global.Reset();
4115 6 : }
4116 :
4117 :
4118 23724 : THREADED_TEST(ResettingGlobalHandle) {
4119 12 : v8::Isolate* isolate = CcTest::isolate();
4120 : v8::Persistent<String> global;
4121 : {
4122 6 : v8::HandleScope scope(isolate);
4123 12 : global.Reset(isolate, v8_str("str"));
4124 : }
4125 18 : v8::internal::GlobalHandles* global_handles =
4126 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4127 : int initial_handle_count = global_handles->global_handles_count();
4128 : {
4129 6 : v8::HandleScope scope(isolate);
4130 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4131 : }
4132 : {
4133 6 : v8::HandleScope scope(isolate);
4134 12 : global.Reset(isolate, v8_str("longer"));
4135 : }
4136 6 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
4137 : {
4138 6 : v8::HandleScope scope(isolate);
4139 6 : CHECK_EQ(6, v8::Local<String>::New(isolate, global)->Length());
4140 : }
4141 : global.Reset();
4142 12 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
4143 6 : }
4144 :
4145 :
4146 23724 : THREADED_TEST(ResettingGlobalHandleToEmpty) {
4147 12 : v8::Isolate* isolate = CcTest::isolate();
4148 : v8::Persistent<String> global;
4149 : {
4150 6 : v8::HandleScope scope(isolate);
4151 12 : global.Reset(isolate, v8_str("str"));
4152 : }
4153 12 : v8::internal::GlobalHandles* global_handles =
4154 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4155 : int initial_handle_count = global_handles->global_handles_count();
4156 : {
4157 6 : v8::HandleScope scope(isolate);
4158 6 : CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4159 : }
4160 : {
4161 6 : v8::HandleScope scope(isolate);
4162 : Local<String> empty;
4163 6 : global.Reset(isolate, empty);
4164 : }
4165 6 : CHECK(global.IsEmpty());
4166 12 : CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
4167 6 : }
4168 :
4169 :
4170 : template <class T>
4171 : static v8::Global<T> PassUnique(v8::Global<T> unique) {
4172 : return unique.Pass();
4173 : }
4174 :
4175 :
4176 : template <class T>
4177 : static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
4178 : const v8::Persistent<T>& global) {
4179 : v8::Global<String> unique(isolate, global);
4180 : return unique.Pass();
4181 : }
4182 :
4183 :
4184 23724 : THREADED_TEST(Global) {
4185 12 : v8::Isolate* isolate = CcTest::isolate();
4186 : v8::Persistent<String> global;
4187 : {
4188 6 : v8::HandleScope scope(isolate);
4189 12 : global.Reset(isolate, v8_str("str"));
4190 : }
4191 42 : v8::internal::GlobalHandles* global_handles =
4192 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4193 : int initial_handle_count = global_handles->global_handles_count();
4194 : {
4195 : v8::Global<String> unique(isolate, global);
4196 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4197 : // Test assignment via Pass
4198 : {
4199 : v8::Global<String> copy = unique.Pass();
4200 6 : CHECK(unique.IsEmpty());
4201 6 : CHECK(copy == global);
4202 6 : CHECK_EQ(initial_handle_count + 1,
4203 : global_handles->global_handles_count());
4204 : unique = copy.Pass();
4205 : }
4206 : // Test ctor via Pass
4207 : {
4208 : v8::Global<String> copy(unique.Pass());
4209 6 : CHECK(unique.IsEmpty());
4210 6 : CHECK(copy == global);
4211 6 : CHECK_EQ(initial_handle_count + 1,
4212 : global_handles->global_handles_count());
4213 : unique = copy.Pass();
4214 : }
4215 : // Test pass through function call
4216 : {
4217 : v8::Global<String> copy = PassUnique(unique.Pass());
4218 6 : CHECK(unique.IsEmpty());
4219 6 : CHECK(copy == global);
4220 6 : CHECK_EQ(initial_handle_count + 1,
4221 : global_handles->global_handles_count());
4222 : unique = copy.Pass();
4223 : }
4224 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4225 : }
4226 : // Test pass from function call
4227 : {
4228 : v8::Global<String> unique = ReturnUnique(isolate, global);
4229 6 : CHECK(unique == global);
4230 6 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4231 : }
4232 6 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4233 : global.Reset();
4234 6 : }
4235 :
4236 :
4237 : namespace {
4238 :
4239 : class TwoPassCallbackData;
4240 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4241 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4242 :
4243 :
4244 : class TwoPassCallbackData {
4245 : public:
4246 215 : TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4247 : : first_pass_called_(false),
4248 : second_pass_called_(false),
4249 : trigger_gc_(false),
4250 430 : instance_counter_(instance_counter) {
4251 215 : HandleScope scope(isolate);
4252 : i::ScopedVector<char> buffer(40);
4253 215 : i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4254 : auto string =
4255 : v8::String::NewFromUtf8(isolate, buffer.start(),
4256 215 : v8::NewStringType::kNormal).ToLocalChecked();
4257 : cell_.Reset(isolate, string);
4258 430 : (*instance_counter_)++;
4259 215 : }
4260 :
4261 215 : ~TwoPassCallbackData() {
4262 215 : CHECK(first_pass_called_);
4263 215 : CHECK(second_pass_called_);
4264 215 : CHECK(cell_.IsEmpty());
4265 215 : (*instance_counter_)--;
4266 215 : }
4267 :
4268 215 : void FirstPass() {
4269 215 : CHECK(!first_pass_called_);
4270 215 : CHECK(!second_pass_called_);
4271 215 : CHECK(!cell_.IsEmpty());
4272 : cell_.Reset();
4273 215 : first_pass_called_ = true;
4274 215 : }
4275 :
4276 215 : void SecondPass() {
4277 215 : CHECK(first_pass_called_);
4278 215 : CHECK(!second_pass_called_);
4279 215 : CHECK(cell_.IsEmpty());
4280 215 : second_pass_called_ = true;
4281 215 : delete this;
4282 215 : }
4283 :
4284 : void SetWeak() {
4285 : cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4286 : }
4287 :
4288 15 : void MarkTriggerGc() { trigger_gc_ = true; }
4289 : bool trigger_gc() { return trigger_gc_; }
4290 :
4291 : int* instance_counter() { return instance_counter_; }
4292 :
4293 : private:
4294 : bool first_pass_called_;
4295 : bool second_pass_called_;
4296 : bool trigger_gc_;
4297 : v8::Global<v8::String> cell_;
4298 : int* instance_counter_;
4299 : };
4300 :
4301 :
4302 445 : void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4303 215 : ApiTestFuzzer::Fuzz();
4304 215 : bool trigger_gc = data.GetParameter()->trigger_gc();
4305 215 : int* instance_counter = data.GetParameter()->instance_counter();
4306 215 : data.GetParameter()->SecondPass();
4307 430 : if (!trigger_gc) return;
4308 15 : auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4309 : data_2->SetWeak();
4310 15 : CcTest::CollectAllGarbage();
4311 : }
4312 :
4313 :
4314 430 : void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4315 215 : data.GetParameter()->FirstPass();
4316 : data.SetSecondPassCallback(SecondPassCallback);
4317 215 : }
4318 :
4319 : } // namespace
4320 :
4321 :
4322 23723 : TEST(TwoPassPhantomCallbacks) {
4323 5 : auto isolate = CcTest::isolate();
4324 : const size_t kLength = 20;
4325 5 : int instance_counter = 0;
4326 105 : for (size_t i = 0; i < kLength; ++i) {
4327 100 : auto data = new TwoPassCallbackData(isolate, &instance_counter);
4328 : data->SetWeak();
4329 : }
4330 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4331 5 : CcTest::CollectAllGarbage();
4332 5 : EmptyMessageQueues(isolate);
4333 5 : CHECK_EQ(0, instance_counter);
4334 5 : }
4335 :
4336 :
4337 23723 : TEST(TwoPassPhantomCallbacksNestedGc) {
4338 5 : auto isolate = CcTest::isolate();
4339 : const size_t kLength = 20;
4340 : TwoPassCallbackData* array[kLength];
4341 5 : int instance_counter = 0;
4342 105 : for (size_t i = 0; i < kLength; ++i) {
4343 100 : array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4344 : array[i]->SetWeak();
4345 : }
4346 5 : array[5]->MarkTriggerGc();
4347 5 : array[10]->MarkTriggerGc();
4348 5 : array[15]->MarkTriggerGc();
4349 5 : CHECK_EQ(static_cast<int>(kLength), instance_counter);
4350 5 : CcTest::CollectAllGarbage();
4351 5 : EmptyMessageQueues(isolate);
4352 5 : CHECK_EQ(0, instance_counter);
4353 5 : }
4354 :
4355 :
4356 : namespace {
4357 :
4358 30 : void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4359 :
4360 :
4361 20 : Local<v8::Object> NewObjectForIntKey(
4362 : v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4363 : int key) {
4364 : auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4365 20 : auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4366 20 : obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4367 20 : return obj;
4368 : }
4369 :
4370 :
4371 : template <typename K, typename V>
4372 : class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4373 : public:
4374 : typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4375 : static const v8::PersistentContainerCallbackType kCallbackType =
4376 : v8::kWeakWithInternalFields;
4377 : struct WeakCallbackDataType {
4378 : MapType* map;
4379 : K key;
4380 : };
4381 : static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4382 : Local<V> value) {
4383 25 : WeakCallbackDataType* data = new WeakCallbackDataType;
4384 25 : data->map = map;
4385 25 : data->key = key;
4386 : return data;
4387 : }
4388 : static MapType* MapFromWeakCallbackInfo(
4389 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4390 5 : return data.GetParameter()->map;
4391 : }
4392 : static K KeyFromWeakCallbackInfo(
4393 5 : const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4394 10 : return data.GetParameter()->key;
4395 : }
4396 25 : static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
4397 5 : static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4398 5 : CHECK_EQ(IntKeyToVoidPointer(key),
4399 : v8::Object::GetAlignedPointerFromInternalField(value, 0));
4400 5 : }
4401 : static void OnWeakCallback(
4402 : const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
4403 5 : static void DisposeWeak(
4404 : const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4405 : K key = KeyFromWeakCallbackInfo(info);
4406 5 : CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4407 : DisposeCallbackData(info.GetParameter());
4408 5 : }
4409 : };
4410 :
4411 :
4412 : template <typename Map>
4413 10 : void TestGlobalValueMap() {
4414 10 : LocalContext env;
4415 20 : v8::Isolate* isolate = env->GetIsolate();
4416 : v8::Global<ObjectTemplate> templ;
4417 : {
4418 10 : HandleScope scope(isolate);
4419 10 : auto t = ObjectTemplate::New(isolate);
4420 10 : t->SetInternalFieldCount(1);
4421 10 : templ.Reset(isolate, t);
4422 : }
4423 : Map map(isolate);
4424 40 : v8::internal::GlobalHandles* global_handles =
4425 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4426 : int initial_handle_count = global_handles->global_handles_count();
4427 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4428 : {
4429 10 : HandleScope scope(isolate);
4430 10 : Local<v8::Object> obj = map.Get(7);
4431 10 : CHECK(obj.IsEmpty());
4432 10 : Local<v8::Object> expected = v8::Object::New(isolate);
4433 20 : map.Set(7, expected);
4434 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4435 10 : obj = map.Get(7);
4436 20 : CHECK(expected->Equals(env.local(), obj).FromJust());
4437 : {
4438 10 : typename Map::PersistentValueReference ref = map.GetReference(7);
4439 20 : CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4440 : }
4441 5 : v8::Global<v8::Object> removed = map.Remove(7);
4442 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4443 10 : CHECK(expected == removed);
4444 10 : removed = map.Remove(7);
4445 10 : CHECK(removed.IsEmpty());
4446 20 : map.Set(8, expected);
4447 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4448 20 : map.Set(8, expected);
4449 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4450 : {
4451 : typename Map::PersistentValueReference ref;
4452 10 : Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4453 15 : removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4454 10 : CHECK_EQ(1, static_cast<int>(map.Size()));
4455 10 : CHECK(expected == removed);
4456 20 : CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4457 10 : }
4458 : }
4459 10 : CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4460 : if (map.IsWeak()) {
4461 5 : CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4462 : } else {
4463 5 : map.Clear();
4464 : }
4465 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4466 10 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4467 : {
4468 10 : HandleScope scope(isolate);
4469 10 : Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4470 20 : map.Set(9, value);
4471 10 : map.Clear();
4472 : }
4473 10 : CHECK_EQ(0, static_cast<int>(map.Size()));
4474 20 : CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4475 10 : }
4476 :
4477 : } // namespace
4478 :
4479 :
4480 23723 : TEST(GlobalValueMap) {
4481 : // Default case, w/o weak callbacks:
4482 5 : TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4483 :
4484 : // Custom traits with weak callbacks:
4485 : typedef v8::GlobalValueMap<int, v8::Object,
4486 : PhantomStdMapTraits<int, v8::Object>> WeakMap;
4487 5 : TestGlobalValueMap<WeakMap>();
4488 5 : }
4489 :
4490 :
4491 23723 : TEST(PersistentValueVector) {
4492 5 : LocalContext env;
4493 5 : v8::Isolate* isolate = env->GetIsolate();
4494 15 : v8::internal::GlobalHandles* global_handles =
4495 : reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4496 : int handle_count = global_handles->global_handles_count();
4497 10 : HandleScope scope(isolate);
4498 :
4499 5 : v8::PersistentValueVector<v8::Object> vector(isolate);
4500 :
4501 5 : Local<v8::Object> obj1 = v8::Object::New(isolate);
4502 5 : Local<v8::Object> obj2 = v8::Object::New(isolate);
4503 5 : v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4504 :
4505 5 : CHECK(vector.IsEmpty());
4506 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4507 :
4508 : vector.ReserveCapacity(3);
4509 5 : CHECK(vector.IsEmpty());
4510 :
4511 5 : vector.Append(obj1);
4512 5 : vector.Append(obj2);
4513 5 : vector.Append(obj1);
4514 : vector.Append(obj3.Pass());
4515 5 : vector.Append(obj1);
4516 :
4517 5 : CHECK(!vector.IsEmpty());
4518 5 : CHECK_EQ(5, static_cast<int>(vector.Size()));
4519 5 : CHECK(obj3.IsEmpty());
4520 15 : CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4521 15 : CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4522 15 : CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4523 20 : CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4524 :
4525 5 : CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4526 :
4527 5 : vector.Clear();
4528 5 : CHECK(vector.IsEmpty());
4529 5 : CHECK_EQ(0, static_cast<int>(vector.Size()));
4530 10 : CHECK_EQ(handle_count, global_handles->global_handles_count());
4531 5 : }
4532 :
4533 :
4534 23724 : THREADED_TEST(GlobalHandleUpcast) {
4535 6 : v8::Isolate* isolate = CcTest::isolate();
4536 6 : v8::HandleScope scope(isolate);
4537 6 : v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4538 : v8::Persistent<String> global_string(isolate, local);
4539 : v8::Persistent<Value>& global_value =
4540 : v8::Persistent<Value>::Cast(global_string);
4541 6 : CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4542 6 : CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4543 6 : global_string.Reset();
4544 6 : }
4545 :
4546 :
4547 23724 : THREADED_TEST(HandleEquality) {
4548 6 : v8::Isolate* isolate = CcTest::isolate();
4549 : v8::Persistent<String> global1;
4550 : v8::Persistent<String> global2;
4551 : {
4552 6 : v8::HandleScope scope(isolate);
4553 12 : global1.Reset(isolate, v8_str("str"));
4554 12 : global2.Reset(isolate, v8_str("str2"));
4555 : }
4556 6 : CHECK(global1 == global1);
4557 6 : CHECK(!(global1 != global1));
4558 : {
4559 6 : v8::HandleScope scope(isolate);
4560 : Local<String> local1 = Local<String>::New(isolate, global1);
4561 : Local<String> local2 = Local<String>::New(isolate, global2);
4562 :
4563 6 : CHECK(global1 == local1);
4564 6 : CHECK(!(global1 != local1));
4565 6 : CHECK(local1 == global1);
4566 6 : CHECK(!(local1 != global1));
4567 :
4568 6 : CHECK(!(global1 == local2));
4569 6 : CHECK(global1 != local2);
4570 6 : CHECK(!(local2 == global1));
4571 6 : CHECK(local2 != global1);
4572 :
4573 6 : CHECK(!(local1 == local2));
4574 6 : CHECK(local1 != local2);
4575 :
4576 : Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4577 6 : CHECK(local1 == anotherLocal1);
4578 6 : CHECK(!(local1 != anotherLocal1));
4579 : }
4580 : global1.Reset();
4581 : global2.Reset();
4582 6 : }
4583 :
4584 :
4585 23724 : THREADED_TEST(LocalHandle) {
4586 6 : v8::HandleScope scope(CcTest::isolate());
4587 : v8::Local<String> local =
4588 6 : v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4589 6 : CHECK_EQ(3, local->Length());
4590 6 : }
4591 :
4592 :
4593 : class WeakCallCounter {
4594 : public:
4595 10 : explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
4596 : int id() { return id_; }
4597 25 : void increment() { number_of_weak_calls_++; }
4598 : int NumberOfWeakCalls() { return number_of_weak_calls_; }
4599 :
4600 : private:
4601 : int id_;
4602 : int number_of_weak_calls_;
4603 : };
4604 :
4605 :
4606 : template <typename T>
4607 : struct WeakCallCounterAndPersistent {
4608 : explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4609 25 : : counter(counter) {}
4610 : WeakCallCounter* counter;
4611 : v8::Persistent<T> handle;
4612 : };
4613 :
4614 :
4615 : template <typename T>
4616 25 : static void WeakPointerCallback(
4617 50 : const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4618 25 : CHECK_EQ(1234, data.GetParameter()->counter->id());
4619 : data.GetParameter()->counter->increment();
4620 : data.GetParameter()->handle.Reset();
4621 25 : }
4622 :
4623 23724 : THREADED_TEST(ScriptException) {
4624 6 : LocalContext env;
4625 12 : v8::HandleScope scope(env->GetIsolate());
4626 : Local<Script> script = v8_compile("throw 'panama!';");
4627 12 : v8::TryCatch try_catch(env->GetIsolate());
4628 6 : v8::MaybeLocal<Value> result = script->Run(env.local());
4629 6 : CHECK(result.IsEmpty());
4630 6 : CHECK(try_catch.HasCaught());
4631 18 : String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
4632 12 : CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4633 6 : }
4634 :
4635 :
4636 23723 : TEST(TryCatchCustomException) {
4637 5 : LocalContext env;
4638 5 : v8::Isolate* isolate = env->GetIsolate();
4639 10 : v8::HandleScope scope(isolate);
4640 10 : v8::TryCatch try_catch(isolate);
4641 : CompileRun(
4642 : "function CustomError() { this.a = 'b'; }"
4643 : "(function f() { throw new CustomError(); })();");
4644 5 : CHECK(try_catch.HasCaught());
4645 35 : CHECK(try_catch.Exception()
4646 : ->ToObject(env.local())
4647 : .ToLocalChecked()
4648 : ->Get(env.local(), v8_str("a"))
4649 : .ToLocalChecked()
4650 : ->Equals(env.local(), v8_str("b"))
4651 5 : .FromJust());
4652 5 : }
4653 :
4654 :
4655 : bool message_received;
4656 :
4657 :
4658 6 : static void check_message_0(v8::Local<v8::Message> message,
4659 : v8::Local<Value> data) {
4660 18 : CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4661 : .FromJust());
4662 12 : CHECK_EQ(6.75, message->GetScriptOrigin()
4663 : .ResourceName()
4664 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4665 : .FromJust());
4666 6 : CHECK(!message->IsSharedCrossOrigin());
4667 6 : message_received = true;
4668 6 : }
4669 :
4670 :
4671 23724 : THREADED_TEST(MessageHandler0) {
4672 6 : message_received = false;
4673 6 : v8::HandleScope scope(CcTest::isolate());
4674 6 : CHECK(!message_received);
4675 12 : LocalContext context;
4676 6 : CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4677 6 : v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4678 18 : CHECK(script->Run(context.local()).IsEmpty());
4679 6 : CHECK(message_received);
4680 : // clear out the message listener
4681 12 : CcTest::isolate()->RemoveMessageListeners(check_message_0);
4682 6 : }
4683 :
4684 :
4685 5 : static void check_message_1(v8::Local<v8::Message> message,
4686 : v8::Local<Value> data) {
4687 5 : CHECK(data->IsNumber());
4688 10 : CHECK_EQ(1337,
4689 : data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4690 5 : CHECK(!message->IsSharedCrossOrigin());
4691 5 : message_received = true;
4692 5 : }
4693 :
4694 :
4695 23723 : TEST(MessageHandler1) {
4696 5 : message_received = false;
4697 5 : v8::HandleScope scope(CcTest::isolate());
4698 5 : CHECK(!message_received);
4699 5 : CcTest::isolate()->AddMessageListener(check_message_1);
4700 10 : LocalContext context;
4701 : CompileRun("throw 1337;");
4702 5 : CHECK(message_received);
4703 : // clear out the message listener
4704 10 : CcTest::isolate()->RemoveMessageListeners(check_message_1);
4705 5 : }
4706 :
4707 :
4708 5 : static void check_message_2(v8::Local<v8::Message> message,
4709 : v8::Local<Value> data) {
4710 5 : LocalContext context;
4711 5 : CHECK(data->IsObject());
4712 : v8::Local<v8::Value> hidden_property =
4713 : v8::Object::Cast(*data)
4714 : ->GetPrivate(
4715 : context.local(),
4716 5 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4717 10 : .ToLocalChecked();
4718 15 : CHECK(v8_str("hidden value")
4719 : ->Equals(context.local(), hidden_property)
4720 : .FromJust());
4721 5 : CHECK(!message->IsSharedCrossOrigin());
4722 5 : message_received = true;
4723 5 : }
4724 :
4725 :
4726 23723 : TEST(MessageHandler2) {
4727 5 : message_received = false;
4728 5 : v8::HandleScope scope(CcTest::isolate());
4729 5 : CHECK(!message_received);
4730 5 : CcTest::isolate()->AddMessageListener(check_message_2);
4731 10 : LocalContext context;
4732 5 : v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4733 : v8::Object::Cast(*error)
4734 : ->SetPrivate(context.local(),
4735 : v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4736 15 : v8_str("hidden value"))
4737 10 : .FromJust();
4738 25 : CHECK(context->Global()
4739 : ->Set(context.local(), v8_str("error"), error)
4740 : .FromJust());
4741 : CompileRun("throw error;");
4742 5 : CHECK(message_received);
4743 : // clear out the message listener
4744 10 : CcTest::isolate()->RemoveMessageListeners(check_message_2);
4745 5 : }
4746 :
4747 :
4748 5 : static void check_message_3(v8::Local<v8::Message> message,
4749 : v8::Local<Value> data) {
4750 5 : CHECK(message->IsSharedCrossOrigin());
4751 10 : CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4752 10 : CHECK(message->GetScriptOrigin().Options().IsOpaque());
4753 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4754 : .ResourceName()
4755 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4756 : .FromJust());
4757 10 : CHECK_EQ(7.40, message->GetScriptOrigin()
4758 : .SourceMapUrl()
4759 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4760 : .FromJust());
4761 5 : message_received = true;
4762 5 : }
4763 :
4764 :
4765 23723 : TEST(MessageHandler3) {
4766 5 : message_received = false;
4767 5 : v8::Isolate* isolate = CcTest::isolate();
4768 5 : v8::HandleScope scope(isolate);
4769 5 : CHECK(!message_received);
4770 5 : isolate->AddMessageListener(check_message_3);
4771 10 : LocalContext context;
4772 : v8::ScriptOrigin origin =
4773 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4774 : v8::Integer::New(isolate, 2), v8::True(isolate),
4775 5 : Local<v8::Integer>(), v8_str("7.40"), v8::True(isolate));
4776 : v8::Local<v8::Script> script =
4777 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4778 5 : .ToLocalChecked();
4779 10 : CHECK(script->Run(context.local()).IsEmpty());
4780 5 : CHECK(message_received);
4781 : // clear out the message listener
4782 10 : isolate->RemoveMessageListeners(check_message_3);
4783 5 : }
4784 :
4785 :
4786 5 : static void check_message_4(v8::Local<v8::Message> message,
4787 : v8::Local<Value> data) {
4788 5 : CHECK(!message->IsSharedCrossOrigin());
4789 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4790 : .ResourceName()
4791 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4792 : .FromJust());
4793 5 : message_received = true;
4794 5 : }
4795 :
4796 :
4797 23723 : TEST(MessageHandler4) {
4798 5 : message_received = false;
4799 5 : v8::Isolate* isolate = CcTest::isolate();
4800 5 : v8::HandleScope scope(isolate);
4801 5 : CHECK(!message_received);
4802 5 : isolate->AddMessageListener(check_message_4);
4803 10 : LocalContext context;
4804 : v8::ScriptOrigin origin =
4805 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4806 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
4807 : v8::Local<v8::Script> script =
4808 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4809 5 : .ToLocalChecked();
4810 10 : CHECK(script->Run(context.local()).IsEmpty());
4811 5 : CHECK(message_received);
4812 : // clear out the message listener
4813 10 : isolate->RemoveMessageListeners(check_message_4);
4814 5 : }
4815 :
4816 :
4817 5 : static void check_message_5a(v8::Local<v8::Message> message,
4818 : v8::Local<Value> data) {
4819 5 : CHECK(message->IsSharedCrossOrigin());
4820 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4821 : .ResourceName()
4822 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4823 : .FromJust());
4824 5 : message_received = true;
4825 5 : }
4826 :
4827 :
4828 5 : static void check_message_5b(v8::Local<v8::Message> message,
4829 : v8::Local<Value> data) {
4830 5 : CHECK(!message->IsSharedCrossOrigin());
4831 10 : CHECK_EQ(6.75, message->GetScriptOrigin()
4832 : .ResourceName()
4833 : ->NumberValue(CcTest::isolate()->GetCurrentContext())
4834 : .FromJust());
4835 5 : message_received = true;
4836 5 : }
4837 :
4838 :
4839 23723 : TEST(MessageHandler5) {
4840 5 : message_received = false;
4841 5 : v8::Isolate* isolate = CcTest::isolate();
4842 5 : v8::HandleScope scope(isolate);
4843 5 : CHECK(!message_received);
4844 5 : isolate->AddMessageListener(check_message_5a);
4845 10 : LocalContext context;
4846 : v8::ScriptOrigin origin1 =
4847 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4848 5 : v8::Integer::New(isolate, 2), v8::True(isolate));
4849 : v8::Local<v8::Script> script =
4850 5 : Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
4851 5 : .ToLocalChecked();
4852 10 : CHECK(script->Run(context.local()).IsEmpty());
4853 5 : CHECK(message_received);
4854 : // clear out the message listener
4855 5 : isolate->RemoveMessageListeners(check_message_5a);
4856 :
4857 5 : message_received = false;
4858 5 : isolate->AddMessageListener(check_message_5b);
4859 : v8::ScriptOrigin origin2 =
4860 : v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4861 5 : v8::Integer::New(isolate, 2), v8::False(isolate));
4862 5 : script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
4863 5 : .ToLocalChecked();
4864 10 : CHECK(script->Run(context.local()).IsEmpty());
4865 5 : CHECK(message_received);
4866 : // clear out the message listener
4867 10 : isolate->RemoveMessageListeners(check_message_5b);
4868 5 : }
4869 :
4870 :
4871 23723 : TEST(NativeWeakMap) {
4872 5 : v8::Isolate* isolate = CcTest::isolate();
4873 5 : HandleScope scope(isolate);
4874 5 : Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
4875 5 : CHECK(!weak_map.IsEmpty());
4876 :
4877 10 : LocalContext env;
4878 5 : Local<Object> value = v8::Object::New(isolate);
4879 :
4880 5 : Local<Object> local1 = v8::Object::New(isolate);
4881 5 : CHECK(!weak_map->Has(local1));
4882 10 : CHECK(weak_map->Get(local1)->IsUndefined());
4883 5 : weak_map->Set(local1, value);
4884 5 : CHECK(weak_map->Has(local1));
4885 10 : CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
4886 :
4887 : WeakCallCounter counter(1234);
4888 : WeakCallCounterAndPersistent<Value> o1(&counter);
4889 : WeakCallCounterAndPersistent<Value> o2(&counter);
4890 : WeakCallCounterAndPersistent<Value> s1(&counter);
4891 : {
4892 5 : HandleScope scope(isolate);
4893 5 : Local<v8::Object> obj1 = v8::Object::New(isolate);
4894 5 : Local<v8::Object> obj2 = v8::Object::New(isolate);
4895 5 : Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4896 :
4897 5 : weak_map->Set(obj1, value);
4898 5 : weak_map->Set(obj2, value);
4899 5 : weak_map->Set(sym1, value);
4900 :
4901 : o1.handle.Reset(isolate, obj1);
4902 : o2.handle.Reset(isolate, obj2);
4903 : s1.handle.Reset(isolate, sym1);
4904 :
4905 5 : CHECK(weak_map->Has(local1));
4906 5 : CHECK(weak_map->Has(obj1));
4907 5 : CHECK(weak_map->Has(obj2));
4908 5 : CHECK(weak_map->Has(sym1));
4909 :
4910 10 : CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
4911 10 : CHECK(value->Equals(env.local(), weak_map->Get(obj1)).FromJust());
4912 10 : CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust());
4913 10 : CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust());
4914 : }
4915 5 : CcTest::CollectAllGarbage();
4916 : {
4917 5 : HandleScope scope(isolate);
4918 10 : CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
4919 10 : CHECK(value->Equals(env.local(),
4920 : weak_map->Get(Local<Value>::New(isolate, o1.handle)))
4921 : .FromJust());
4922 10 : CHECK(value->Equals(env.local(),
4923 : weak_map->Get(Local<Value>::New(isolate, o2.handle)))
4924 : .FromJust());
4925 10 : CHECK(value->Equals(env.local(),
4926 : weak_map->Get(Local<Value>::New(isolate, s1.handle)))
4927 5 : .FromJust());
4928 : }
4929 :
4930 : o1.handle.SetWeak(&o1, &WeakPointerCallback,
4931 : v8::WeakCallbackType::kParameter);
4932 : o2.handle.SetWeak(&o2, &WeakPointerCallback,
4933 : v8::WeakCallbackType::kParameter);
4934 : s1.handle.SetWeak(&s1, &WeakPointerCallback,
4935 : v8::WeakCallbackType::kParameter);
4936 :
4937 5 : CcTest::CollectAllGarbage();
4938 5 : CHECK_EQ(3, counter.NumberOfWeakCalls());
4939 :
4940 5 : CHECK(o1.handle.IsEmpty());
4941 5 : CHECK(o2.handle.IsEmpty());
4942 5 : CHECK(s1.handle.IsEmpty());
4943 :
4944 10 : CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
4945 5 : CHECK(weak_map->Delete(local1));
4946 5 : CHECK(!weak_map->Has(local1));
4947 15 : CHECK(weak_map->Get(local1)->IsUndefined());
4948 5 : }
4949 :
4950 :
4951 23724 : THREADED_TEST(GetSetProperty) {
4952 6 : LocalContext context;
4953 6 : v8::Isolate* isolate = context->GetIsolate();
4954 12 : v8::HandleScope scope(isolate);
4955 30 : CHECK(context->Global()
4956 : ->Set(context.local(), v8_str("foo"), v8_num(14))
4957 : .FromJust());
4958 30 : CHECK(context->Global()
4959 : ->Set(context.local(), v8_str("12"), v8_num(92))
4960 : .FromJust());
4961 30 : CHECK(context->Global()
4962 : ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
4963 : .FromJust());
4964 24 : CHECK(context->Global()
4965 : ->Set(context.local(), v8_num(13), v8_num(56))
4966 : .FromJust());
4967 : Local<Value> foo = CompileRun("this.foo");
4968 12 : CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
4969 : Local<Value> twelve = CompileRun("this[12]");
4970 12 : CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
4971 : Local<Value> sixteen = CompileRun("this[16]");
4972 12 : CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
4973 : Local<Value> thirteen = CompileRun("this[13]");
4974 12 : CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
4975 36 : CHECK_EQ(92, context->Global()
4976 : ->Get(context.local(), v8::Integer::New(isolate, 12))
4977 : .ToLocalChecked()
4978 : ->Int32Value(context.local())
4979 : .FromJust());
4980 36 : CHECK_EQ(92, context->Global()
4981 : ->Get(context.local(), v8_str("12"))
4982 : .ToLocalChecked()
4983 : ->Int32Value(context.local())
4984 : .FromJust());
4985 30 : CHECK_EQ(92, context->Global()
4986 : ->Get(context.local(), v8_num(12))
4987 : .ToLocalChecked()
4988 : ->Int32Value(context.local())
4989 : .FromJust());
4990 36 : CHECK_EQ(32, context->Global()
4991 : ->Get(context.local(), v8::Integer::New(isolate, 16))
4992 : .ToLocalChecked()
4993 : ->Int32Value(context.local())
4994 : .FromJust());
4995 36 : CHECK_EQ(32, context->Global()
4996 : ->Get(context.local(), v8_str("16"))
4997 : .ToLocalChecked()
4998 : ->Int32Value(context.local())
4999 : .FromJust());
5000 30 : CHECK_EQ(32, context->Global()
5001 : ->Get(context.local(), v8_num(16))
5002 : .ToLocalChecked()
5003 : ->Int32Value(context.local())
5004 : .FromJust());
5005 36 : CHECK_EQ(56, context->Global()
5006 : ->Get(context.local(), v8::Integer::New(isolate, 13))
5007 : .ToLocalChecked()
5008 : ->Int32Value(context.local())
5009 : .FromJust());
5010 36 : CHECK_EQ(56, context->Global()
5011 : ->Get(context.local(), v8_str("13"))
5012 : .ToLocalChecked()
5013 : ->Int32Value(context.local())
5014 : .FromJust());
5015 30 : CHECK_EQ(56, context->Global()
5016 : ->Get(context.local(), v8_num(13))
5017 : .ToLocalChecked()
5018 : ->Int32Value(context.local())
5019 6 : .FromJust());
5020 6 : }
5021 :
5022 :
5023 23724 : THREADED_TEST(PropertyAttributes) {
5024 6 : LocalContext context;
5025 12 : v8::HandleScope scope(context->GetIsolate());
5026 : // none
5027 6 : Local<String> prop = v8_str("none");
5028 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5029 24 : CHECK_EQ(v8::None, context->Global()
5030 : ->GetPropertyAttributes(context.local(), prop)
5031 : .FromJust());
5032 : // read-only
5033 6 : prop = v8_str("read_only");
5034 : context->Global()
5035 24 : ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5036 12 : .FromJust();
5037 36 : CHECK_EQ(7, context->Global()
5038 : ->Get(context.local(), prop)
5039 : .ToLocalChecked()
5040 : ->Int32Value(context.local())
5041 : .FromJust());
5042 24 : CHECK_EQ(v8::ReadOnly, context->Global()
5043 : ->GetPropertyAttributes(context.local(), prop)
5044 : .FromJust());
5045 : CompileRun("read_only = 9");
5046 36 : CHECK_EQ(7, context->Global()
5047 : ->Get(context.local(), prop)
5048 : .ToLocalChecked()
5049 : ->Int32Value(context.local())
5050 : .FromJust());
5051 30 : CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5052 36 : CHECK_EQ(7, context->Global()
5053 : ->Get(context.local(), prop)
5054 : .ToLocalChecked()
5055 : ->Int32Value(context.local())
5056 : .FromJust());
5057 : // dont-delete
5058 6 : prop = v8_str("dont_delete");
5059 : context->Global()
5060 24 : ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5061 12 : .FromJust();
5062 36 : CHECK_EQ(13, context->Global()
5063 : ->Get(context.local(), prop)
5064 : .ToLocalChecked()
5065 : ->Int32Value(context.local())
5066 : .FromJust());
5067 : CompileRun("delete dont_delete");
5068 36 : CHECK_EQ(13, context->Global()
5069 : ->Get(context.local(), prop)
5070 : .ToLocalChecked()
5071 : ->Int32Value(context.local())
5072 : .FromJust());
5073 24 : CHECK_EQ(v8::DontDelete, context->Global()
5074 : ->GetPropertyAttributes(context.local(), prop)
5075 : .FromJust());
5076 : // dont-enum
5077 6 : prop = v8_str("dont_enum");
5078 : context->Global()
5079 24 : ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5080 12 : .FromJust();
5081 24 : CHECK_EQ(v8::DontEnum, context->Global()
5082 : ->GetPropertyAttributes(context.local(), prop)
5083 : .FromJust());
5084 : // absent
5085 6 : prop = v8_str("absent");
5086 24 : CHECK_EQ(v8::None, context->Global()
5087 : ->GetPropertyAttributes(context.local(), prop)
5088 : .FromJust());
5089 6 : Local<Value> fake_prop = v8_num(1);
5090 24 : CHECK_EQ(v8::None, context->Global()
5091 : ->GetPropertyAttributes(context.local(), fake_prop)
5092 : .FromJust());
5093 : // exception
5094 12 : TryCatch try_catch(context->GetIsolate());
5095 : Local<Value> exception =
5096 6 : CompileRun("({ toString: function() { throw 'exception';} })");
5097 24 : CHECK(context->Global()
5098 : ->GetPropertyAttributes(context.local(), exception)
5099 : .IsNothing());
5100 6 : CHECK(try_catch.HasCaught());
5101 : String::Utf8Value exception_value(context->GetIsolate(),
5102 18 : try_catch.Exception());
5103 6 : CHECK_EQ(0, strcmp("exception", *exception_value));
5104 12 : try_catch.Reset();
5105 6 : }
5106 :
5107 :
5108 23724 : THREADED_TEST(Array) {
5109 6 : LocalContext context;
5110 12 : v8::HandleScope scope(context->GetIsolate());
5111 6 : Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5112 6 : CHECK_EQ(0u, array->Length());
5113 12 : CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5114 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5115 12 : CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5116 12 : CHECK(!array->Has(context.local(), 100).FromJust());
5117 12 : CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5118 6 : CHECK_EQ(3u, array->Length());
5119 12 : CHECK(!array->Has(context.local(), 0).FromJust());
5120 12 : CHECK(!array->Has(context.local(), 1).FromJust());
5121 12 : CHECK(array->Has(context.local(), 2).FromJust());
5122 18 : CHECK_EQ(7, array->Get(context.local(), 2)
5123 : .ToLocalChecked()
5124 : ->Int32Value(context.local())
5125 : .FromJust());
5126 : Local<Value> obj = CompileRun("[1, 2, 3]");
5127 : Local<v8::Array> arr = obj.As<v8::Array>();
5128 6 : CHECK_EQ(3u, arr->Length());
5129 18 : CHECK_EQ(1, arr->Get(context.local(), 0)
5130 : .ToLocalChecked()
5131 : ->Int32Value(context.local())
5132 : .FromJust());
5133 18 : CHECK_EQ(2, arr->Get(context.local(), 1)
5134 : .ToLocalChecked()
5135 : ->Int32Value(context.local())
5136 : .FromJust());
5137 18 : CHECK_EQ(3, arr->Get(context.local(), 2)
5138 : .ToLocalChecked()
5139 : ->Int32Value(context.local())
5140 : .FromJust());
5141 6 : array = v8::Array::New(context->GetIsolate(), 27);
5142 6 : CHECK_EQ(27u, array->Length());
5143 6 : array = v8::Array::New(context->GetIsolate(), -27);
5144 12 : CHECK_EQ(0u, array->Length());
5145 6 : }
5146 :
5147 :
5148 180 : void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5149 30 : v8::EscapableHandleScope scope(args.GetIsolate());
5150 30 : ApiTestFuzzer::Fuzz();
5151 30 : Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5152 180 : for (int i = 0; i < args.Length(); i++) {
5153 180 : CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5154 : .FromJust());
5155 : }
5156 : args.GetReturnValue().Set(scope.Escape(result));
5157 30 : }
5158 :
5159 :
5160 23724 : THREADED_TEST(Vector) {
5161 6 : v8::Isolate* isolate = CcTest::isolate();
5162 6 : v8::HandleScope scope(isolate);
5163 6 : Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5164 18 : global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5165 12 : LocalContext context(0, global);
5166 :
5167 : const char* fun = "f()";
5168 : Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5169 6 : CHECK_EQ(0u, a0->Length());
5170 :
5171 : const char* fun2 = "f(11)";
5172 : Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5173 6 : CHECK_EQ(1u, a1->Length());
5174 18 : CHECK_EQ(11, a1->Get(context.local(), 0)
5175 : .ToLocalChecked()
5176 : ->Int32Value(context.local())
5177 : .FromJust());
5178 :
5179 : const char* fun3 = "f(12, 13)";
5180 : Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5181 6 : CHECK_EQ(2u, a2->Length());
5182 18 : CHECK_EQ(12, a2->Get(context.local(), 0)
5183 : .ToLocalChecked()
5184 : ->Int32Value(context.local())
5185 : .FromJust());
5186 18 : CHECK_EQ(13, a2->Get(context.local(), 1)
5187 : .ToLocalChecked()
5188 : ->Int32Value(context.local())
5189 : .FromJust());
5190 :
5191 : const char* fun4 = "f(14, 15, 16)";
5192 : Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5193 6 : CHECK_EQ(3u, a3->Length());
5194 18 : CHECK_EQ(14, a3->Get(context.local(), 0)
5195 : .ToLocalChecked()
5196 : ->Int32Value(context.local())
5197 : .FromJust());
5198 18 : CHECK_EQ(15, a3->Get(context.local(), 1)
5199 : .ToLocalChecked()
5200 : ->Int32Value(context.local())
5201 : .FromJust());
5202 18 : CHECK_EQ(16, a3->Get(context.local(), 2)
5203 : .ToLocalChecked()
5204 : ->Int32Value(context.local())
5205 : .FromJust());
5206 :
5207 : const char* fun5 = "f(17, 18, 19, 20)";
5208 : Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5209 6 : CHECK_EQ(4u, a4->Length());
5210 18 : CHECK_EQ(17, a4->Get(context.local(), 0)
5211 : .ToLocalChecked()
5212 : ->Int32Value(context.local())
5213 : .FromJust());
5214 18 : CHECK_EQ(18, a4->Get(context.local(), 1)
5215 : .ToLocalChecked()
5216 : ->Int32Value(context.local())
5217 : .FromJust());
5218 18 : CHECK_EQ(19, a4->Get(context.local(), 2)
5219 : .ToLocalChecked()
5220 : ->Int32Value(context.local())
5221 : .FromJust());
5222 18 : CHECK_EQ(20, a4->Get(context.local(), 3)
5223 : .ToLocalChecked()
5224 : ->Int32Value(context.local())
5225 6 : .FromJust());
5226 6 : }
5227 :
5228 :
5229 23724 : THREADED_TEST(FunctionCall) {
5230 6 : LocalContext context;
5231 6 : v8::Isolate* isolate = context->GetIsolate();
5232 12 : v8::HandleScope scope(isolate);
5233 : CompileRun(
5234 : "function Foo() {"
5235 : " var result = [];"
5236 : " for (var i = 0; i < arguments.length; i++) {"
5237 : " result.push(arguments[i]);"
5238 : " }"
5239 : " return result;"
5240 : "}"
5241 : "function ReturnThisSloppy() {"
5242 : " return this;"
5243 : "}"
5244 : "function ReturnThisStrict() {"
5245 : " 'use strict';"
5246 : " return this;"
5247 : "}");
5248 : Local<Function> Foo = Local<Function>::Cast(
5249 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5250 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5251 : context->Global()
5252 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
5253 6 : .ToLocalChecked());
5254 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
5255 : context->Global()
5256 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
5257 6 : .ToLocalChecked());
5258 :
5259 : v8::Local<Value>* args0 = nullptr;
5260 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5261 12 : Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5262 6 : CHECK_EQ(0u, a0->Length());
5263 :
5264 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5265 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5266 12 : Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5267 6 : CHECK_EQ(1u, a1->Length());
5268 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5269 : .ToLocalChecked()
5270 : ->NumberValue(context.local())
5271 : .FromJust());
5272 :
5273 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5274 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5275 12 : Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5276 6 : CHECK_EQ(2u, a2->Length());
5277 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5278 : .ToLocalChecked()
5279 : ->NumberValue(context.local())
5280 : .FromJust());
5281 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5282 : .ToLocalChecked()
5283 : ->NumberValue(context.local())
5284 : .FromJust());
5285 :
5286 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5287 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5288 12 : Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5289 6 : CHECK_EQ(3u, a3->Length());
5290 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5291 : .ToLocalChecked()
5292 : ->NumberValue(context.local())
5293 : .FromJust());
5294 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5295 : .ToLocalChecked()
5296 : ->NumberValue(context.local())
5297 : .FromJust());
5298 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5299 : .ToLocalChecked()
5300 : ->NumberValue(context.local())
5301 : .FromJust());
5302 :
5303 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5304 6 : v8_num(10.11)};
5305 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5306 12 : Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5307 6 : CHECK_EQ(4u, a4->Length());
5308 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5309 : .ToLocalChecked()
5310 : ->NumberValue(context.local())
5311 : .FromJust());
5312 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5313 : .ToLocalChecked()
5314 : ->NumberValue(context.local())
5315 : .FromJust());
5316 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5317 : .ToLocalChecked()
5318 : ->NumberValue(context.local())
5319 : .FromJust());
5320 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5321 : .ToLocalChecked()
5322 : ->NumberValue(context.local())
5323 : .FromJust());
5324 :
5325 : Local<v8::Value> r1 =
5326 : ReturnThisSloppy
5327 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5328 6 : .ToLocalChecked();
5329 12 : CHECK(r1->StrictEquals(context->Global()));
5330 : Local<v8::Value> r2 =
5331 12 : ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, nullptr)
5332 6 : .ToLocalChecked();
5333 12 : CHECK(r2->StrictEquals(context->Global()));
5334 : Local<v8::Value> r3 =
5335 6 : ReturnThisSloppy->Call(context.local(), v8_num(42), 0, nullptr)
5336 6 : .ToLocalChecked();
5337 6 : CHECK(r3->IsNumberObject());
5338 6 : CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5339 : Local<v8::Value> r4 =
5340 18 : ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, nullptr)
5341 6 : .ToLocalChecked();
5342 6 : CHECK(r4->IsStringObject());
5343 18 : CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5344 : Local<v8::Value> r5 =
5345 12 : ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, nullptr)
5346 6 : .ToLocalChecked();
5347 6 : CHECK(r5->IsBooleanObject());
5348 6 : CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5349 :
5350 : Local<v8::Value> r6 =
5351 : ReturnThisStrict
5352 12 : ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5353 6 : .ToLocalChecked();
5354 6 : CHECK(r6->IsUndefined());
5355 : Local<v8::Value> r7 =
5356 12 : ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, nullptr)
5357 6 : .ToLocalChecked();
5358 6 : CHECK(r7->IsNull());
5359 : Local<v8::Value> r8 =
5360 6 : ReturnThisStrict->Call(context.local(), v8_num(42), 0, nullptr)
5361 6 : .ToLocalChecked();
5362 6 : CHECK(r8->StrictEquals(v8_num(42)));
5363 : Local<v8::Value> r9 =
5364 18 : ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, nullptr)
5365 6 : .ToLocalChecked();
5366 12 : CHECK(r9->StrictEquals(v8_str("hello")));
5367 : Local<v8::Value> r10 =
5368 12 : ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, nullptr)
5369 6 : .ToLocalChecked();
5370 12 : CHECK(r10->StrictEquals(v8::True(isolate)));
5371 6 : }
5372 :
5373 :
5374 23724 : THREADED_TEST(ConstructCall) {
5375 6 : LocalContext context;
5376 6 : v8::Isolate* isolate = context->GetIsolate();
5377 12 : v8::HandleScope scope(isolate);
5378 : CompileRun(
5379 : "function Foo() {"
5380 : " var result = [];"
5381 : " for (var i = 0; i < arguments.length; i++) {"
5382 : " result.push(arguments[i]);"
5383 : " }"
5384 : " return result;"
5385 : "}");
5386 : Local<Function> Foo = Local<Function>::Cast(
5387 30 : context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5388 :
5389 : v8::Local<Value>* args0 = nullptr;
5390 : Local<v8::Array> a0 = Local<v8::Array>::Cast(
5391 6 : Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5392 6 : CHECK_EQ(0u, a0->Length());
5393 :
5394 6 : v8::Local<Value> args1[] = {v8_num(1.1)};
5395 : Local<v8::Array> a1 = Local<v8::Array>::Cast(
5396 6 : Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5397 6 : CHECK_EQ(1u, a1->Length());
5398 24 : CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5399 : .ToLocalChecked()
5400 : ->NumberValue(context.local())
5401 : .FromJust());
5402 :
5403 6 : v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5404 : Local<v8::Array> a2 = Local<v8::Array>::Cast(
5405 6 : Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5406 6 : CHECK_EQ(2u, a2->Length());
5407 24 : CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5408 : .ToLocalChecked()
5409 : ->NumberValue(context.local())
5410 : .FromJust());
5411 24 : CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5412 : .ToLocalChecked()
5413 : ->NumberValue(context.local())
5414 : .FromJust());
5415 :
5416 6 : v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5417 : Local<v8::Array> a3 = Local<v8::Array>::Cast(
5418 6 : Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5419 6 : CHECK_EQ(3u, a3->Length());
5420 24 : CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5421 : .ToLocalChecked()
5422 : ->NumberValue(context.local())
5423 : .FromJust());
5424 24 : CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5425 : .ToLocalChecked()
5426 : ->NumberValue(context.local())
5427 : .FromJust());
5428 24 : CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5429 : .ToLocalChecked()
5430 : ->NumberValue(context.local())
5431 : .FromJust());
5432 :
5433 : v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5434 6 : v8_num(10.11)};
5435 : Local<v8::Array> a4 = Local<v8::Array>::Cast(
5436 6 : Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5437 6 : CHECK_EQ(4u, a4->Length());
5438 24 : CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5439 : .ToLocalChecked()
5440 : ->NumberValue(context.local())
5441 : .FromJust());
5442 24 : CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5443 : .ToLocalChecked()
5444 : ->NumberValue(context.local())
5445 : .FromJust());
5446 24 : CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5447 : .ToLocalChecked()
5448 : ->NumberValue(context.local())
5449 : .FromJust());
5450 24 : CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5451 : .ToLocalChecked()
5452 : ->NumberValue(context.local())
5453 6 : .FromJust());
5454 6 : }
5455 :
5456 :
5457 23724 : THREADED_TEST(ConversionNumber) {
5458 6 : LocalContext env;
5459 6 : v8::Isolate* isolate = env->GetIsolate();
5460 12 : v8::HandleScope scope(isolate);
5461 : // Very large number.
5462 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5463 : Local<Value> obj =
5464 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5465 12 : CHECK_EQ(5312874545152.0,
5466 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5467 12 : CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5468 12 : CHECK_EQ(0, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5469 : // Large number.
5470 : CompileRun("var obj = -1234567890123;");
5471 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5472 12 : CHECK_EQ(-1234567890123.0,
5473 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5474 12 : CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5475 18 : CHECK_EQ(2382691125, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5476 : // Small positive integer.
5477 : CompileRun("var obj = 42;");
5478 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5479 12 : CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5480 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5481 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5482 : // Negative integer.
5483 : CompileRun("var obj = -37;");
5484 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5485 12 : CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5486 12 : CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5487 18 : CHECK_EQ(4294967259, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5488 : // Positive non-int32 integer.
5489 : CompileRun("var obj = 0x81234567;");
5490 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5491 12 : CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5492 12 : CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5493 18 : CHECK_EQ(2166572391, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5494 : // Fraction.
5495 : CompileRun("var obj = 42.3;");
5496 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5497 12 : CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5498 12 : CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5499 12 : CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5500 : // Large negative fraction.
5501 : CompileRun("var obj = -5726623061.75;");
5502 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5503 12 : CHECK_EQ(-5726623061.75,
5504 : obj->ToNumber(env.local()).ToLocalChecked()->Value());
5505 12 : CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5506 24 : CHECK_EQ(2863311531, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5507 6 : }
5508 :
5509 :
5510 23724 : THREADED_TEST(isNumberType) {
5511 6 : LocalContext env;
5512 12 : v8::HandleScope scope(env->GetIsolate());
5513 : // Very large number.
5514 : CompileRun("var obj = Math.pow(2,32) * 1237;");
5515 : Local<Value> obj =
5516 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5517 6 : CHECK(!obj->IsInt32());
5518 6 : CHECK(!obj->IsUint32());
5519 : // Large negative number.
5520 : CompileRun("var obj = -1234567890123;");
5521 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5522 6 : CHECK(!obj->IsInt32());
5523 6 : CHECK(!obj->IsUint32());
5524 : // Small positive integer.
5525 : CompileRun("var obj = 42;");
5526 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5527 6 : CHECK(obj->IsInt32());
5528 6 : CHECK(obj->IsUint32());
5529 : // Negative integer.
5530 : CompileRun("var obj = -37;");
5531 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5532 6 : CHECK(obj->IsInt32());
5533 6 : CHECK(!obj->IsUint32());
5534 : // Positive non-int32 integer.
5535 : CompileRun("var obj = 0x81234567;");
5536 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5537 6 : CHECK(!obj->IsInt32());
5538 6 : CHECK(obj->IsUint32());
5539 : // Fraction.
5540 : CompileRun("var obj = 42.3;");
5541 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5542 6 : CHECK(!obj->IsInt32());
5543 6 : CHECK(!obj->IsUint32());
5544 : // Large negative fraction.
5545 : CompileRun("var obj = -5726623061.75;");
5546 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5547 6 : CHECK(!obj->IsInt32());
5548 6 : CHECK(!obj->IsUint32());
5549 : // Positive zero
5550 : CompileRun("var obj = 0.0;");
5551 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5552 6 : CHECK(obj->IsInt32());
5553 6 : CHECK(obj->IsUint32());
5554 : // Positive zero
5555 : CompileRun("var obj = -0.0;");
5556 30 : obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5557 6 : CHECK(!obj->IsInt32());
5558 12 : CHECK(!obj->IsUint32());
5559 6 : }
5560 :
5561 54 : static void CheckUncle(v8::Isolate* isolate, v8::TryCatch* try_catch) {
5562 54 : CHECK(try_catch->HasCaught());
5563 54 : String::Utf8Value str_value(isolate, try_catch->Exception());
5564 54 : CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5565 54 : try_catch->Reset();
5566 54 : }
5567 :
5568 23724 : THREADED_TEST(ConversionException) {
5569 6 : LocalContext env;
5570 6 : v8::Isolate* isolate = env->GetIsolate();
5571 12 : v8::HandleScope scope(isolate);
5572 : CompileRun(
5573 : "function TestClass() { };"
5574 : "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5575 : "var obj = new TestClass();");
5576 : Local<Value> obj =
5577 30 : env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5578 :
5579 12 : v8::TryCatch try_catch(isolate);
5580 :
5581 12 : CHECK(obj->ToString(env.local()).IsEmpty());
5582 6 : CheckUncle(isolate, &try_catch);
5583 :
5584 12 : CHECK(obj->ToNumber(env.local()).IsEmpty());
5585 6 : CheckUncle(isolate, &try_catch);
5586 :
5587 12 : CHECK(obj->ToInteger(env.local()).IsEmpty());
5588 6 : CheckUncle(isolate, &try_catch);
5589 :
5590 12 : CHECK(obj->ToUint32(env.local()).IsEmpty());
5591 6 : CheckUncle(isolate, &try_catch);
5592 :
5593 12 : CHECK(obj->ToInt32(env.local()).IsEmpty());
5594 6 : CheckUncle(isolate, &try_catch);
5595 :
5596 18 : CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5597 6 : CHECK(try_catch.HasCaught());
5598 6 : try_catch.Reset();
5599 :
5600 12 : CHECK(obj->Int32Value(env.local()).IsNothing());
5601 6 : CheckUncle(isolate, &try_catch);
5602 :
5603 12 : CHECK(obj->Uint32Value(env.local()).IsNothing());
5604 6 : CheckUncle(isolate, &try_catch);
5605 :
5606 12 : CHECK(obj->NumberValue(env.local()).IsNothing());
5607 6 : CheckUncle(isolate, &try_catch);
5608 :
5609 12 : CHECK(obj->IntegerValue(env.local()).IsNothing());
5610 12 : CheckUncle(isolate, &try_catch);
5611 6 : }
5612 :
5613 :
5614 56 : void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5615 28 : ApiTestFuzzer::Fuzz();
5616 56 : args.GetIsolate()->ThrowException(v8_str("konto"));
5617 28 : }
5618 :
5619 :
5620 25 : void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5621 5 : if (args.Length() < 1) {
5622 : args.GetReturnValue().Set(false);
5623 5 : return;
5624 : }
5625 5 : v8::HandleScope scope(args.GetIsolate());
5626 10 : v8::TryCatch try_catch(args.GetIsolate());
5627 : Local<Value> result =
5628 : CompileRun(args[0]
5629 5 : ->ToString(args.GetIsolate()->GetCurrentContext())
5630 10 : .ToLocalChecked());
5631 10 : CHECK(!try_catch.HasCaught() || result.IsEmpty());
5632 10 : args.GetReturnValue().Set(try_catch.HasCaught());
5633 : }
5634 :
5635 :
5636 23724 : THREADED_TEST(APICatch) {
5637 6 : v8::Isolate* isolate = CcTest::isolate();
5638 6 : v8::HandleScope scope(isolate);
5639 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5640 : templ->Set(v8_str("ThrowFromC"),
5641 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5642 12 : LocalContext context(0, templ);
5643 : CompileRun(
5644 : "var thrown = false;"
5645 : "try {"
5646 : " ThrowFromC();"
5647 : "} catch (e) {"
5648 : " thrown = true;"
5649 : "}");
5650 : Local<Value> thrown = context->Global()
5651 24 : ->Get(context.local(), v8_str("thrown"))
5652 6 : .ToLocalChecked();
5653 18 : CHECK(thrown->BooleanValue(context.local()).FromJust());
5654 6 : }
5655 :
5656 :
5657 23724 : THREADED_TEST(APIThrowTryCatch) {
5658 6 : v8::Isolate* isolate = CcTest::isolate();
5659 6 : v8::HandleScope scope(isolate);
5660 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5661 : templ->Set(v8_str("ThrowFromC"),
5662 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5663 12 : LocalContext context(0, templ);
5664 12 : v8::TryCatch try_catch(isolate);
5665 : CompileRun("ThrowFromC();");
5666 12 : CHECK(try_catch.HasCaught());
5667 6 : }
5668 :
5669 :
5670 : // Test that a try-finally block doesn't shadow a try-catch block
5671 : // when setting up an external handler.
5672 : //
5673 : // BUG(271): Some of the exception propagation does not work on the
5674 : // ARM simulator because the simulator separates the C++ stack and the
5675 : // JS stack. This test therefore fails on the simulator. The test is
5676 : // not threaded to allow the threading tests to run on the simulator.
5677 23723 : TEST(TryCatchInTryFinally) {
5678 5 : v8::Isolate* isolate = CcTest::isolate();
5679 5 : v8::HandleScope scope(isolate);
5680 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5681 15 : templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5682 10 : LocalContext context(0, templ);
5683 : Local<Value> result = CompileRun(
5684 : "try {"
5685 : " try {"
5686 : " CCatcher('throw 7;');"
5687 : " } finally {"
5688 : " }"
5689 : "} catch (e) {"
5690 : "}");
5691 10 : CHECK(result->IsTrue());
5692 5 : }
5693 :
5694 :
5695 5 : static void check_custom_error_tostring(v8::Local<v8::Message> message,
5696 : v8::Local<v8::Value> data) {
5697 : const char* uncaught_error = "Uncaught MyError toString";
5698 25 : CHECK(message->Get()
5699 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5700 : v8_str(uncaught_error))
5701 : .FromJust());
5702 5 : }
5703 :
5704 :
5705 23723 : TEST(CustomErrorToString) {
5706 5 : LocalContext context;
5707 10 : v8::HandleScope scope(context->GetIsolate());
5708 5 : context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5709 : CompileRun(
5710 : "function MyError(name, message) { "
5711 : " this.name = name; "
5712 : " this.message = message; "
5713 : "} "
5714 : "MyError.prototype = Object.create(Error.prototype); "
5715 : "MyError.prototype.toString = function() { "
5716 : " return 'MyError toString'; "
5717 : "}; "
5718 : "throw new MyError('my name', 'my message'); ");
5719 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5720 5 : }
5721 :
5722 :
5723 15 : static void check_custom_error_message(v8::Local<v8::Message> message,
5724 : v8::Local<v8::Value> data) {
5725 : const char* uncaught_error = "Uncaught MyError: my message";
5726 45 : printf("%s\n", *v8::String::Utf8Value(CcTest::isolate(), message->Get()));
5727 60 : CHECK(message->Get()
5728 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5729 : v8_str(uncaught_error))
5730 : .FromJust());
5731 15 : }
5732 :
5733 :
5734 23723 : TEST(CustomErrorMessage) {
5735 5 : LocalContext context;
5736 10 : v8::HandleScope scope(context->GetIsolate());
5737 5 : context->GetIsolate()->AddMessageListener(check_custom_error_message);
5738 :
5739 : // Handlebars.
5740 : CompileRun(
5741 : "function MyError(msg) { "
5742 : " this.name = 'MyError'; "
5743 : " this.message = msg; "
5744 : "} "
5745 : "MyError.prototype = new Error(); "
5746 : "throw new MyError('my message'); ");
5747 :
5748 : // Closure.
5749 : CompileRun(
5750 : "function MyError(msg) { "
5751 : " this.name = 'MyError'; "
5752 : " this.message = msg; "
5753 : "} "
5754 : "inherits = function(childCtor, parentCtor) { "
5755 : " function tempCtor() {}; "
5756 : " tempCtor.prototype = parentCtor.prototype; "
5757 : " childCtor.superClass_ = parentCtor.prototype; "
5758 : " childCtor.prototype = new tempCtor(); "
5759 : " childCtor.prototype.constructor = childCtor; "
5760 : "}; "
5761 : "inherits(MyError, Error); "
5762 : "throw new MyError('my message'); ");
5763 :
5764 : // Object.create.
5765 : CompileRun(
5766 : "function MyError(msg) { "
5767 : " this.name = 'MyError'; "
5768 : " this.message = msg; "
5769 : "} "
5770 : "MyError.prototype = Object.create(Error.prototype); "
5771 : "throw new MyError('my message'); ");
5772 :
5773 10 : context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5774 5 : }
5775 :
5776 :
5777 5 : static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5778 : v8::Local<v8::Value> data) {
5779 : const char* uncaught_error = "Uncaught exception";
5780 25 : CHECK(message->Get()
5781 : ->Equals(CcTest::isolate()->GetCurrentContext(),
5782 : v8_str(uncaught_error))
5783 : .FromJust());
5784 5 : }
5785 :
5786 :
5787 23723 : TEST(CustomErrorRethrowsOnToString) {
5788 5 : LocalContext context;
5789 10 : v8::HandleScope scope(context->GetIsolate());
5790 5 : context->GetIsolate()->AddMessageListener(check_custom_rethrowing_message);
5791 :
5792 : CompileRun(
5793 : "var e = { toString: function() { throw e; } };"
5794 : "try { throw e; } finally {}");
5795 :
5796 : context->GetIsolate()->RemoveMessageListeners(
5797 10 : check_custom_rethrowing_message);
5798 5 : }
5799 :
5800 :
5801 15 : static void receive_message(v8::Local<v8::Message> message,
5802 : v8::Local<v8::Value> data) {
5803 15 : message->Get();
5804 15 : message_received = true;
5805 15 : }
5806 :
5807 :
5808 23723 : TEST(APIThrowMessage) {
5809 5 : message_received = false;
5810 5 : v8::Isolate* isolate = CcTest::isolate();
5811 5 : v8::HandleScope scope(isolate);
5812 5 : isolate->AddMessageListener(receive_message);
5813 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5814 : templ->Set(v8_str("ThrowFromC"),
5815 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5816 10 : LocalContext context(0, templ);
5817 : CompileRun("ThrowFromC();");
5818 5 : CHECK(message_received);
5819 10 : isolate->RemoveMessageListeners(receive_message);
5820 5 : }
5821 :
5822 :
5823 23723 : TEST(APIThrowMessageAndVerboseTryCatch) {
5824 5 : message_received = false;
5825 5 : v8::Isolate* isolate = CcTest::isolate();
5826 5 : v8::HandleScope scope(isolate);
5827 5 : isolate->AddMessageListener(receive_message);
5828 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5829 : templ->Set(v8_str("ThrowFromC"),
5830 15 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5831 10 : LocalContext context(0, templ);
5832 10 : v8::TryCatch try_catch(isolate);
5833 5 : try_catch.SetVerbose(true);
5834 : Local<Value> result = CompileRun("ThrowFromC();");
5835 5 : CHECK(try_catch.HasCaught());
5836 5 : CHECK(result.IsEmpty());
5837 5 : CHECK(message_received);
5838 10 : isolate->RemoveMessageListeners(receive_message);
5839 5 : }
5840 :
5841 :
5842 23723 : TEST(APIStackOverflowAndVerboseTryCatch) {
5843 5 : message_received = false;
5844 5 : LocalContext context;
5845 10 : v8::HandleScope scope(context->GetIsolate());
5846 5 : context->GetIsolate()->AddMessageListener(receive_message);
5847 10 : v8::TryCatch try_catch(context->GetIsolate());
5848 5 : try_catch.SetVerbose(true);
5849 : Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5850 5 : CHECK(try_catch.HasCaught());
5851 5 : CHECK(result.IsEmpty());
5852 5 : CHECK(message_received);
5853 10 : context->GetIsolate()->RemoveMessageListeners(receive_message);
5854 5 : }
5855 :
5856 :
5857 23724 : THREADED_TEST(ExternalScriptException) {
5858 6 : v8::Isolate* isolate = CcTest::isolate();
5859 6 : v8::HandleScope scope(isolate);
5860 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5861 : templ->Set(v8_str("ThrowFromC"),
5862 18 : v8::FunctionTemplate::New(isolate, ThrowFromC));
5863 12 : LocalContext context(0, templ);
5864 :
5865 12 : v8::TryCatch try_catch(isolate);
5866 : Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5867 6 : CHECK(result.IsEmpty());
5868 6 : CHECK(try_catch.HasCaught());
5869 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
5870 12 : CHECK_EQ(0, strcmp("konto", *exception_value));
5871 6 : }
5872 :
5873 :
5874 370 : void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5875 85 : ApiTestFuzzer::Fuzz();
5876 85 : CHECK_EQ(4, args.Length());
5877 85 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5878 170 : int count = args[0]->Int32Value(context).FromJust();
5879 170 : int cInterval = args[2]->Int32Value(context).FromJust();
5880 85 : if (count == 0) {
5881 10 : args.GetIsolate()->ThrowException(v8_str("FromC"));
5882 5 : return;
5883 : } else {
5884 80 : Local<v8::Object> global = context->Global();
5885 : Local<Value> fun =
5886 240 : global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
5887 320 : v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
5888 80 : if (count % cInterval == 0) {
5889 30 : v8::TryCatch try_catch(args.GetIsolate());
5890 : Local<Value> result = fun.As<Function>()
5891 30 : ->Call(context, global, 4, argv)
5892 60 : .FromMaybe(Local<Value>());
5893 60 : int expected = args[3]->Int32Value(context).FromJust();
5894 30 : if (try_catch.HasCaught()) {
5895 15 : CHECK_EQ(expected, count);
5896 15 : CHECK(result.IsEmpty());
5897 15 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5898 : } else {
5899 15 : CHECK_NE(expected, count);
5900 : }
5901 : args.GetReturnValue().Set(result);
5902 30 : return;
5903 : } else {
5904 : args.GetReturnValue().Set(fun.As<Function>()
5905 50 : ->Call(context, global, 4, argv)
5906 100 : .FromMaybe(v8::Local<v8::Value>()));
5907 50 : return;
5908 : }
5909 : }
5910 : }
5911 :
5912 :
5913 75 : void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5914 25 : ApiTestFuzzer::Fuzz();
5915 25 : CHECK_EQ(3, args.Length());
5916 25 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
5917 50 : bool equality = args[0]->BooleanValue(context).FromJust();
5918 50 : int count = args[1]->Int32Value(context).FromJust();
5919 50 : int expected = args[2]->Int32Value(context).FromJust();
5920 25 : if (equality) {
5921 15 : CHECK_EQ(count, expected);
5922 : } else {
5923 10 : CHECK_NE(count, expected);
5924 : }
5925 25 : }
5926 :
5927 :
5928 23724 : THREADED_TEST(EvalInTryFinally) {
5929 6 : LocalContext context;
5930 12 : v8::HandleScope scope(context->GetIsolate());
5931 12 : v8::TryCatch try_catch(context->GetIsolate());
5932 : CompileRun(
5933 : "(function() {"
5934 : " try {"
5935 : " eval('asldkf (*&^&*^');"
5936 : " } finally {"
5937 : " return;"
5938 : " }"
5939 : "})()");
5940 12 : CHECK(!try_catch.HasCaught());
5941 6 : }
5942 :
5943 :
5944 : // This test works by making a stack of alternating JavaScript and C
5945 : // activations. These activations set up exception handlers with regular
5946 : // intervals, one interval for C activations and another for JavaScript
5947 : // activations. When enough activations have been created an exception is
5948 : // thrown and we check that the right activation catches the exception and that
5949 : // no other activations do. The right activation is always the topmost one with
5950 : // a handler, regardless of whether it is in JavaScript or C.
5951 : //
5952 : // The notation used to describe a test case looks like this:
5953 : //
5954 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
5955 : //
5956 : // Each entry is an activation, either JS or C. The index is the count at that
5957 : // level. Stars identify activations with exception handlers, the @ identifies
5958 : // the exception handler that should catch the exception.
5959 : //
5960 : // BUG(271): Some of the exception propagation does not work on the
5961 : // ARM simulator because the simulator separates the C++ stack and the
5962 : // JS stack. This test therefore fails on the simulator. The test is
5963 : // not threaded to allow the threading tests to run on the simulator.
5964 23723 : TEST(ExceptionOrder) {
5965 5 : v8::Isolate* isolate = CcTest::isolate();
5966 5 : v8::HandleScope scope(isolate);
5967 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5968 15 : templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5969 : templ->Set(v8_str("CThrowCountDown"),
5970 15 : v8::FunctionTemplate::New(isolate, CThrowCountDown));
5971 10 : LocalContext context(0, templ);
5972 : CompileRun(
5973 : "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5974 : " if (count == 0) throw 'FromJS';"
5975 : " if (count % jsInterval == 0) {"
5976 : " try {"
5977 : " var value = CThrowCountDown(count - 1,"
5978 : " jsInterval,"
5979 : " cInterval,"
5980 : " expected);"
5981 : " check(false, count, expected);"
5982 : " return value;"
5983 : " } catch (e) {"
5984 : " check(true, count, expected);"
5985 : " }"
5986 : " } else {"
5987 : " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5988 : " }"
5989 : "}");
5990 : Local<Function> fun = Local<Function>::Cast(
5991 : context->Global()
5992 20 : ->Get(context.local(), v8_str("JSThrowCountDown"))
5993 5 : .ToLocalChecked());
5994 :
5995 : const int argc = 4;
5996 : // count jsInterval cInterval expected
5997 :
5998 : // *JS[4] *C[3] @JS[2] C[1] JS[0]
5999 5 : v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6000 10 : fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6001 :
6002 : // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6003 5 : v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6004 10 : fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6005 :
6006 : // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6007 5 : v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6008 10 : fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6009 :
6010 : // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6011 5 : v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6012 10 : fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6013 :
6014 : // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6015 5 : v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6016 10 : fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6017 :
6018 : // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6019 5 : v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6020 15 : fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6021 5 : }
6022 :
6023 :
6024 162 : void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6025 54 : ApiTestFuzzer::Fuzz();
6026 54 : CHECK_EQ(1, args.Length());
6027 54 : args.GetIsolate()->ThrowException(args[0]);
6028 54 : }
6029 :
6030 :
6031 23724 : THREADED_TEST(ThrowValues) {
6032 6 : v8::Isolate* isolate = CcTest::isolate();
6033 6 : v8::HandleScope scope(isolate);
6034 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6035 18 : templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6036 12 : LocalContext context(0, templ);
6037 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6038 : CompileRun("function Run(obj) {"
6039 : " try {"
6040 : " Throw(obj);"
6041 : " } catch (e) {"
6042 : " return e;"
6043 : " }"
6044 : " return 'no exception';"
6045 : "}"
6046 : "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6047 6 : CHECK_EQ(5u, result->Length());
6048 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6049 : .ToLocalChecked()
6050 : ->IsString());
6051 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6052 : .ToLocalChecked()
6053 : ->IsNumber());
6054 24 : CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6055 : .ToLocalChecked()
6056 : ->Int32Value(context.local())
6057 : .FromJust());
6058 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6059 : .ToLocalChecked()
6060 : ->IsNumber());
6061 24 : CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6062 : .ToLocalChecked()
6063 : ->Int32Value(context.local())
6064 : .FromJust());
6065 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6066 : .ToLocalChecked()
6067 : ->IsNull());
6068 18 : CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6069 : .ToLocalChecked()
6070 6 : ->IsUndefined());
6071 6 : }
6072 :
6073 :
6074 23724 : THREADED_TEST(CatchZero) {
6075 6 : LocalContext context;
6076 12 : v8::HandleScope scope(context->GetIsolate());
6077 12 : v8::TryCatch try_catch(context->GetIsolate());
6078 6 : CHECK(!try_catch.HasCaught());
6079 : CompileRun("throw 10");
6080 6 : CHECK(try_catch.HasCaught());
6081 18 : CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6082 6 : try_catch.Reset();
6083 6 : CHECK(!try_catch.HasCaught());
6084 : CompileRun("throw 0");
6085 6 : CHECK(try_catch.HasCaught());
6086 24 : CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6087 6 : }
6088 :
6089 :
6090 23724 : THREADED_TEST(CatchExceptionFromWith) {
6091 6 : LocalContext context;
6092 12 : v8::HandleScope scope(context->GetIsolate());
6093 12 : v8::TryCatch try_catch(context->GetIsolate());
6094 6 : CHECK(!try_catch.HasCaught());
6095 : CompileRun("var o = {}; with (o) { throw 42; }");
6096 12 : CHECK(try_catch.HasCaught());
6097 6 : }
6098 :
6099 :
6100 23724 : THREADED_TEST(TryCatchAndFinallyHidingException) {
6101 6 : LocalContext context;
6102 12 : v8::HandleScope scope(context->GetIsolate());
6103 12 : v8::TryCatch try_catch(context->GetIsolate());
6104 6 : CHECK(!try_catch.HasCaught());
6105 : CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6106 : CompileRun("f({toString: function() { throw 42; }});");
6107 12 : CHECK(!try_catch.HasCaught());
6108 6 : }
6109 :
6110 :
6111 6 : void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6112 6 : v8::TryCatch try_catch(args.GetIsolate());
6113 6 : }
6114 :
6115 :
6116 23724 : THREADED_TEST(TryCatchAndFinally) {
6117 6 : LocalContext context;
6118 6 : v8::Isolate* isolate = context->GetIsolate();
6119 12 : v8::HandleScope scope(isolate);
6120 48 : CHECK(context->Global()
6121 : ->Set(context.local(), v8_str("native_with_try_catch"),
6122 : v8::FunctionTemplate::New(isolate, WithTryCatch)
6123 : ->GetFunction(context.local())
6124 : .ToLocalChecked())
6125 : .FromJust());
6126 12 : v8::TryCatch try_catch(isolate);
6127 6 : CHECK(!try_catch.HasCaught());
6128 : CompileRun(
6129 : "try {\n"
6130 : " throw new Error('a');\n"
6131 : "} finally {\n"
6132 : " native_with_try_catch();\n"
6133 : "}\n");
6134 12 : CHECK(try_catch.HasCaught());
6135 6 : }
6136 :
6137 :
6138 30 : static void TryCatchNested1Helper(int depth) {
6139 30 : if (depth > 0) {
6140 25 : v8::TryCatch try_catch(CcTest::isolate());
6141 25 : try_catch.SetVerbose(true);
6142 25 : TryCatchNested1Helper(depth - 1);
6143 25 : CHECK(try_catch.HasCaught());
6144 25 : try_catch.ReThrow();
6145 : } else {
6146 10 : CcTest::isolate()->ThrowException(v8_str("E1"));
6147 : }
6148 30 : }
6149 :
6150 :
6151 30 : static void TryCatchNested2Helper(int depth) {
6152 30 : if (depth > 0) {
6153 25 : v8::TryCatch try_catch(CcTest::isolate());
6154 25 : try_catch.SetVerbose(true);
6155 25 : TryCatchNested2Helper(depth - 1);
6156 25 : CHECK(try_catch.HasCaught());
6157 25 : try_catch.ReThrow();
6158 : } else {
6159 : CompileRun("throw 'E2';");
6160 : }
6161 30 : }
6162 :
6163 :
6164 23723 : TEST(TryCatchNested) {
6165 5 : v8::V8::Initialize();
6166 5 : LocalContext context;
6167 10 : v8::HandleScope scope(context->GetIsolate());
6168 :
6169 : {
6170 : // Test nested try-catch with a native throw in the end.
6171 5 : v8::TryCatch try_catch(context->GetIsolate());
6172 5 : TryCatchNested1Helper(5);
6173 5 : CHECK(try_catch.HasCaught());
6174 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6175 : try_catch.Exception()),
6176 5 : "E1"));
6177 : }
6178 :
6179 : {
6180 : // Test nested try-catch with a JavaScript throw in the end.
6181 5 : v8::TryCatch try_catch(context->GetIsolate());
6182 5 : TryCatchNested2Helper(5);
6183 5 : CHECK(try_catch.HasCaught());
6184 10 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6185 : try_catch.Exception()),
6186 5 : "E2"));
6187 5 : }
6188 5 : }
6189 :
6190 :
6191 10 : void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6192 10 : CHECK(try_catch->HasCaught());
6193 10 : Local<Message> message = try_catch->Message();
6194 10 : Local<Value> resource = message->GetScriptOrigin().ResourceName();
6195 10 : CHECK_EQ(
6196 : 0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), resource), "inner"));
6197 20 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), message->Get()),
6198 : "Uncaught Error: a"));
6199 20 : CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6200 : .FromJust());
6201 20 : CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6202 : .FromJust());
6203 10 : }
6204 :
6205 :
6206 5 : void TryCatchMixedNestingHelper(
6207 5 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6208 5 : ApiTestFuzzer::Fuzz();
6209 5 : v8::TryCatch try_catch(args.GetIsolate());
6210 5 : CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6211 5 : CHECK(try_catch.HasCaught());
6212 5 : TryCatchMixedNestingCheck(&try_catch);
6213 5 : try_catch.ReThrow();
6214 5 : }
6215 :
6216 :
6217 : // This test ensures that an outer TryCatch in the following situation:
6218 : // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6219 : // does not clobber the Message object generated for the inner TryCatch.
6220 : // This exercises the ability of TryCatch.ReThrow() to restore the
6221 : // inner pending Message before throwing the exception again.
6222 23723 : TEST(TryCatchMixedNesting) {
6223 5 : v8::Isolate* isolate = CcTest::isolate();
6224 5 : v8::HandleScope scope(isolate);
6225 5 : v8::V8::Initialize();
6226 10 : v8::TryCatch try_catch(isolate);
6227 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6228 : templ->Set(v8_str("TryCatchMixedNestingHelper"),
6229 15 : v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6230 10 : LocalContext context(0, templ);
6231 5 : CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6232 10 : TryCatchMixedNestingCheck(&try_catch);
6233 5 : }
6234 :
6235 :
6236 15 : void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6237 5 : ApiTestFuzzer::Fuzz();
6238 5 : v8::TryCatch try_catch(args.GetIsolate());
6239 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6240 5 : CHECK(try_catch.HasCaught());
6241 5 : }
6242 :
6243 :
6244 23723 : TEST(TryCatchNative) {
6245 5 : v8::Isolate* isolate = CcTest::isolate();
6246 5 : v8::HandleScope scope(isolate);
6247 5 : v8::V8::Initialize();
6248 10 : v8::TryCatch try_catch(isolate);
6249 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6250 : templ->Set(v8_str("TryCatchNativeHelper"),
6251 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6252 10 : LocalContext context(0, templ);
6253 : CompileRun("TryCatchNativeHelper();");
6254 10 : CHECK(!try_catch.HasCaught());
6255 5 : }
6256 :
6257 :
6258 5 : void TryCatchNativeResetHelper(
6259 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
6260 5 : ApiTestFuzzer::Fuzz();
6261 5 : v8::TryCatch try_catch(args.GetIsolate());
6262 10 : args.GetIsolate()->ThrowException(v8_str("boom"));
6263 5 : CHECK(try_catch.HasCaught());
6264 5 : try_catch.Reset();
6265 5 : CHECK(!try_catch.HasCaught());
6266 5 : }
6267 :
6268 :
6269 23723 : TEST(TryCatchNativeReset) {
6270 5 : v8::Isolate* isolate = CcTest::isolate();
6271 5 : v8::HandleScope scope(isolate);
6272 5 : v8::V8::Initialize();
6273 10 : v8::TryCatch try_catch(isolate);
6274 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6275 : templ->Set(v8_str("TryCatchNativeResetHelper"),
6276 15 : v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6277 10 : LocalContext context(0, templ);
6278 : CompileRun("TryCatchNativeResetHelper();");
6279 10 : CHECK(!try_catch.HasCaught());
6280 5 : }
6281 :
6282 :
6283 23724 : THREADED_TEST(Equality) {
6284 6 : LocalContext context;
6285 6 : v8::Isolate* isolate = context->GetIsolate();
6286 12 : v8::HandleScope scope(context->GetIsolate());
6287 : // Check that equality works at all before relying on CHECK_EQ
6288 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6289 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6290 :
6291 24 : CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6292 24 : CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6293 18 : CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6294 18 : CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6295 18 : CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6296 :
6297 : // Assume String is not internalized.
6298 18 : CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6299 18 : CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6300 12 : CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6301 12 : CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6302 12 : CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6303 12 : CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6304 6 : Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6305 6 : CHECK(!not_a_number->StrictEquals(not_a_number));
6306 6 : CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6307 6 : CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6308 :
6309 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
6310 : v8::Persistent<v8::Object> alias(isolate, obj);
6311 6 : CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6312 : alias.Reset();
6313 :
6314 18 : CHECK(v8_str("a")->SameValue(v8_str("a")));
6315 18 : CHECK(!v8_str("a")->SameValue(v8_str("b")));
6316 12 : CHECK(!v8_str("5")->SameValue(v8_num(5)));
6317 12 : CHECK(v8_num(1)->SameValue(v8_num(1)));
6318 12 : CHECK(!v8_num(1)->SameValue(v8_num(2)));
6319 12 : CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6320 6 : CHECK(not_a_number->SameValue(not_a_number));
6321 6 : CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6322 12 : CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6323 6 : }
6324 :
6325 23724 : THREADED_TEST(TypeOf) {
6326 6 : LocalContext context;
6327 6 : v8::Isolate* isolate = context->GetIsolate();
6328 12 : v8::HandleScope scope(context->GetIsolate());
6329 :
6330 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6331 12 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6332 :
6333 30 : CHECK(v8::Undefined(isolate)
6334 : ->TypeOf(isolate)
6335 : ->Equals(context.local(), v8_str("undefined"))
6336 : .FromJust());
6337 30 : CHECK(v8::Null(isolate)
6338 : ->TypeOf(isolate)
6339 : ->Equals(context.local(), v8_str("object"))
6340 : .FromJust());
6341 30 : CHECK(v8_str("str")
6342 : ->TypeOf(isolate)
6343 : ->Equals(context.local(), v8_str("string"))
6344 : .FromJust());
6345 30 : CHECK(v8_num(0.0)
6346 : ->TypeOf(isolate)
6347 : ->Equals(context.local(), v8_str("number"))
6348 : .FromJust());
6349 30 : CHECK(v8_num(1)
6350 : ->TypeOf(isolate)
6351 : ->Equals(context.local(), v8_str("number"))
6352 : .FromJust());
6353 30 : CHECK(v8::Object::New(isolate)
6354 : ->TypeOf(isolate)
6355 : ->Equals(context.local(), v8_str("object"))
6356 : .FromJust());
6357 30 : CHECK(v8::Boolean::New(isolate, true)
6358 : ->TypeOf(isolate)
6359 : ->Equals(context.local(), v8_str("boolean"))
6360 : .FromJust());
6361 24 : CHECK(fun->TypeOf(isolate)
6362 : ->Equals(context.local(), v8_str("function"))
6363 6 : .FromJust());
6364 6 : }
6365 :
6366 23724 : THREADED_TEST(InstanceOf) {
6367 6 : LocalContext env;
6368 12 : v8::HandleScope scope(env->GetIsolate());
6369 : CompileRun(
6370 : "var A = {};"
6371 : "var B = {};"
6372 : "var C = {};"
6373 : "B.__proto__ = A;"
6374 : "C.__proto__ = B;"
6375 : "function F() {}"
6376 : "F.prototype = A;"
6377 : "var G = { [Symbol.hasInstance] : null};"
6378 : "var H = { [Symbol.hasInstance] : () => { throw new Error(); } };"
6379 : "var J = { [Symbol.hasInstance] : () => true };"
6380 : "class K {}"
6381 : "var D = new K;"
6382 : "class L extends K {}"
6383 : "var E = new L");
6384 :
6385 6 : v8::Local<v8::Object> f = v8::Local<v8::Object>::Cast(CompileRun("F"));
6386 6 : v8::Local<v8::Object> g = v8::Local<v8::Object>::Cast(CompileRun("G"));
6387 6 : v8::Local<v8::Object> h = v8::Local<v8::Object>::Cast(CompileRun("H"));
6388 6 : v8::Local<v8::Object> j = v8::Local<v8::Object>::Cast(CompileRun("J"));
6389 6 : v8::Local<v8::Object> k = v8::Local<v8::Object>::Cast(CompileRun("K"));
6390 6 : v8::Local<v8::Object> l = v8::Local<v8::Object>::Cast(CompileRun("L"));
6391 : v8::Local<v8::Value> a = v8::Local<v8::Value>::Cast(CompileRun("A"));
6392 : v8::Local<v8::Value> b = v8::Local<v8::Value>::Cast(CompileRun("B"));
6393 : v8::Local<v8::Value> c = v8::Local<v8::Value>::Cast(CompileRun("C"));
6394 : v8::Local<v8::Value> d = v8::Local<v8::Value>::Cast(CompileRun("D"));
6395 : v8::Local<v8::Value> e = v8::Local<v8::Value>::Cast(CompileRun("E"));
6396 :
6397 12 : v8::TryCatch try_catch(env->GetIsolate());
6398 12 : CHECK(!a->InstanceOf(env.local(), f).ToChecked());
6399 12 : CHECK(b->InstanceOf(env.local(), f).ToChecked());
6400 12 : CHECK(c->InstanceOf(env.local(), f).ToChecked());
6401 12 : CHECK(!d->InstanceOf(env.local(), f).ToChecked());
6402 12 : CHECK(!e->InstanceOf(env.local(), f).ToChecked());
6403 6 : CHECK(!try_catch.HasCaught());
6404 :
6405 12 : CHECK(a->InstanceOf(env.local(), g).IsNothing());
6406 6 : CHECK(try_catch.HasCaught());
6407 6 : try_catch.Reset();
6408 :
6409 12 : CHECK(b->InstanceOf(env.local(), h).IsNothing());
6410 6 : CHECK(try_catch.HasCaught());
6411 6 : try_catch.Reset();
6412 :
6413 18 : CHECK(v8_num(1)->InstanceOf(env.local(), j).ToChecked());
6414 6 : CHECK(!try_catch.HasCaught());
6415 :
6416 12 : CHECK(d->InstanceOf(env.local(), k).ToChecked());
6417 12 : CHECK(e->InstanceOf(env.local(), k).ToChecked());
6418 12 : CHECK(!d->InstanceOf(env.local(), l).ToChecked());
6419 12 : CHECK(e->InstanceOf(env.local(), l).ToChecked());
6420 12 : CHECK(!try_catch.HasCaught());
6421 6 : }
6422 :
6423 23724 : THREADED_TEST(MultiRun) {
6424 6 : LocalContext context;
6425 12 : v8::HandleScope scope(context->GetIsolate());
6426 : Local<Script> script = v8_compile("x");
6427 66 : for (int i = 0; i < 10; i++) {
6428 60 : script->Run(context.local()).IsEmpty();
6429 6 : }
6430 6 : }
6431 :
6432 :
6433 204 : static void GetXValue(Local<Name> name,
6434 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6435 204 : ApiTestFuzzer::Fuzz();
6436 816 : CHECK(info.Data()
6437 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6438 : .FromJust());
6439 816 : CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6440 : .FromJust());
6441 : info.GetReturnValue().Set(name);
6442 204 : }
6443 :
6444 :
6445 23724 : THREADED_TEST(SimplePropertyRead) {
6446 6 : LocalContext context;
6447 6 : v8::Isolate* isolate = context->GetIsolate();
6448 12 : v8::HandleScope scope(isolate);
6449 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6450 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6451 36 : CHECK(context->Global()
6452 : ->Set(context.local(), v8_str("obj"),
6453 : templ->NewInstance(context.local()).ToLocalChecked())
6454 : .FromJust());
6455 : Local<Script> script = v8_compile("obj.x");
6456 66 : for (int i = 0; i < 10; i++) {
6457 60 : Local<Value> result = script->Run(context.local()).ToLocalChecked();
6458 180 : CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6459 6 : }
6460 6 : }
6461 :
6462 :
6463 23724 : THREADED_TEST(DefinePropertyOnAPIAccessor) {
6464 6 : LocalContext context;
6465 6 : v8::Isolate* isolate = context->GetIsolate();
6466 12 : v8::HandleScope scope(isolate);
6467 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6468 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6469 36 : CHECK(context->Global()
6470 : ->Set(context.local(), v8_str("obj"),
6471 : templ->NewInstance(context.local()).ToLocalChecked())
6472 : .FromJust());
6473 :
6474 : // Uses getOwnPropertyDescriptor to check the configurable status
6475 : Local<Script> script_desc = v8_compile(
6476 : "var prop = Object.getOwnPropertyDescriptor( "
6477 : "obj, 'x');"
6478 : "prop.configurable;");
6479 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6480 12 : CHECK(result->BooleanValue(context.local()).FromJust());
6481 :
6482 : // Redefine get - but still configurable
6483 : Local<Script> script_define = v8_compile(
6484 : "var desc = { get: function(){return 42; },"
6485 : " configurable: true };"
6486 : "Object.defineProperty(obj, 'x', desc);"
6487 : "obj.x");
6488 6 : result = script_define->Run(context.local()).ToLocalChecked();
6489 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6490 :
6491 : // Check that the accessor is still configurable
6492 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6493 12 : CHECK(result->BooleanValue(context.local()).FromJust());
6494 :
6495 : // Redefine to a non-configurable
6496 : script_define = v8_compile(
6497 : "var desc = { get: function(){return 43; },"
6498 : " configurable: false };"
6499 : "Object.defineProperty(obj, 'x', desc);"
6500 : "obj.x");
6501 6 : result = script_define->Run(context.local()).ToLocalChecked();
6502 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6503 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6504 12 : CHECK(!result->BooleanValue(context.local()).FromJust());
6505 :
6506 : // Make sure that it is not possible to redefine again
6507 12 : v8::TryCatch try_catch(isolate);
6508 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6509 6 : CHECK(try_catch.HasCaught());
6510 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6511 6 : CHECK_EQ(0,
6512 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6513 6 : }
6514 :
6515 :
6516 23724 : THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6517 6 : v8::Isolate* isolate = CcTest::isolate();
6518 6 : v8::HandleScope scope(isolate);
6519 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6520 18 : templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6521 12 : LocalContext context;
6522 36 : CHECK(context->Global()
6523 : ->Set(context.local(), v8_str("obj"),
6524 : templ->NewInstance(context.local()).ToLocalChecked())
6525 : .FromJust());
6526 :
6527 : Local<Script> script_desc = v8_compile(
6528 : "var prop ="
6529 : "Object.getOwnPropertyDescriptor( "
6530 : "obj, 'x');"
6531 : "prop.configurable;");
6532 6 : Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6533 12 : CHECK(result->BooleanValue(context.local()).FromJust());
6534 :
6535 : Local<Script> script_define = v8_compile(
6536 : "var desc = {get: function(){return 42; },"
6537 : " configurable: true };"
6538 : "Object.defineProperty(obj, 'x', desc);"
6539 : "obj.x");
6540 6 : result = script_define->Run(context.local()).ToLocalChecked();
6541 12 : CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6542 :
6543 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6544 12 : CHECK(result->BooleanValue(context.local()).FromJust());
6545 :
6546 : script_define = v8_compile(
6547 : "var desc = {get: function(){return 43; },"
6548 : " configurable: false };"
6549 : "Object.defineProperty(obj, 'x', desc);"
6550 : "obj.x");
6551 6 : result = script_define->Run(context.local()).ToLocalChecked();
6552 12 : CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6553 :
6554 6 : result = script_desc->Run(context.local()).ToLocalChecked();
6555 12 : CHECK(!result->BooleanValue(context.local()).FromJust());
6556 :
6557 12 : v8::TryCatch try_catch(isolate);
6558 12 : CHECK(script_define->Run(context.local()).IsEmpty());
6559 6 : CHECK(try_catch.HasCaught());
6560 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6561 6 : CHECK_EQ(0,
6562 6 : strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6563 6 : }
6564 :
6565 :
6566 72 : static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6567 : char const* name) {
6568 : return v8::Local<v8::Object>::Cast(
6569 : (*context)
6570 : ->Global()
6571 288 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6572 144 : .ToLocalChecked());
6573 : }
6574 :
6575 :
6576 23724 : THREADED_TEST(DefineAPIAccessorOnObject) {
6577 6 : v8::Isolate* isolate = CcTest::isolate();
6578 6 : v8::HandleScope scope(isolate);
6579 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6580 12 : LocalContext context;
6581 :
6582 42 : CHECK(context->Global()
6583 : ->Set(context.local(), v8_str("obj1"),
6584 : templ->NewInstance(context.local()).ToLocalChecked())
6585 : .FromJust());
6586 : CompileRun("var obj2 = {};");
6587 :
6588 6 : CHECK(CompileRun("obj1.x")->IsUndefined());
6589 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6590 :
6591 30 : CHECK(GetGlobalProperty(&context, "obj1")
6592 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6593 : v8_str("donut"))
6594 : .FromJust());
6595 :
6596 6 : ExpectString("obj1.x", "x");
6597 6 : CHECK(CompileRun("obj2.x")->IsUndefined());
6598 :
6599 30 : CHECK(GetGlobalProperty(&context, "obj2")
6600 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6601 : v8_str("donut"))
6602 : .FromJust());
6603 :
6604 6 : ExpectString("obj1.x", "x");
6605 6 : ExpectString("obj2.x", "x");
6606 :
6607 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6608 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6609 :
6610 : CompileRun(
6611 : "Object.defineProperty(obj1, 'x',"
6612 : "{ get: function() { return 'y'; }, configurable: true })");
6613 :
6614 6 : ExpectString("obj1.x", "y");
6615 6 : ExpectString("obj2.x", "x");
6616 :
6617 : CompileRun(
6618 : "Object.defineProperty(obj2, 'x',"
6619 : "{ get: function() { return 'y'; }, configurable: true })");
6620 :
6621 6 : ExpectString("obj1.x", "y");
6622 6 : ExpectString("obj2.x", "y");
6623 :
6624 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6625 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6626 :
6627 30 : CHECK(GetGlobalProperty(&context, "obj1")
6628 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6629 : v8_str("donut"))
6630 : .FromJust());
6631 30 : CHECK(GetGlobalProperty(&context, "obj2")
6632 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6633 : v8_str("donut"))
6634 : .FromJust());
6635 :
6636 6 : ExpectString("obj1.x", "x");
6637 6 : ExpectString("obj2.x", "x");
6638 :
6639 : ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6640 : ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6641 :
6642 : // Define getters/setters, but now make them not configurable.
6643 : CompileRun(
6644 : "Object.defineProperty(obj1, 'x',"
6645 : "{ get: function() { return 'z'; }, configurable: false })");
6646 : CompileRun(
6647 : "Object.defineProperty(obj2, 'x',"
6648 : "{ get: function() { return 'z'; }, configurable: false })");
6649 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6650 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6651 :
6652 6 : ExpectString("obj1.x", "z");
6653 6 : ExpectString("obj2.x", "z");
6654 :
6655 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6656 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6657 : v8_str("donut"))
6658 : .FromJust());
6659 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6660 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6661 : v8_str("donut"))
6662 : .FromJust());
6663 :
6664 6 : ExpectString("obj1.x", "z");
6665 12 : ExpectString("obj2.x", "z");
6666 6 : }
6667 :
6668 :
6669 23724 : THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6670 6 : v8::Isolate* isolate = CcTest::isolate();
6671 6 : v8::HandleScope scope(isolate);
6672 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6673 12 : LocalContext context;
6674 :
6675 42 : CHECK(context->Global()
6676 : ->Set(context.local(), v8_str("obj1"),
6677 : templ->NewInstance(context.local()).ToLocalChecked())
6678 : .FromJust());
6679 : CompileRun("var obj2 = {};");
6680 :
6681 30 : CHECK(GetGlobalProperty(&context, "obj1")
6682 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6683 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6684 : .FromJust());
6685 30 : CHECK(GetGlobalProperty(&context, "obj2")
6686 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6687 : v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6688 : .FromJust());
6689 :
6690 6 : ExpectString("obj1.x", "x");
6691 6 : ExpectString("obj2.x", "x");
6692 :
6693 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6694 : ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6695 :
6696 30 : CHECK(!GetGlobalProperty(&context, "obj1")
6697 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6698 : v8_str("donut"))
6699 : .FromJust());
6700 30 : CHECK(!GetGlobalProperty(&context, "obj2")
6701 : ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6702 : v8_str("donut"))
6703 : .FromJust());
6704 :
6705 : {
6706 6 : v8::TryCatch try_catch(isolate);
6707 : CompileRun(
6708 : "Object.defineProperty(obj1, 'x',"
6709 : "{get: function() { return 'func'; }})");
6710 6 : CHECK(try_catch.HasCaught());
6711 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6712 6 : CHECK_EQ(
6713 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6714 : }
6715 : {
6716 6 : v8::TryCatch try_catch(isolate);
6717 : CompileRun(
6718 : "Object.defineProperty(obj2, 'x',"
6719 : "{get: function() { return 'func'; }})");
6720 6 : CHECK(try_catch.HasCaught());
6721 12 : String::Utf8Value exception_value(isolate, try_catch.Exception());
6722 6 : CHECK_EQ(
6723 6 : 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6724 6 : }
6725 6 : }
6726 :
6727 :
6728 24 : static void Get239Value(Local<Name> name,
6729 : const v8::PropertyCallbackInfo<v8::Value>& info) {
6730 24 : ApiTestFuzzer::Fuzz();
6731 96 : CHECK(info.Data()
6732 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6733 : .FromJust());
6734 96 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6735 : .FromJust());
6736 : info.GetReturnValue().Set(name);
6737 24 : }
6738 :
6739 :
6740 23724 : THREADED_TEST(ElementAPIAccessor) {
6741 6 : v8::Isolate* isolate = CcTest::isolate();
6742 6 : v8::HandleScope scope(isolate);
6743 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6744 12 : LocalContext context;
6745 :
6746 42 : CHECK(context->Global()
6747 : ->Set(context.local(), v8_str("obj1"),
6748 : templ->NewInstance(context.local()).ToLocalChecked())
6749 : .FromJust());
6750 : CompileRun("var obj2 = {};");
6751 :
6752 30 : CHECK(GetGlobalProperty(&context, "obj1")
6753 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6754 : v8_str("donut"))
6755 : .FromJust());
6756 30 : CHECK(GetGlobalProperty(&context, "obj2")
6757 : ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6758 : v8_str("donut"))
6759 : .FromJust());
6760 :
6761 6 : ExpectString("obj1[239]", "239");
6762 6 : ExpectString("obj2[239]", "239");
6763 6 : ExpectString("obj1['239']", "239");
6764 12 : ExpectString("obj2['239']", "239");
6765 6 : }
6766 :
6767 :
6768 23718 : v8::Persistent<Value> xValue;
6769 :
6770 :
6771 120 : static void SetXValue(Local<Name> name, Local<Value> value,
6772 : const v8::PropertyCallbackInfo<void>& info) {
6773 120 : Local<Context> context = info.GetIsolate()->GetCurrentContext();
6774 240 : CHECK(value->Equals(context, v8_num(4)).FromJust());
6775 360 : CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6776 360 : CHECK(name->Equals(context, v8_str("x")).FromJust());
6777 120 : CHECK(xValue.IsEmpty());
6778 : xValue.Reset(info.GetIsolate(), value);
6779 120 : }
6780 :
6781 :
6782 23724 : THREADED_TEST(SimplePropertyWrite) {
6783 6 : v8::Isolate* isolate = CcTest::isolate();
6784 6 : v8::HandleScope scope(isolate);
6785 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6786 18 : templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6787 12 : LocalContext context;
6788 36 : CHECK(context->Global()
6789 : ->Set(context.local(), v8_str("obj"),
6790 : templ->NewInstance(context.local()).ToLocalChecked())
6791 : .FromJust());
6792 : Local<Script> script = v8_compile("obj.x = 4");
6793 66 : for (int i = 0; i < 10; i++) {
6794 60 : CHECK(xValue.IsEmpty());
6795 60 : script->Run(context.local()).ToLocalChecked();
6796 240 : CHECK(v8_num(4)
6797 : ->Equals(context.local(),
6798 : Local<Value>::New(CcTest::isolate(), xValue))
6799 : .FromJust());
6800 : xValue.Reset();
6801 6 : }
6802 6 : }
6803 :
6804 :
6805 23724 : THREADED_TEST(SetterOnly) {
6806 6 : v8::Isolate* isolate = CcTest::isolate();
6807 6 : v8::HandleScope scope(isolate);
6808 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6809 18 : templ->SetAccessor(v8_str("x"), nullptr, SetXValue, v8_str("donut"));
6810 12 : LocalContext context;
6811 36 : CHECK(context->Global()
6812 : ->Set(context.local(), v8_str("obj"),
6813 : templ->NewInstance(context.local()).ToLocalChecked())
6814 : .FromJust());
6815 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
6816 66 : for (int i = 0; i < 10; i++) {
6817 60 : CHECK(xValue.IsEmpty());
6818 60 : script->Run(context.local()).ToLocalChecked();
6819 240 : CHECK(v8_num(4)
6820 : ->Equals(context.local(),
6821 : Local<Value>::New(CcTest::isolate(), xValue))
6822 : .FromJust());
6823 : xValue.Reset();
6824 6 : }
6825 6 : }
6826 :
6827 :
6828 23724 : THREADED_TEST(NoAccessors) {
6829 6 : v8::Isolate* isolate = CcTest::isolate();
6830 6 : v8::HandleScope scope(isolate);
6831 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6832 : templ->SetAccessor(v8_str("x"),
6833 : static_cast<v8::AccessorGetterCallback>(nullptr), nullptr,
6834 12 : v8_str("donut"));
6835 12 : LocalContext context;
6836 36 : CHECK(context->Global()
6837 : ->Set(context.local(), v8_str("obj"),
6838 : templ->NewInstance(context.local()).ToLocalChecked())
6839 : .FromJust());
6840 : Local<Script> script = v8_compile("obj.x = 4; obj.x");
6841 66 : for (int i = 0; i < 10; i++) {
6842 60 : script->Run(context.local()).ToLocalChecked();
6843 6 : }
6844 6 : }
6845 :
6846 :
6847 23724 : THREADED_TEST(MultiContexts) {
6848 6 : v8::Isolate* isolate = CcTest::isolate();
6849 6 : v8::HandleScope scope(isolate);
6850 6 : v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6851 : templ->Set(v8_str("dummy"),
6852 18 : v8::FunctionTemplate::New(isolate, DummyCallHandler));
6853 :
6854 6 : Local<String> password = v8_str("Password");
6855 :
6856 : // Create an environment
6857 12 : LocalContext context0(0, templ);
6858 6 : context0->SetSecurityToken(password);
6859 6 : v8::Local<v8::Object> global0 = context0->Global();
6860 18 : CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
6861 : .FromJust());
6862 24 : CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
6863 : .ToLocalChecked()
6864 : ->Int32Value(context0.local())
6865 : .FromJust());
6866 :
6867 : // Create an independent environment
6868 12 : LocalContext context1(0, templ);
6869 6 : context1->SetSecurityToken(password);
6870 6 : v8::Local<v8::Object> global1 = context1->Global();
6871 18 : CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
6872 : .FromJust());
6873 12 : CHECK(!global0->Equals(context1.local(), global1).FromJust());
6874 24 : CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
6875 : .ToLocalChecked()
6876 : ->Int32Value(context0.local())
6877 : .FromJust());
6878 24 : CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
6879 : .ToLocalChecked()
6880 : ->Int32Value(context1.local())
6881 : .FromJust());
6882 :
6883 : // Now create a new context with the old global
6884 12 : LocalContext context2(0, templ, global1);
6885 6 : context2->SetSecurityToken(password);
6886 6 : v8::Local<v8::Object> global2 = context2->Global();
6887 12 : CHECK(global1->Equals(context2.local(), global2).FromJust());
6888 24 : CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
6889 : .ToLocalChecked()
6890 : ->Int32Value(context1.local())
6891 : .FromJust());
6892 24 : CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
6893 : .ToLocalChecked()
6894 : ->Int32Value(context2.local())
6895 6 : .FromJust());
6896 6 : }
6897 :
6898 :
6899 23724 : THREADED_TEST(FunctionPrototypeAcrossContexts) {
6900 : // Make sure that functions created by cloning boilerplates cannot
6901 : // communicate through their __proto__ field.
6902 :
6903 6 : v8::HandleScope scope(CcTest::isolate());
6904 :
6905 12 : LocalContext env0;
6906 6 : v8::Local<v8::Object> global0 = env0->Global();
6907 18 : v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
6908 6 : .ToLocalChecked()
6909 : .As<v8::Object>();
6910 : v8::Local<v8::Object> tostring0 =
6911 18 : object0->Get(env0.local(), v8_str("toString"))
6912 6 : .ToLocalChecked()
6913 : .As<v8::Object>();
6914 : v8::Local<v8::Object> proto0 =
6915 18 : tostring0->Get(env0.local(), v8_str("__proto__"))
6916 6 : .ToLocalChecked()
6917 : .As<v8::Object>();
6918 18 : CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
6919 :
6920 12 : LocalContext env1;
6921 6 : v8::Local<v8::Object> global1 = env1->Global();
6922 18 : v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
6923 6 : .ToLocalChecked()
6924 : .As<v8::Object>();
6925 : v8::Local<v8::Object> tostring1 =
6926 18 : object1->Get(env1.local(), v8_str("toString"))
6927 6 : .ToLocalChecked()
6928 : .As<v8::Object>();
6929 : v8::Local<v8::Object> proto1 =
6930 18 : tostring1->Get(env1.local(), v8_str("__proto__"))
6931 6 : .ToLocalChecked()
6932 : .As<v8::Object>();
6933 24 : CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
6934 6 : }
6935 :
6936 :
6937 23724 : THREADED_TEST(Regress892105) {
6938 : // Make sure that object and array literals created by cloning
6939 : // boilerplates cannot communicate through their __proto__
6940 : // field. This is rather difficult to check, but we try to add stuff
6941 : // to Object.prototype and Array.prototype and create a new
6942 : // environment. This should succeed.
6943 :
6944 6 : v8::HandleScope scope(CcTest::isolate());
6945 :
6946 : Local<String> source = v8_str(
6947 : "Object.prototype.obj = 1234;"
6948 : "Array.prototype.arr = 4567;"
6949 6 : "8901");
6950 :
6951 12 : LocalContext env0;
6952 6 : Local<Script> script0 = v8_compile(source);
6953 24 : CHECK_EQ(8901.0, script0->Run(env0.local())
6954 : .ToLocalChecked()
6955 : ->NumberValue(env0.local())
6956 : .FromJust());
6957 :
6958 12 : LocalContext env1;
6959 6 : Local<Script> script1 = v8_compile(source);
6960 24 : CHECK_EQ(8901.0, script1->Run(env1.local())
6961 : .ToLocalChecked()
6962 : ->NumberValue(env1.local())
6963 6 : .FromJust());
6964 6 : }
6965 :
6966 60 : static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
6967 : args.GetReturnValue().Set(args.This());
6968 30 : }
6969 :
6970 23724 : THREADED_TEST(UndetectableObject) {
6971 6 : LocalContext env;
6972 12 : v8::HandleScope scope(env->GetIsolate());
6973 :
6974 : Local<v8::FunctionTemplate> desc =
6975 6 : v8::FunctionTemplate::New(env->GetIsolate());
6976 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6977 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
6978 :
6979 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
6980 6 : .ToLocalChecked()
6981 6 : ->NewInstance(env.local())
6982 : .ToLocalChecked();
6983 30 : CHECK(
6984 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
6985 :
6986 6 : ExpectString("undetectable.toString()", "[object Object]");
6987 6 : ExpectString("typeof undetectable", "undefined");
6988 6 : ExpectString("typeof(undetectable)", "undefined");
6989 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
6990 6 : ExpectBoolean("typeof undetectable == 'object'", false);
6991 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6992 6 : ExpectBoolean("!undetectable", true);
6993 :
6994 6 : ExpectObject("true&&undetectable", obj);
6995 6 : ExpectBoolean("false&&undetectable", false);
6996 6 : ExpectBoolean("true||undetectable", true);
6997 6 : ExpectObject("false||undetectable", obj);
6998 :
6999 6 : ExpectObject("undetectable&&true", obj);
7000 6 : ExpectObject("undetectable&&false", obj);
7001 6 : ExpectBoolean("undetectable||true", true);
7002 6 : ExpectBoolean("undetectable||false", false);
7003 :
7004 6 : ExpectBoolean("undetectable==null", true);
7005 6 : ExpectBoolean("null==undetectable", true);
7006 6 : ExpectBoolean("undetectable==undefined", true);
7007 6 : ExpectBoolean("undefined==undetectable", true);
7008 6 : ExpectBoolean("undetectable==undetectable", true);
7009 :
7010 :
7011 6 : ExpectBoolean("undetectable===null", false);
7012 6 : ExpectBoolean("null===undetectable", false);
7013 6 : ExpectBoolean("undetectable===undefined", false);
7014 6 : ExpectBoolean("undefined===undetectable", false);
7015 12 : ExpectBoolean("undetectable===undetectable", true);
7016 6 : }
7017 :
7018 :
7019 23724 : THREADED_TEST(VoidLiteral) {
7020 6 : LocalContext env;
7021 6 : v8::Isolate* isolate = env->GetIsolate();
7022 12 : v8::HandleScope scope(isolate);
7023 :
7024 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7025 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7026 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7027 :
7028 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7029 6 : .ToLocalChecked()
7030 6 : ->NewInstance(env.local())
7031 : .ToLocalChecked();
7032 30 : CHECK(
7033 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7034 :
7035 6 : ExpectBoolean("undefined == void 0", true);
7036 6 : ExpectBoolean("undetectable == void 0", true);
7037 6 : ExpectBoolean("null == void 0", true);
7038 6 : ExpectBoolean("undefined === void 0", true);
7039 6 : ExpectBoolean("undetectable === void 0", false);
7040 6 : ExpectBoolean("null === void 0", false);
7041 :
7042 6 : ExpectBoolean("void 0 == undefined", true);
7043 6 : ExpectBoolean("void 0 == undetectable", true);
7044 6 : ExpectBoolean("void 0 == null", true);
7045 6 : ExpectBoolean("void 0 === undefined", true);
7046 6 : ExpectBoolean("void 0 === undetectable", false);
7047 6 : ExpectBoolean("void 0 === null", false);
7048 :
7049 : ExpectString(
7050 : "(function() {"
7051 : " try {"
7052 : " return x === void 0;"
7053 : " } catch(e) {"
7054 : " return e.toString();"
7055 : " }"
7056 : "})()",
7057 6 : "ReferenceError: x is not defined");
7058 : ExpectString(
7059 : "(function() {"
7060 : " try {"
7061 : " return void 0 === x;"
7062 : " } catch(e) {"
7063 : " return e.toString();"
7064 : " }"
7065 : "})()",
7066 12 : "ReferenceError: x is not defined");
7067 6 : }
7068 :
7069 :
7070 23724 : THREADED_TEST(ExtensibleOnUndetectable) {
7071 6 : LocalContext env;
7072 6 : v8::Isolate* isolate = env->GetIsolate();
7073 12 : v8::HandleScope scope(isolate);
7074 :
7075 6 : Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7076 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7077 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7078 :
7079 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
7080 6 : .ToLocalChecked()
7081 6 : ->NewInstance(env.local())
7082 : .ToLocalChecked();
7083 30 : CHECK(
7084 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7085 :
7086 : Local<String> source = v8_str(
7087 : "undetectable.x = 42;"
7088 6 : "undetectable.x");
7089 :
7090 6 : Local<Script> script = v8_compile(source);
7091 :
7092 24 : CHECK(v8::Integer::New(isolate, 42)
7093 : ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7094 : .FromJust());
7095 :
7096 6 : ExpectBoolean("Object.isExtensible(undetectable)", true);
7097 :
7098 6 : source = v8_str("Object.preventExtensions(undetectable);");
7099 6 : script = v8_compile(source);
7100 6 : script->Run(env.local()).ToLocalChecked();
7101 6 : ExpectBoolean("Object.isExtensible(undetectable)", false);
7102 :
7103 6 : source = v8_str("undetectable.y = 2000;");
7104 6 : script = v8_compile(source);
7105 6 : script->Run(env.local()).ToLocalChecked();
7106 12 : ExpectBoolean("undetectable.y == undefined", true);
7107 6 : }
7108 :
7109 :
7110 : // The point of this test is type checking. We run it only so compilers
7111 : // don't complain about an unused function.
7112 23723 : TEST(PersistentHandles) {
7113 5 : LocalContext env;
7114 5 : v8::Isolate* isolate = CcTest::isolate();
7115 10 : v8::HandleScope scope(isolate);
7116 5 : Local<String> str = v8_str("foo");
7117 : v8::Persistent<String> p_str(isolate, str);
7118 : p_str.Reset();
7119 : Local<Script> scr = v8_compile("");
7120 : v8::Persistent<Script> p_scr(isolate, scr);
7121 : p_scr.Reset();
7122 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7123 : v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7124 5 : p_templ.Reset();
7125 5 : }
7126 :
7127 :
7128 6 : static void HandleLogDelegator(
7129 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7130 6 : ApiTestFuzzer::Fuzz();
7131 6 : }
7132 :
7133 :
7134 23724 : THREADED_TEST(GlobalObjectTemplate) {
7135 6 : v8::Isolate* isolate = CcTest::isolate();
7136 6 : v8::HandleScope handle_scope(isolate);
7137 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7138 : global_template->Set(v8_str("JSNI_Log"),
7139 18 : v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7140 6 : v8::Local<Context> context = Context::New(isolate, 0, global_template);
7141 : Context::Scope context_scope(context);
7142 6 : CompileRun("JSNI_Log('LOG')");
7143 6 : }
7144 :
7145 :
7146 : static const char* kSimpleExtensionSource =
7147 : "function Foo() {"
7148 : " return 4;"
7149 : "}";
7150 :
7151 :
7152 23723 : TEST(SimpleExtensions) {
7153 5 : v8::HandleScope handle_scope(CcTest::isolate());
7154 5 : v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7155 5 : const char* extension_names[] = {"simpletest"};
7156 : v8::ExtensionConfiguration extensions(1, extension_names);
7157 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7158 : Context::Scope lock(context);
7159 : v8::Local<Value> result = CompileRun("Foo()");
7160 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7161 5 : .FromJust());
7162 5 : }
7163 :
7164 :
7165 : static const char* kStackTraceFromExtensionSource =
7166 : "function foo() {"
7167 : " throw new Error();"
7168 : "}"
7169 : "function bar() {"
7170 : " foo();"
7171 : "}";
7172 :
7173 :
7174 23723 : TEST(StackTraceInExtension) {
7175 5 : v8::HandleScope handle_scope(CcTest::isolate());
7176 : v8::RegisterExtension(
7177 5 : new Extension("stacktracetest", kStackTraceFromExtensionSource));
7178 5 : const char* extension_names[] = {"stacktracetest"};
7179 : v8::ExtensionConfiguration extensions(1, extension_names);
7180 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7181 : Context::Scope lock(context);
7182 : CompileRun(
7183 : "function user() { bar(); }"
7184 : "var error;"
7185 : "try{ user(); } catch (e) { error = e; }");
7186 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7187 5 : CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7188 10 : CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7189 5 : }
7190 :
7191 :
7192 23723 : TEST(NullExtensions) {
7193 5 : v8::HandleScope handle_scope(CcTest::isolate());
7194 5 : v8::RegisterExtension(new Extension("nulltest", nullptr));
7195 5 : const char* extension_names[] = {"nulltest"};
7196 : v8::ExtensionConfiguration extensions(1, extension_names);
7197 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7198 : Context::Scope lock(context);
7199 : v8::Local<Value> result = CompileRun("1+3");
7200 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7201 5 : .FromJust());
7202 5 : }
7203 :
7204 : static const char* kEmbeddedExtensionSource =
7205 : "function Ret54321(){return 54321;}~~@@$"
7206 : "$%% THIS IS A SERIES OF NON-nullptr-TERMINATED STRINGS.";
7207 : static const int kEmbeddedExtensionSourceValidLen = 34;
7208 :
7209 :
7210 23723 : TEST(ExtensionMissingSourceLength) {
7211 5 : v8::HandleScope handle_scope(CcTest::isolate());
7212 : v8::RegisterExtension(
7213 5 : new Extension("srclentest_fail", kEmbeddedExtensionSource));
7214 5 : const char* extension_names[] = {"srclentest_fail"};
7215 : v8::ExtensionConfiguration extensions(1, extension_names);
7216 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7217 5 : CHECK_NULL(*context);
7218 5 : }
7219 :
7220 :
7221 23723 : TEST(ExtensionWithSourceLength) {
7222 20 : for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7223 : source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7224 15 : v8::HandleScope handle_scope(CcTest::isolate());
7225 : i::ScopedVector<char> extension_name(32);
7226 15 : i::SNPrintF(extension_name, "ext #%d", source_len);
7227 : v8::RegisterExtension(new Extension(
7228 15 : extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
7229 15 : const char* extension_names[1] = {extension_name.start()};
7230 : v8::ExtensionConfiguration extensions(1, extension_names);
7231 15 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7232 15 : if (source_len == kEmbeddedExtensionSourceValidLen) {
7233 : Context::Scope lock(context);
7234 5 : v8::Local<Value> result = CompileRun("Ret54321()");
7235 15 : CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7236 : ->Equals(context, result)
7237 : .FromJust());
7238 : } else {
7239 : // Anything but exactly the right length should fail to compile.
7240 10 : CHECK_NULL(*context);
7241 : }
7242 15 : }
7243 5 : }
7244 :
7245 :
7246 : static const char* kEvalExtensionSource1 =
7247 : "function UseEval1() {"
7248 : " var x = 42;"
7249 : " return eval('x');"
7250 : "}";
7251 :
7252 :
7253 : static const char* kEvalExtensionSource2 =
7254 : "(function() {"
7255 : " var x = 42;"
7256 : " function e() {"
7257 : " return eval('x');"
7258 : " }"
7259 : " this.UseEval2 = e;"
7260 : "})()";
7261 :
7262 :
7263 23723 : TEST(UseEvalFromExtension) {
7264 5 : v8::HandleScope handle_scope(CcTest::isolate());
7265 5 : v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7266 5 : v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7267 5 : const char* extension_names[] = {"evaltest1", "evaltest2"};
7268 : v8::ExtensionConfiguration extensions(2, extension_names);
7269 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7270 : Context::Scope lock(context);
7271 : v8::Local<Value> result = CompileRun("UseEval1()");
7272 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7273 : .FromJust());
7274 : result = CompileRun("UseEval2()");
7275 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7276 5 : .FromJust());
7277 5 : }
7278 :
7279 :
7280 : static const char* kWithExtensionSource1 =
7281 : "function UseWith1() {"
7282 : " var x = 42;"
7283 : " with({x:87}) { return x; }"
7284 : "}";
7285 :
7286 :
7287 : static const char* kWithExtensionSource2 =
7288 : "(function() {"
7289 : " var x = 42;"
7290 : " function e() {"
7291 : " with ({x:87}) { return x; }"
7292 : " }"
7293 : " this.UseWith2 = e;"
7294 : "})()";
7295 :
7296 :
7297 23723 : TEST(UseWithFromExtension) {
7298 5 : v8::HandleScope handle_scope(CcTest::isolate());
7299 5 : v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7300 5 : v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7301 5 : const char* extension_names[] = {"withtest1", "withtest2"};
7302 : v8::ExtensionConfiguration extensions(2, extension_names);
7303 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7304 : Context::Scope lock(context);
7305 : v8::Local<Value> result = CompileRun("UseWith1()");
7306 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7307 : .FromJust());
7308 : result = CompileRun("UseWith2()");
7309 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7310 5 : .FromJust());
7311 5 : }
7312 :
7313 :
7314 23723 : TEST(AutoExtensions) {
7315 5 : v8::HandleScope handle_scope(CcTest::isolate());
7316 5 : Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7317 : extension->set_auto_enable(true);
7318 5 : v8::RegisterExtension(extension);
7319 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
7320 : Context::Scope lock(context);
7321 : v8::Local<Value> result = CompileRun("Foo()");
7322 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7323 5 : .FromJust());
7324 5 : }
7325 :
7326 :
7327 : static const char* kSyntaxErrorInExtensionSource = "[";
7328 :
7329 :
7330 : // Test that a syntax error in an extension does not cause a fatal
7331 : // error but results in an empty context.
7332 23723 : TEST(SyntaxErrorExtensions) {
7333 5 : v8::HandleScope handle_scope(CcTest::isolate());
7334 : v8::RegisterExtension(
7335 5 : new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
7336 5 : const char* extension_names[] = {"syntaxerror"};
7337 : v8::ExtensionConfiguration extensions(1, extension_names);
7338 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7339 5 : CHECK(context.IsEmpty());
7340 5 : }
7341 :
7342 :
7343 : static const char* kExceptionInExtensionSource = "throw 42";
7344 :
7345 :
7346 : // Test that an exception when installing an extension does not cause
7347 : // a fatal error but results in an empty context.
7348 23723 : TEST(ExceptionExtensions) {
7349 5 : v8::HandleScope handle_scope(CcTest::isolate());
7350 : v8::RegisterExtension(
7351 5 : new Extension("exception", kExceptionInExtensionSource));
7352 5 : const char* extension_names[] = {"exception"};
7353 : v8::ExtensionConfiguration extensions(1, extension_names);
7354 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7355 5 : CHECK(context.IsEmpty());
7356 5 : }
7357 :
7358 : static const char* kNativeCallInExtensionSource =
7359 : "function call_runtime_last_index_of(x) {"
7360 : " return %StringLastIndexOf(x, 'bob');"
7361 : "}";
7362 :
7363 : static const char* kNativeCallTest =
7364 : "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7365 :
7366 : // Test that a native runtime calls are supported in extensions.
7367 23723 : TEST(NativeCallInExtensions) {
7368 5 : v8::HandleScope handle_scope(CcTest::isolate());
7369 : v8::RegisterExtension(
7370 5 : new Extension("nativecall", kNativeCallInExtensionSource));
7371 5 : const char* extension_names[] = {"nativecall"};
7372 : v8::ExtensionConfiguration extensions(1, extension_names);
7373 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7374 : Context::Scope lock(context);
7375 5 : v8::Local<Value> result = CompileRun(kNativeCallTest);
7376 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24))
7377 5 : .FromJust());
7378 5 : }
7379 :
7380 :
7381 0 : class NativeFunctionExtension : public Extension {
7382 : public:
7383 : NativeFunctionExtension(const char* name, const char* source,
7384 : v8::FunctionCallback fun = &Echo)
7385 15 : : Extension(name, source), function_(fun) {}
7386 :
7387 5 : virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7388 : v8::Isolate* isolate, v8::Local<v8::String> name) {
7389 5 : return v8::FunctionTemplate::New(isolate, function_);
7390 : }
7391 :
7392 10 : static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7393 5 : if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7394 5 : }
7395 :
7396 : private:
7397 : v8::FunctionCallback function_;
7398 : };
7399 :
7400 :
7401 23723 : TEST(NativeFunctionDeclaration) {
7402 5 : v8::HandleScope handle_scope(CcTest::isolate());
7403 : const char* name = "nativedecl";
7404 : v8::RegisterExtension(
7405 10 : new NativeFunctionExtension(name, "native function foo();"));
7406 5 : const char* extension_names[] = {name};
7407 : v8::ExtensionConfiguration extensions(1, extension_names);
7408 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7409 : Context::Scope lock(context);
7410 : v8::Local<Value> result = CompileRun("foo(42);");
7411 15 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7412 5 : .FromJust());
7413 5 : }
7414 :
7415 :
7416 23723 : TEST(NativeFunctionDeclarationError) {
7417 5 : v8::HandleScope handle_scope(CcTest::isolate());
7418 : const char* name = "nativedeclerr";
7419 : // Syntax error in extension code.
7420 : v8::RegisterExtension(
7421 10 : new NativeFunctionExtension(name, "native\nfunction foo();"));
7422 5 : const char* extension_names[] = {name};
7423 : v8::ExtensionConfiguration extensions(1, extension_names);
7424 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7425 5 : CHECK(context.IsEmpty());
7426 5 : }
7427 :
7428 :
7429 23723 : TEST(NativeFunctionDeclarationErrorEscape) {
7430 5 : v8::HandleScope handle_scope(CcTest::isolate());
7431 : const char* name = "nativedeclerresc";
7432 : // Syntax error in extension code - escape code in "native" means that
7433 : // it's not treated as a keyword.
7434 : v8::RegisterExtension(
7435 10 : new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
7436 5 : const char* extension_names[] = {name};
7437 : v8::ExtensionConfiguration extensions(1, extension_names);
7438 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7439 5 : CHECK(context.IsEmpty());
7440 5 : }
7441 :
7442 :
7443 30 : static void CheckDependencies(const char* name, const char* expected) {
7444 30 : v8::HandleScope handle_scope(CcTest::isolate());
7445 : v8::ExtensionConfiguration config(1, &name);
7446 60 : LocalContext context(&config);
7447 210 : CHECK(
7448 : v8_str(expected)
7449 : ->Equals(context.local(), context->Global()
7450 : ->Get(context.local(), v8_str("loaded"))
7451 : .ToLocalChecked())
7452 30 : .FromJust());
7453 30 : }
7454 :
7455 :
7456 : /*
7457 : * Configuration:
7458 : *
7459 : * /-- B <--\
7460 : * A <- -- D <-- E
7461 : * \-- C <--/
7462 : */
7463 23724 : THREADED_TEST(ExtensionDependency) {
7464 : static const char* kEDeps[] = {"D"};
7465 6 : v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7466 : static const char* kDDeps[] = {"B", "C"};
7467 6 : v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7468 : static const char* kBCDeps[] = {"A"};
7469 6 : v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7470 6 : v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7471 6 : v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7472 6 : CheckDependencies("A", "undefinedA");
7473 6 : CheckDependencies("B", "undefinedAB");
7474 6 : CheckDependencies("C", "undefinedAC");
7475 6 : CheckDependencies("D", "undefinedABCD");
7476 6 : CheckDependencies("E", "undefinedABCDE");
7477 6 : v8::HandleScope handle_scope(CcTest::isolate());
7478 : static const char* exts[2] = {"C", "E"};
7479 : v8::ExtensionConfiguration config(2, exts);
7480 12 : LocalContext context(&config);
7481 42 : CHECK(
7482 : v8_str("undefinedACBDE")
7483 : ->Equals(context.local(), context->Global()
7484 : ->Get(context.local(), v8_str("loaded"))
7485 : .ToLocalChecked())
7486 6 : .FromJust());
7487 6 : }
7488 :
7489 :
7490 : static const char* kExtensionTestScript =
7491 : "native function A();"
7492 : "native function B();"
7493 : "native function C();"
7494 : "function Foo(i) {"
7495 : " if (i == 0) return A();"
7496 : " if (i == 1) return B();"
7497 : " if (i == 2) return C();"
7498 : "}";
7499 :
7500 :
7501 738 : static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7502 198 : ApiTestFuzzer::Fuzz();
7503 198 : if (args.IsConstructCall()) {
7504 720 : CHECK(args.This()
7505 : ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7506 : args.Data())
7507 : .FromJust());
7508 : args.GetReturnValue().SetNull();
7509 378 : return;
7510 : }
7511 : args.GetReturnValue().Set(args.Data());
7512 : }
7513 :
7514 :
7515 0 : class FunctionExtension : public Extension {
7516 : public:
7517 12 : FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7518 : virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7519 : v8::Isolate* isolate, v8::Local<String> name);
7520 : };
7521 :
7522 :
7523 : static int lookup_count = 0;
7524 33 : v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7525 : v8::Isolate* isolate, v8::Local<String> name) {
7526 33 : lookup_count++;
7527 99 : if (name->Equals(isolate->GetCurrentContext(), v8_str("A")).FromJust()) {
7528 : return v8::FunctionTemplate::New(isolate, CallFun,
7529 22 : v8::Integer::New(isolate, 8));
7530 66 : } else if (name->Equals(isolate->GetCurrentContext(), v8_str("B"))
7531 44 : .FromJust()) {
7532 : return v8::FunctionTemplate::New(isolate, CallFun,
7533 22 : v8::Integer::New(isolate, 7));
7534 33 : } else if (name->Equals(isolate->GetCurrentContext(), v8_str("C"))
7535 22 : .FromJust()) {
7536 : return v8::FunctionTemplate::New(isolate, CallFun,
7537 22 : v8::Integer::New(isolate, 6));
7538 : } else {
7539 0 : return v8::Local<v8::FunctionTemplate>();
7540 : }
7541 : }
7542 :
7543 :
7544 23724 : THREADED_TEST(FunctionLookup) {
7545 6 : v8::RegisterExtension(new FunctionExtension());
7546 6 : v8::HandleScope handle_scope(CcTest::isolate());
7547 : static const char* exts[1] = {"functiontest"};
7548 : v8::ExtensionConfiguration config(1, exts);
7549 12 : LocalContext context(&config);
7550 6 : CHECK_EQ(3, lookup_count);
7551 18 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7552 : ->Equals(context.local(), CompileRun("Foo(0)"))
7553 : .FromJust());
7554 18 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7555 : ->Equals(context.local(), CompileRun("Foo(1)"))
7556 : .FromJust());
7557 18 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7558 : ->Equals(context.local(), CompileRun("Foo(2)"))
7559 6 : .FromJust());
7560 6 : }
7561 :
7562 :
7563 23724 : THREADED_TEST(NativeFunctionConstructCall) {
7564 6 : v8::RegisterExtension(new FunctionExtension());
7565 6 : v8::HandleScope handle_scope(CcTest::isolate());
7566 : static const char* exts[1] = {"functiontest"};
7567 : v8::ExtensionConfiguration config(1, exts);
7568 12 : LocalContext context(&config);
7569 66 : for (int i = 0; i < 10; i++) {
7570 : // Run a few times to ensure that allocation of objects doesn't
7571 : // change behavior of a constructor function.
7572 180 : CHECK(v8::Integer::New(CcTest::isolate(), 8)
7573 : ->Equals(context.local(), CompileRun("(new A()).data"))
7574 : .FromJust());
7575 180 : CHECK(v8::Integer::New(CcTest::isolate(), 7)
7576 : ->Equals(context.local(), CompileRun("(new B()).data"))
7577 : .FromJust());
7578 180 : CHECK(v8::Integer::New(CcTest::isolate(), 6)
7579 : ->Equals(context.local(), CompileRun("(new C()).data"))
7580 : .FromJust());
7581 6 : }
7582 6 : }
7583 :
7584 :
7585 : static const char* last_location;
7586 : static const char* last_message;
7587 10 : void StoringErrorCallback(const char* location, const char* message) {
7588 10 : if (last_location == nullptr) {
7589 10 : last_location = location;
7590 10 : last_message = message;
7591 : }
7592 10 : }
7593 :
7594 :
7595 : // ErrorReporting creates a circular extensions configuration and
7596 : // tests that the fatal error handler gets called. This renders V8
7597 : // unusable and therefore this test cannot be run in parallel.
7598 23723 : TEST(ErrorReporting) {
7599 5 : CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7600 : static const char* aDeps[] = {"B"};
7601 5 : v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7602 : static const char* bDeps[] = {"A"};
7603 5 : v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7604 5 : last_location = nullptr;
7605 : v8::ExtensionConfiguration config(1, bDeps);
7606 5 : v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7607 5 : CHECK(context.IsEmpty());
7608 5 : CHECK(last_location);
7609 5 : }
7610 :
7611 : static size_t dcheck_count;
7612 0 : void DcheckErrorCallback(const char* file, int line, const char* message) {
7613 0 : last_message = message;
7614 0 : ++dcheck_count;
7615 0 : }
7616 :
7617 23723 : TEST(DcheckErrorHandler) {
7618 5 : V8::SetDcheckErrorHandler(DcheckErrorCallback);
7619 :
7620 5 : last_message = nullptr;
7621 5 : dcheck_count = 0;
7622 :
7623 : DCHECK(false && "w00t");
7624 : #ifdef DEBUG
7625 : CHECK_EQ(dcheck_count, 1);
7626 : CHECK(last_message);
7627 : CHECK(std::string(last_message).find("w00t") != std::string::npos);
7628 : #else
7629 : // The DCHECK should be a noop in non-DEBUG builds.
7630 5 : CHECK_EQ(dcheck_count, 0);
7631 : #endif
7632 5 : }
7633 :
7634 6 : static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7635 : v8::Local<Value> data) {
7636 6 : v8::Isolate* isolate = CcTest::isolate();
7637 6 : Local<Context> context = isolate->GetCurrentContext();
7638 12 : CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7639 18 : CHECK(v8::Undefined(isolate)
7640 : ->Equals(context, message->GetScriptOrigin().ResourceName())
7641 : .FromJust());
7642 12 : message->GetLineNumber(context).FromJust();
7643 6 : message->GetSourceLine(context).ToLocalChecked();
7644 6 : }
7645 :
7646 :
7647 23724 : THREADED_TEST(ErrorWithMissingScriptInfo) {
7648 6 : LocalContext context;
7649 12 : v8::HandleScope scope(context->GetIsolate());
7650 6 : context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7651 : CompileRun("throw Error()");
7652 : context->GetIsolate()->RemoveMessageListeners(
7653 12 : MissingScriptInfoMessageListener);
7654 6 : }
7655 :
7656 :
7657 : struct FlagAndPersistent {
7658 : bool flag;
7659 : v8::Global<v8::Object> handle;
7660 : };
7661 :
7662 :
7663 80 : static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7664 40 : data.GetParameter()->flag = true;
7665 : data.GetParameter()->handle.Reset();
7666 40 : }
7667 :
7668 :
7669 20 : static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7670 20 : i::FLAG_stress_incremental_marking = false;
7671 : // Parallel scavenge introduces too much fragmentation.
7672 20 : i::FLAG_parallel_scavenge = false;
7673 20 : v8::Isolate* iso = CcTest::isolate();
7674 20 : v8::HandleScope scope(iso);
7675 20 : v8::Local<Context> context = Context::New(iso);
7676 : Context::Scope context_scope(context);
7677 :
7678 : FlagAndPersistent object_a, object_b;
7679 :
7680 : size_t big_heap_size = 0;
7681 : size_t big_array_size = 0;
7682 :
7683 : {
7684 20 : v8::HandleScope handle_scope(iso);
7685 20 : Local<Object> a(v8::Object::New(iso));
7686 20 : Local<Object> b(v8::Object::New(iso));
7687 : object_a.handle.Reset(iso, a);
7688 : object_b.handle.Reset(iso, b);
7689 20 : if (interlinked) {
7690 30 : a->Set(context, v8_str("x"), b).FromJust();
7691 30 : b->Set(context, v8_str("x"), a).FromJust();
7692 : }
7693 20 : if (global_gc) {
7694 10 : CcTest::CollectAllGarbage();
7695 : } else {
7696 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7697 : }
7698 20 : v8::Local<Value> big_array = v8::Array::New(CcTest::isolate(), 5000);
7699 : // Verify that we created an array where the space was reserved up front.
7700 : big_array_size =
7701 : v8::internal::JSArray::cast(*v8::Utils::OpenHandle(*big_array))
7702 : ->elements()
7703 20 : ->Size();
7704 20 : CHECK_LE(20000, big_array_size);
7705 60 : a->Set(context, v8_str("y"), big_array).FromJust();
7706 20 : big_heap_size = CcTest::heap()->SizeOfObjects();
7707 : }
7708 :
7709 20 : object_a.flag = false;
7710 20 : object_b.flag = false;
7711 : object_a.handle.SetWeak(&object_a, &SetFlag,
7712 : v8::WeakCallbackType::kParameter);
7713 : object_b.handle.SetWeak(&object_b, &SetFlag,
7714 : v8::WeakCallbackType::kParameter);
7715 20 : CHECK(!object_b.handle.IsIndependent());
7716 : object_a.handle.MarkIndependent();
7717 : object_b.handle.MarkIndependent();
7718 20 : CHECK(object_b.handle.IsIndependent());
7719 20 : if (global_gc) {
7720 10 : CcTest::CollectAllGarbage();
7721 : } else {
7722 10 : CcTest::CollectGarbage(i::NEW_SPACE);
7723 : }
7724 : // A single GC should be enough to reclaim the memory, since we are using
7725 : // phantom handles.
7726 20 : CHECK_GT(big_heap_size - big_array_size, CcTest::heap()->SizeOfObjects());
7727 20 : CHECK(object_a.flag);
7728 40 : CHECK(object_b.flag);
7729 20 : }
7730 :
7731 :
7732 23723 : TEST(IndependentWeakHandle) {
7733 5 : IndependentWeakHandle(false, false);
7734 5 : IndependentWeakHandle(false, true);
7735 5 : IndependentWeakHandle(true, false);
7736 5 : IndependentWeakHandle(true, true);
7737 5 : }
7738 :
7739 :
7740 : class Trivial {
7741 : public:
7742 12 : explicit Trivial(int x) : x_(x) {}
7743 :
7744 36 : int x() { return x_; }
7745 12 : void set_x(int x) { x_ = x; }
7746 :
7747 : private:
7748 : int x_;
7749 : };
7750 :
7751 :
7752 : class Trivial2 {
7753 : public:
7754 12 : Trivial2(int x, int y) : y_(y), x_(x) {}
7755 :
7756 : int x() { return x_; }
7757 12 : void set_x(int x) { x_ = x; }
7758 :
7759 : int y() { return y_; }
7760 : void set_y(int y) { y_ = y; }
7761 :
7762 : private:
7763 : int y_;
7764 : int x_;
7765 : };
7766 :
7767 12 : void CheckInternalFields(
7768 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
7769 : v8::Persistent<v8::Object>* handle = data.GetParameter();
7770 : handle->Reset();
7771 : Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
7772 12 : Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
7773 12 : CHECK_EQ(42, t1->x());
7774 12 : CHECK_EQ(103, t2->x());
7775 : t1->set_x(1729);
7776 : t2->set_x(33550336);
7777 12 : }
7778 :
7779 12 : void InternalFieldCallback(bool global_gc) {
7780 12 : LocalContext env;
7781 12 : v8::Isolate* isolate = env->GetIsolate();
7782 24 : v8::HandleScope scope(isolate);
7783 :
7784 12 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
7785 12 : Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
7786 : Trivial* t1;
7787 24 : Trivial2* t2;
7788 12 : instance_templ->SetInternalFieldCount(2);
7789 : v8::Persistent<v8::Object> handle;
7790 : {
7791 12 : v8::HandleScope scope(isolate);
7792 12 : Local<v8::Object> obj = templ->GetFunction(env.local())
7793 12 : .ToLocalChecked()
7794 12 : ->NewInstance(env.local())
7795 : .ToLocalChecked();
7796 : handle.Reset(isolate, obj);
7797 12 : CHECK_EQ(2, obj->InternalFieldCount());
7798 12 : CHECK(obj->GetInternalField(0)->IsUndefined());
7799 12 : t1 = new Trivial(42);
7800 12 : t2 = new Trivial2(103, 9);
7801 :
7802 12 : obj->SetAlignedPointerInInternalField(0, t1);
7803 : t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
7804 12 : CHECK_EQ(42, t1->x());
7805 :
7806 12 : obj->SetAlignedPointerInInternalField(1, t2);
7807 : t2 =
7808 : reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
7809 12 : CHECK_EQ(103, t2->x());
7810 :
7811 : handle.SetWeak<v8::Persistent<v8::Object>>(
7812 : &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
7813 12 : if (!global_gc) {
7814 : handle.MarkIndependent();
7815 12 : }
7816 : }
7817 12 : if (global_gc) {
7818 6 : CcTest::CollectAllGarbage();
7819 : } else {
7820 6 : CcTest::CollectGarbage(i::NEW_SPACE);
7821 : }
7822 :
7823 12 : CHECK_EQ(1729, t1->x());
7824 12 : CHECK_EQ(33550336, t2->x());
7825 :
7826 12 : delete t1;
7827 24 : delete t2;
7828 12 : }
7829 :
7830 23724 : THREADED_TEST(InternalFieldCallback) {
7831 6 : InternalFieldCallback(false);
7832 6 : InternalFieldCallback(true);
7833 6 : }
7834 :
7835 :
7836 24 : static void ResetUseValueAndSetFlag(
7837 48 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7838 : // Blink will reset the handle, and then use the other handle, so they
7839 : // can't use the same backing slot.
7840 : data.GetParameter()->handle.Reset();
7841 24 : data.GetParameter()->flag = true;
7842 24 : }
7843 :
7844 12 : void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) {
7845 : using v8::Context;
7846 : using v8::Local;
7847 : using v8::Object;
7848 :
7849 12 : v8::Isolate* iso = CcTest::isolate();
7850 12 : v8::HandleScope scope(iso);
7851 12 : v8::Local<Context> context = Context::New(iso);
7852 : Context::Scope context_scope(context);
7853 :
7854 : FlagAndPersistent object_a, object_b;
7855 :
7856 : {
7857 12 : v8::HandleScope handle_scope(iso);
7858 12 : Local<Object> a(v8::Object::New(iso));
7859 12 : Local<Object> b(v8::Object::New(iso));
7860 : object_a.handle.Reset(iso, a);
7861 : object_b.handle.Reset(iso, b);
7862 12 : if (global_gc) {
7863 6 : CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
7864 : } else {
7865 6 : CcTest::CollectGarbage(i::NEW_SPACE);
7866 12 : }
7867 : }
7868 :
7869 12 : object_a.flag = false;
7870 12 : object_b.flag = false;
7871 : object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
7872 : v8::WeakCallbackType::kParameter);
7873 : object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
7874 : v8::WeakCallbackType::kParameter);
7875 12 : if (!global_gc) {
7876 : object_a.handle.MarkIndependent();
7877 : object_b.handle.MarkIndependent();
7878 6 : CHECK(object_b.handle.IsIndependent());
7879 : }
7880 12 : if (global_gc) {
7881 6 : CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
7882 : } else {
7883 6 : CcTest::CollectGarbage(i::NEW_SPACE);
7884 : }
7885 12 : CHECK(object_a.flag);
7886 24 : CHECK(object_b.flag);
7887 12 : }
7888 :
7889 :
7890 23724 : THREADED_HEAP_TEST(ResetWeakHandle) {
7891 6 : v8::internal::heap::HeapTester::ResetWeakHandle(false);
7892 6 : v8::internal::heap::HeapTester::ResetWeakHandle(true);
7893 6 : }
7894 :
7895 24 : static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
7896 :
7897 24 : static void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
7898 :
7899 12 : static void ForceScavenge2(
7900 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7901 12 : data.GetParameter()->flag = true;
7902 : InvokeScavenge();
7903 12 : }
7904 :
7905 12 : static void ForceScavenge1(
7906 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7907 : data.GetParameter()->handle.Reset();
7908 : data.SetSecondPassCallback(ForceScavenge2);
7909 12 : }
7910 :
7911 :
7912 12 : static void ForceMarkSweep2(
7913 12 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7914 12 : data.GetParameter()->flag = true;
7915 : InvokeMarkSweep();
7916 12 : }
7917 :
7918 12 : static void ForceMarkSweep1(
7919 24 : const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7920 : data.GetParameter()->handle.Reset();
7921 : data.SetSecondPassCallback(ForceMarkSweep2);
7922 12 : }
7923 :
7924 :
7925 23724 : THREADED_TEST(GCFromWeakCallbacks) {
7926 6 : v8::Isolate* isolate = CcTest::isolate();
7927 6 : v8::Locker locker(CcTest::isolate());
7928 12 : v8::HandleScope scope(isolate);
7929 6 : v8::Local<Context> context = Context::New(isolate);
7930 : Context::Scope context_scope(context);
7931 :
7932 : static const int kNumberOfGCTypes = 2;
7933 : typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
7934 : Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
7935 6 : &ForceMarkSweep1};
7936 :
7937 : typedef void (*GCInvoker)();
7938 6 : GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7939 :
7940 18 : for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7941 24 : for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7942 : FlagAndPersistent object;
7943 : {
7944 24 : v8::HandleScope handle_scope(isolate);
7945 48 : object.handle.Reset(isolate, v8::Object::New(isolate));
7946 : }
7947 24 : object.flag = false;
7948 : object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
7949 24 : v8::WeakCallbackType::kParameter);
7950 : object.handle.MarkIndependent();
7951 24 : invoke_gc[outer_gc]();
7952 24 : EmptyMessageQueues(isolate);
7953 24 : CHECK(object.flag);
7954 : }
7955 6 : }
7956 6 : }
7957 :
7958 :
7959 : v8::Local<Function> args_fun;
7960 :
7961 :
7962 6 : static void ArgumentsTestCallback(
7963 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
7964 6 : ApiTestFuzzer::Fuzz();
7965 : v8::Isolate* isolate = args.GetIsolate();
7966 6 : Local<Context> context = isolate->GetCurrentContext();
7967 6 : CHECK_EQ(3, args.Length());
7968 18 : CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
7969 18 : CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
7970 18 : CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
7971 12 : CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
7972 6 : v8::HandleScope scope(args.GetIsolate());
7973 6 : CcTest::CollectAllGarbage();
7974 6 : }
7975 :
7976 :
7977 23724 : THREADED_TEST(Arguments) {
7978 6 : v8::Isolate* isolate = CcTest::isolate();
7979 6 : v8::HandleScope scope(isolate);
7980 6 : v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7981 : global->Set(v8_str("f"),
7982 18 : v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7983 12 : LocalContext context(nullptr, global);
7984 : args_fun = context->Global()
7985 24 : ->Get(context.local(), v8_str("f"))
7986 6 : .ToLocalChecked()
7987 6 : .As<Function>();
7988 18 : v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
7989 6 : }
7990 :
7991 :
7992 : static int p_getter_count;
7993 : static int p_getter_count2;
7994 :
7995 :
7996 240 : static void PGetter(Local<Name> name,
7997 : const v8::PropertyCallbackInfo<v8::Value>& info) {
7998 240 : ApiTestFuzzer::Fuzz();
7999 240 : p_getter_count++;
8000 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8001 240 : v8::Local<v8::Object> global = context->Global();
8002 960 : CHECK(
8003 : info.Holder()
8004 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8005 : .FromJust());
8006 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8007 240 : CHECK(info.This()
8008 : ->Equals(context,
8009 : global->Get(context, v8_str("o1")).ToLocalChecked())
8010 : .FromJust());
8011 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8012 240 : CHECK(info.This()
8013 : ->Equals(context,
8014 : global->Get(context, v8_str("o2")).ToLocalChecked())
8015 : .FromJust());
8016 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8017 240 : CHECK(info.This()
8018 : ->Equals(context,
8019 : global->Get(context, v8_str("o3")).ToLocalChecked())
8020 : .FromJust());
8021 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8022 240 : CHECK(info.This()
8023 : ->Equals(context,
8024 : global->Get(context, v8_str("o4")).ToLocalChecked())
8025 : .FromJust());
8026 : }
8027 240 : }
8028 :
8029 :
8030 12 : static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8031 12 : ApiTestFuzzer::Fuzz();
8032 12 : LocalContext context;
8033 84 : CHECK(context->Global()
8034 : ->Set(context.local(), v8_str("o1"),
8035 : obj->NewInstance(context.local()).ToLocalChecked())
8036 : .FromJust());
8037 : CompileRun(
8038 : "o1.__proto__ = { };"
8039 : "var o2 = { __proto__: o1 };"
8040 : "var o3 = { __proto__: o2 };"
8041 : "var o4 = { __proto__: o3 };"
8042 : "for (var i = 0; i < 10; i++) o4.p4;"
8043 : "for (var i = 0; i < 10; i++) o3.p3;"
8044 : "for (var i = 0; i < 10; i++) o2.p2;"
8045 12 : "for (var i = 0; i < 10; i++) o1.p1;");
8046 12 : }
8047 :
8048 :
8049 240 : static void PGetter2(Local<Name> name,
8050 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8051 240 : ApiTestFuzzer::Fuzz();
8052 240 : p_getter_count2++;
8053 240 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8054 240 : v8::Local<v8::Object> global = context->Global();
8055 960 : CHECK(
8056 : info.Holder()
8057 : ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8058 : .FromJust());
8059 720 : if (name->Equals(context, v8_str("p1")).FromJust()) {
8060 240 : CHECK(info.This()
8061 : ->Equals(context,
8062 : global->Get(context, v8_str("o1")).ToLocalChecked())
8063 : .FromJust());
8064 540 : } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8065 240 : CHECK(info.This()
8066 : ->Equals(context,
8067 : global->Get(context, v8_str("o2")).ToLocalChecked())
8068 : .FromJust());
8069 360 : } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8070 240 : CHECK(info.This()
8071 : ->Equals(context,
8072 : global->Get(context, v8_str("o3")).ToLocalChecked())
8073 : .FromJust());
8074 180 : } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8075 240 : CHECK(info.This()
8076 : ->Equals(context,
8077 : global->Get(context, v8_str("o4")).ToLocalChecked())
8078 : .FromJust());
8079 : }
8080 240 : }
8081 :
8082 :
8083 23724 : THREADED_TEST(GetterHolders) {
8084 6 : v8::Isolate* isolate = CcTest::isolate();
8085 6 : v8::HandleScope scope(isolate);
8086 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8087 12 : obj->SetAccessor(v8_str("p1"), PGetter);
8088 12 : obj->SetAccessor(v8_str("p2"), PGetter);
8089 12 : obj->SetAccessor(v8_str("p3"), PGetter);
8090 12 : obj->SetAccessor(v8_str("p4"), PGetter);
8091 6 : p_getter_count = 0;
8092 6 : RunHolderTest(obj);
8093 6 : CHECK_EQ(40, p_getter_count);
8094 6 : }
8095 :
8096 :
8097 23724 : THREADED_TEST(PreInterceptorHolders) {
8098 6 : v8::Isolate* isolate = CcTest::isolate();
8099 6 : v8::HandleScope scope(isolate);
8100 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8101 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8102 6 : p_getter_count2 = 0;
8103 6 : RunHolderTest(obj);
8104 6 : CHECK_EQ(40, p_getter_count2);
8105 6 : }
8106 :
8107 :
8108 23724 : THREADED_TEST(ObjectInstantiation) {
8109 6 : v8::Isolate* isolate = CcTest::isolate();
8110 6 : v8::HandleScope scope(isolate);
8111 6 : v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8112 12 : templ->SetAccessor(v8_str("t"), PGetter2);
8113 12 : LocalContext context;
8114 36 : CHECK(context->Global()
8115 : ->Set(context.local(), v8_str("o"),
8116 : templ->NewInstance(context.local()).ToLocalChecked())
8117 : .FromJust());
8118 600 : for (int i = 0; i < 100; i++) {
8119 600 : v8::HandleScope inner_scope(CcTest::isolate());
8120 : v8::Local<v8::Object> obj =
8121 600 : templ->NewInstance(context.local()).ToLocalChecked();
8122 3600 : CHECK(!obj->Equals(context.local(), context->Global()
8123 : ->Get(context.local(), v8_str("o"))
8124 : .ToLocalChecked())
8125 : .FromJust());
8126 3000 : CHECK(
8127 : context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8128 600 : v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8129 1800 : CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8130 3000 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8131 606 : }
8132 6 : }
8133 :
8134 :
8135 : static int StrCmp16(uint16_t* a, uint16_t* b) {
8136 : while (true) {
8137 168 : if (*a == 0 && *b == 0) return 0;
8138 138 : if (*a != *b) return 0 + *a - *b;
8139 132 : a++;
8140 132 : b++;
8141 : }
8142 : }
8143 :
8144 :
8145 : static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8146 : while (true) {
8147 150 : if (n-- == 0) return 0;
8148 120 : if (*a == 0 && *b == 0) return 0;
8149 120 : if (*a != *b) return 0 + *a - *b;
8150 120 : a++;
8151 120 : b++;
8152 : }
8153 : }
8154 :
8155 :
8156 552 : int GetUtf8Length(Local<String> str) {
8157 552 : int len = str->Utf8Length();
8158 552 : if (len < 0) {
8159 0 : i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8160 0 : i::String::Flatten(istr);
8161 0 : len = str->Utf8Length();
8162 : }
8163 552 : return len;
8164 : }
8165 :
8166 :
8167 23724 : THREADED_TEST(StringWrite) {
8168 6 : LocalContext context;
8169 12 : v8::HandleScope scope(context->GetIsolate());
8170 6 : v8::Local<String> str = v8_str("abcde");
8171 : // abc<Icelandic eth><Unicode snowman>.
8172 6 : v8::Local<String> str2 = v8_str("abc\303\260\342\230\203");
8173 : v8::Local<String> str3 =
8174 : v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8175 6 : v8::NewStringType::kNormal, 7)
8176 6 : .ToLocalChecked();
8177 : // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8178 6 : uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8179 : v8::Local<String> orphans_str =
8180 : v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8181 6 : v8::NewStringType::kNormal, 8)
8182 6 : .ToLocalChecked();
8183 : // single lead surrogate
8184 6 : uint16_t lead[1] = { 0xd800 };
8185 : v8::Local<String> lead_str =
8186 : v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8187 6 : v8::NewStringType::kNormal, 1)
8188 6 : .ToLocalChecked();
8189 : // single trail surrogate
8190 6 : uint16_t trail[1] = { 0xdc00 };
8191 : v8::Local<String> trail_str =
8192 : v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8193 6 : v8::NewStringType::kNormal, 1)
8194 6 : .ToLocalChecked();
8195 : // surrogate pair
8196 6 : uint16_t pair[2] = { 0xd800, 0xdc00 };
8197 : v8::Local<String> pair_str =
8198 : v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8199 6 : v8::NewStringType::kNormal, 2)
8200 6 : .ToLocalChecked();
8201 : const int kStride = 4; // Must match stride in for loops in JS below.
8202 : CompileRun(
8203 : "var left = '';"
8204 : "for (var i = 0; i < 0xd800; i += 4) {"
8205 : " left = left + String.fromCharCode(i);"
8206 : "}");
8207 : CompileRun(
8208 : "var right = '';"
8209 : "for (var i = 0; i < 0xd800; i += 4) {"
8210 : " right = String.fromCharCode(i) + right;"
8211 : "}");
8212 6 : v8::Local<v8::Object> global = context->Global();
8213 18 : Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8214 6 : .ToLocalChecked()
8215 : .As<String>();
8216 18 : Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8217 6 : .ToLocalChecked()
8218 : .As<String>();
8219 :
8220 6 : CHECK_EQ(5, str2->Length());
8221 6 : CHECK_EQ(0xd800 / kStride, left_tree->Length());
8222 6 : CHECK_EQ(0xd800 / kStride, right_tree->Length());
8223 :
8224 : char buf[100];
8225 : char utf8buf[0xd800 * 3];
8226 : uint16_t wbuf[100];
8227 : int len;
8228 : int charlen;
8229 :
8230 : memset(utf8buf, 0x1, 1000);
8231 6 : len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8232 6 : CHECK_EQ(9, len);
8233 6 : CHECK_EQ(5, charlen);
8234 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8235 :
8236 : memset(utf8buf, 0x1, 1000);
8237 6 : len = str2->WriteUtf8(utf8buf, 8, &charlen);
8238 6 : CHECK_EQ(8, len);
8239 6 : CHECK_EQ(5, charlen);
8240 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8241 :
8242 : memset(utf8buf, 0x1, 1000);
8243 6 : len = str2->WriteUtf8(utf8buf, 7, &charlen);
8244 6 : CHECK_EQ(5, len);
8245 6 : CHECK_EQ(4, charlen);
8246 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8247 :
8248 : memset(utf8buf, 0x1, 1000);
8249 6 : len = str2->WriteUtf8(utf8buf, 6, &charlen);
8250 6 : CHECK_EQ(5, len);
8251 6 : CHECK_EQ(4, charlen);
8252 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8253 :
8254 : memset(utf8buf, 0x1, 1000);
8255 6 : len = str2->WriteUtf8(utf8buf, 5, &charlen);
8256 6 : CHECK_EQ(5, len);
8257 6 : CHECK_EQ(4, charlen);
8258 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8259 :
8260 : memset(utf8buf, 0x1, 1000);
8261 6 : len = str2->WriteUtf8(utf8buf, 4, &charlen);
8262 6 : CHECK_EQ(3, len);
8263 6 : CHECK_EQ(3, charlen);
8264 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8265 :
8266 : memset(utf8buf, 0x1, 1000);
8267 6 : len = str2->WriteUtf8(utf8buf, 3, &charlen);
8268 6 : CHECK_EQ(3, len);
8269 6 : CHECK_EQ(3, charlen);
8270 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8271 :
8272 : memset(utf8buf, 0x1, 1000);
8273 6 : len = str2->WriteUtf8(utf8buf, 2, &charlen);
8274 6 : CHECK_EQ(2, len);
8275 6 : CHECK_EQ(2, charlen);
8276 6 : CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8277 :
8278 : // allow orphan surrogates by default
8279 : memset(utf8buf, 0x1, 1000);
8280 6 : len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8281 6 : CHECK_EQ(13, len);
8282 6 : CHECK_EQ(8, charlen);
8283 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8284 :
8285 : // replace orphan surrogates with unicode replacement character
8286 : memset(utf8buf, 0x1, 1000);
8287 : len = orphans_str->WriteUtf8(utf8buf,
8288 : sizeof(utf8buf),
8289 : &charlen,
8290 6 : String::REPLACE_INVALID_UTF8);
8291 6 : CHECK_EQ(13, len);
8292 6 : CHECK_EQ(8, charlen);
8293 6 : CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8294 :
8295 : // replace single lead surrogate with unicode replacement character
8296 : memset(utf8buf, 0x1, 1000);
8297 : len = lead_str->WriteUtf8(utf8buf,
8298 : sizeof(utf8buf),
8299 : &charlen,
8300 6 : String::REPLACE_INVALID_UTF8);
8301 6 : CHECK_EQ(4, len);
8302 6 : CHECK_EQ(1, charlen);
8303 6 : CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8304 :
8305 : // replace single trail surrogate with unicode replacement character
8306 : memset(utf8buf, 0x1, 1000);
8307 : len = trail_str->WriteUtf8(utf8buf,
8308 : sizeof(utf8buf),
8309 : &charlen,
8310 6 : String::REPLACE_INVALID_UTF8);
8311 6 : CHECK_EQ(4, len);
8312 6 : CHECK_EQ(1, charlen);
8313 6 : CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8314 :
8315 : // do not replace / write anything if surrogate pair does not fit the buffer
8316 : // space
8317 : memset(utf8buf, 0x1, 1000);
8318 : len = pair_str->WriteUtf8(utf8buf,
8319 : 3,
8320 : &charlen,
8321 6 : String::REPLACE_INVALID_UTF8);
8322 6 : CHECK_EQ(0, len);
8323 6 : CHECK_EQ(0, charlen);
8324 :
8325 : memset(utf8buf, 0x1, sizeof(utf8buf));
8326 6 : len = GetUtf8Length(left_tree);
8327 : int utf8_expected =
8328 : (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8329 6 : CHECK_EQ(utf8_expected, len);
8330 6 : len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8331 6 : CHECK_EQ(utf8_expected, len);
8332 6 : CHECK_EQ(0xd800 / kStride, charlen);
8333 12 : CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8334 12 : CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8335 12 : CHECK_EQ(0xc0 - kStride,
8336 : static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8337 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8338 :
8339 : memset(utf8buf, 0x1, sizeof(utf8buf));
8340 6 : len = GetUtf8Length(right_tree);
8341 6 : CHECK_EQ(utf8_expected, len);
8342 6 : len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8343 6 : CHECK_EQ(utf8_expected, len);
8344 6 : CHECK_EQ(0xd800 / kStride, charlen);
8345 12 : CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8346 12 : CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8347 12 : CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8348 6 : CHECK_EQ(1, utf8buf[utf8_expected]);
8349 :
8350 : memset(buf, 0x1, sizeof(buf));
8351 : memset(wbuf, 0x1, sizeof(wbuf));
8352 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8353 6 : CHECK_EQ(5, len);
8354 6 : len = str->Write(wbuf);
8355 6 : CHECK_EQ(5, len);
8356 6 : CHECK_EQ(0, strcmp("abcde", buf));
8357 6 : uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8358 6 : CHECK_EQ(0, StrCmp16(answer1, wbuf));
8359 :
8360 : memset(buf, 0x1, sizeof(buf));
8361 : memset(wbuf, 0x1, sizeof(wbuf));
8362 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8363 6 : CHECK_EQ(4, len);
8364 6 : len = str->Write(wbuf, 0, 4);
8365 6 : CHECK_EQ(4, len);
8366 6 : CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8367 6 : uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8368 6 : CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8369 :
8370 : memset(buf, 0x1, sizeof(buf));
8371 : memset(wbuf, 0x1, sizeof(wbuf));
8372 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8373 6 : CHECK_EQ(5, len);
8374 6 : len = str->Write(wbuf, 0, 5);
8375 6 : CHECK_EQ(5, len);
8376 6 : CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8377 6 : uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8378 6 : CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8379 :
8380 : memset(buf, 0x1, sizeof(buf));
8381 : memset(wbuf, 0x1, sizeof(wbuf));
8382 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8383 6 : CHECK_EQ(5, len);
8384 6 : len = str->Write(wbuf, 0, 6);
8385 6 : CHECK_EQ(5, len);
8386 6 : CHECK_EQ(0, strcmp("abcde", buf));
8387 6 : uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8388 6 : CHECK_EQ(0, StrCmp16(answer4, wbuf));
8389 :
8390 : memset(buf, 0x1, sizeof(buf));
8391 : memset(wbuf, 0x1, sizeof(wbuf));
8392 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8393 6 : CHECK_EQ(1, len);
8394 6 : len = str->Write(wbuf, 4, -1);
8395 6 : CHECK_EQ(1, len);
8396 6 : CHECK_EQ(0, strcmp("e", buf));
8397 6 : uint16_t answer5[] = {'e', '\0'};
8398 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8399 :
8400 : memset(buf, 0x1, sizeof(buf));
8401 : memset(wbuf, 0x1, sizeof(wbuf));
8402 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8403 6 : CHECK_EQ(1, len);
8404 6 : len = str->Write(wbuf, 4, 6);
8405 6 : CHECK_EQ(1, len);
8406 6 : CHECK_EQ(0, strcmp("e", buf));
8407 6 : CHECK_EQ(0, StrCmp16(answer5, wbuf));
8408 :
8409 : memset(buf, 0x1, sizeof(buf));
8410 : memset(wbuf, 0x1, sizeof(wbuf));
8411 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8412 6 : CHECK_EQ(1, len);
8413 6 : len = str->Write(wbuf, 4, 1);
8414 6 : CHECK_EQ(1, len);
8415 6 : CHECK_EQ(0, strncmp("e\1", buf, 2));
8416 6 : uint16_t answer6[] = {'e', 0x101};
8417 6 : CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8418 :
8419 : memset(buf, 0x1, sizeof(buf));
8420 : memset(wbuf, 0x1, sizeof(wbuf));
8421 6 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8422 6 : CHECK_EQ(1, len);
8423 6 : len = str->Write(wbuf, 3, 1);
8424 6 : CHECK_EQ(1, len);
8425 6 : CHECK_EQ(0, strncmp("d\1", buf, 2));
8426 6 : uint16_t answer7[] = {'d', 0x101};
8427 6 : CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8428 :
8429 : memset(wbuf, 0x1, sizeof(wbuf));
8430 6 : wbuf[5] = 'X';
8431 6 : len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8432 6 : CHECK_EQ(5, len);
8433 12 : CHECK_EQ('X', wbuf[5]);
8434 6 : uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8435 6 : uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8436 6 : CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8437 6 : CHECK_NE(0, StrCmp16(answer8b, wbuf));
8438 6 : wbuf[5] = '\0';
8439 6 : CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8440 :
8441 : memset(buf, 0x1, sizeof(buf));
8442 6 : buf[5] = 'X';
8443 : len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8444 : 0,
8445 : 6,
8446 6 : String::NO_NULL_TERMINATION);
8447 6 : CHECK_EQ(5, len);
8448 6 : CHECK_EQ('X', buf[5]);
8449 6 : CHECK_EQ(0, strncmp("abcde", buf, 5));
8450 6 : CHECK_NE(0, strcmp("abcde", buf));
8451 6 : buf[5] = '\0';
8452 6 : CHECK_EQ(0, strcmp("abcde", buf));
8453 :
8454 : memset(utf8buf, 0x1, sizeof(utf8buf));
8455 6 : utf8buf[8] = 'X';
8456 : len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8457 6 : String::NO_NULL_TERMINATION);
8458 6 : CHECK_EQ(8, len);
8459 6 : CHECK_EQ('X', utf8buf[8]);
8460 6 : CHECK_EQ(5, charlen);
8461 6 : CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8462 6 : CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8463 6 : utf8buf[8] = '\0';
8464 6 : CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8465 :
8466 : memset(utf8buf, 0x1, sizeof(utf8buf));
8467 6 : utf8buf[5] = 'X';
8468 : len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8469 6 : String::NO_NULL_TERMINATION);
8470 6 : CHECK_EQ(5, len);
8471 6 : CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8472 6 : CHECK_EQ(5, charlen);
8473 6 : utf8buf[5] = '\0';
8474 6 : CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8475 :
8476 : memset(buf, 0x1, sizeof(buf));
8477 6 : len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8478 6 : CHECK_EQ(7, len);
8479 6 : CHECK_EQ(0, strcmp("abc", buf));
8480 6 : CHECK_EQ(0, buf[3]);
8481 6 : CHECK_EQ(0, strcmp("def", buf + 4));
8482 :
8483 6 : CHECK_EQ(0, str->WriteOneByte(nullptr, 0, 0, String::NO_NULL_TERMINATION));
8484 6 : CHECK_EQ(0, str->WriteUtf8(nullptr, 0, 0, String::NO_NULL_TERMINATION));
8485 12 : CHECK_EQ(0, str->Write(nullptr, 0, 0, String::NO_NULL_TERMINATION));
8486 6 : }
8487 :
8488 :
8489 12 : static void Utf16Helper(
8490 : LocalContext& context, // NOLINT
8491 : const char* name,
8492 : const char* lengths_name,
8493 : int len) {
8494 : Local<v8::Array> a = Local<v8::Array>::Cast(
8495 60 : context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8496 : Local<v8::Array> alens =
8497 : Local<v8::Array>::Cast(context->Global()
8498 48 : ->Get(context.local(), v8_str(lengths_name))
8499 12 : .ToLocalChecked());
8500 552 : for (int i = 0; i < len; i++) {
8501 : Local<v8::String> string =
8502 1080 : Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8503 : Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8504 540 : alens->Get(context.local(), i).ToLocalChecked());
8505 540 : int length = GetUtf8Length(string);
8506 540 : CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8507 : }
8508 12 : }
8509 :
8510 6 : void TestUtf8DecodingAgainstReference(
8511 : const char* cases[],
8512 474 : const std::vector<std::vector<uint16_t>>& unicode_expected) {
8513 132 : for (size_t test_ix = 0; test_ix < unicode_expected.size(); ++test_ix) {
8514 60 : v8::Local<String> str = v8_str(cases[test_ix]);
8515 180 : CHECK_EQ(unicode_expected[test_ix].size(), str->Length());
8516 :
8517 60 : std::unique_ptr<uint16_t[]> buffer(new uint16_t[str->Length()]);
8518 60 : str->Write(buffer.get(), 0, -1, String::NO_NULL_TERMINATION);
8519 :
8520 1044 : for (size_t i = 0; i < unicode_expected[test_ix].size(); ++i) {
8521 576 : CHECK_EQ(unicode_expected[test_ix][i], buffer[i]);
8522 : }
8523 : }
8524 6 : }
8525 :
8526 23724 : THREADED_TEST(OverlongSequencesAndSurrogates) {
8527 6 : LocalContext context;
8528 12 : v8::HandleScope scope(context->GetIsolate());
8529 :
8530 : const char* cases[] = {
8531 : // Overlong 2-byte sequence.
8532 : "X\xc0\xbfY\0",
8533 : // Another overlong 2-byte sequence.
8534 : "X\xc1\xbfY\0",
8535 : // Overlong 3-byte sequence.
8536 : "X\xe0\x9f\xbfY\0",
8537 : // Overlong 4-byte sequence.
8538 : "X\xf0\x89\xbf\xbfY\0",
8539 : // Invalid 3-byte sequence (reserved for surrogates).
8540 : "X\xed\xa0\x80Y\0",
8541 : // Invalid 4-bytes sequence (value out of range).
8542 : "X\xf4\x90\x80\x80Y\0",
8543 :
8544 : // Start of an overlong 3-byte sequence but not enough continuation bytes.
8545 : "X\xe0\x9fY\0",
8546 : // Start of an overlong 4-byte sequence but not enough continuation bytes.
8547 : "X\xf0\x89\xbfY\0",
8548 : // Start of an invalid 3-byte sequence (reserved for surrogates) but not
8549 : // enough continuation bytes.
8550 : "X\xed\xa0Y\0",
8551 : // Start of an invalid 4-bytes sequence (value out of range) but not
8552 : // enough continuation bytes.
8553 : "X\xf4\x90\x80Y\0",
8554 6 : };
8555 : const std::vector<std::vector<uint16_t>> unicode_expected = {
8556 : {0x58, 0xfffd, 0xfffd, 0x59},
8557 : {0x58, 0xfffd, 0xfffd, 0x59},
8558 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0x59},
8559 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x59},
8560 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0x59},
8561 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0x59},
8562 : {0x58, 0xfffd, 0xfffd, 0x59},
8563 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0x59},
8564 : {0x58, 0xfffd, 0xfffd, 0x59},
8565 : {0x58, 0xfffd, 0xfffd, 0xfffd, 0x59},
8566 12 : };
8567 12 : CHECK_EQ(unicode_expected.size(), arraysize(cases));
8568 12 : TestUtf8DecodingAgainstReference(cases, unicode_expected);
8569 6 : }
8570 :
8571 23724 : THREADED_TEST(Utf16) {
8572 6 : LocalContext context;
8573 12 : v8::HandleScope scope(context->GetIsolate());
8574 : CompileRun(
8575 : "var pad = '01234567890123456789';"
8576 : "var p = [];"
8577 : "var plens = [20, 3, 3];"
8578 : "p.push('01234567890123456789');"
8579 : "var lead = 0xd800;"
8580 : "var trail = 0xdc00;"
8581 : "p.push(String.fromCharCode(0xd800));"
8582 : "p.push(String.fromCharCode(0xdc00));"
8583 : "var a = [];"
8584 : "var b = [];"
8585 : "var c = [];"
8586 : "var alens = [];"
8587 : "for (var i = 0; i < 3; i++) {"
8588 : " p[1] = String.fromCharCode(lead++);"
8589 : " for (var j = 0; j < 3; j++) {"
8590 : " p[2] = String.fromCharCode(trail++);"
8591 : " a.push(p[i] + p[j]);"
8592 : " b.push(p[i] + p[j]);"
8593 : " c.push(p[i] + p[j]);"
8594 : " alens.push(plens[i] + plens[j]);"
8595 : " }"
8596 : "}"
8597 : "alens[5] -= 2;" // Here the surrogate pairs match up.
8598 : "var a2 = [];"
8599 : "var b2 = [];"
8600 : "var c2 = [];"
8601 : "var a2lens = [];"
8602 : "for (var m = 0; m < 9; m++) {"
8603 : " for (var n = 0; n < 9; n++) {"
8604 : " a2.push(a[m] + a[n]);"
8605 : " b2.push(b[m] + b[n]);"
8606 : " var newc = 'x' + c[m] + c[n] + 'y';"
8607 : " c2.push(newc.substring(1, newc.length - 1));"
8608 : " var utf = alens[m] + alens[n];" // And here.
8609 : // The 'n's that start with 0xdc.. are 6-8
8610 : // The 'm's that end with 0xd8.. are 1, 4 and 7
8611 : " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8612 : " a2lens.push(utf);"
8613 : " }"
8614 : "}");
8615 6 : Utf16Helper(context, "a", "alens", 9);
8616 12 : Utf16Helper(context, "a2", "a2lens", 81);
8617 6 : }
8618 :
8619 :
8620 : static bool SameSymbol(Local<String> s1, Local<String> s2) {
8621 : i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8622 : i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8623 : return *is1 == *is2;
8624 : }
8625 :
8626 :
8627 23724 : THREADED_TEST(Utf16Symbol) {
8628 6 : LocalContext context;
8629 12 : v8::HandleScope scope(context->GetIsolate());
8630 :
8631 : Local<String> symbol1 =
8632 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8633 6 : v8::NewStringType::kInternalized)
8634 6 : .ToLocalChecked();
8635 : Local<String> symbol2 =
8636 : v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8637 6 : v8::NewStringType::kInternalized)
8638 6 : .ToLocalChecked();
8639 6 : CHECK(SameSymbol(symbol1, symbol2));
8640 :
8641 : CompileRun(
8642 : "var sym0 = 'benedictus';"
8643 : "var sym0b = 'S\303\270ren';"
8644 : "var sym1 = '\355\240\201\355\260\207';"
8645 : "var sym2 = '\360\220\220\210';"
8646 : "var sym3 = 'x\355\240\201\355\260\207';"
8647 : "var sym4 = 'x\360\220\220\210';"
8648 : "if (sym1.length != 2) throw sym1;"
8649 : "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8650 : "if (sym2.length != 2) throw sym2;"
8651 : "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8652 : "if (sym3.length != 3) throw sym3;"
8653 : "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8654 : "if (sym4.length != 3) throw sym4;"
8655 : "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8656 : Local<String> sym0 =
8657 : v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8658 6 : v8::NewStringType::kInternalized)
8659 6 : .ToLocalChecked();
8660 : Local<String> sym0b =
8661 : v8::String::NewFromUtf8(context->GetIsolate(), "S\303\270ren",
8662 6 : v8::NewStringType::kInternalized)
8663 6 : .ToLocalChecked();
8664 : Local<String> sym1 =
8665 : v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8666 6 : v8::NewStringType::kInternalized)
8667 6 : .ToLocalChecked();
8668 : Local<String> sym2 =
8669 : v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8670 6 : v8::NewStringType::kInternalized)
8671 6 : .ToLocalChecked();
8672 : Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8673 : "x\355\240\201\355\260\207",
8674 6 : v8::NewStringType::kInternalized)
8675 6 : .ToLocalChecked();
8676 : Local<String> sym4 =
8677 : v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8678 6 : v8::NewStringType::kInternalized)
8679 6 : .ToLocalChecked();
8680 6 : v8::Local<v8::Object> global = context->Global();
8681 : Local<Value> s0 =
8682 18 : global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8683 : Local<Value> s0b =
8684 18 : global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8685 : Local<Value> s1 =
8686 18 : global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8687 : Local<Value> s2 =
8688 18 : global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8689 : Local<Value> s3 =
8690 18 : global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8691 : Local<Value> s4 =
8692 18 : global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8693 6 : CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8694 6 : CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8695 6 : CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8696 6 : CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8697 6 : CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8698 12 : CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8699 6 : }
8700 :
8701 :
8702 23724 : THREADED_TEST(Utf16MissingTrailing) {
8703 6 : LocalContext context;
8704 12 : v8::HandleScope scope(context->GetIsolate());
8705 :
8706 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8707 : int size = 1024 * 64;
8708 6 : uint8_t* buffer = new uint8_t[size];
8709 98310 : for (int i = 0; i < size; i += 4) {
8710 98304 : buffer[i] = 0xf0;
8711 98304 : buffer[i + 1] = 0x9d;
8712 98304 : buffer[i + 2] = 0x80;
8713 98304 : buffer[i + 3] = 0x9e;
8714 : }
8715 :
8716 : // Now invoke the decoder without last 3 bytes
8717 : v8::Local<v8::String> str =
8718 : v8::String::NewFromUtf8(
8719 : context->GetIsolate(), reinterpret_cast<char*>(buffer),
8720 6 : v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8721 : USE(str);
8722 12 : delete[] buffer;
8723 6 : }
8724 :
8725 :
8726 23724 : THREADED_TEST(Utf16Trailing3Byte) {
8727 6 : LocalContext context;
8728 6 : v8::Isolate* isolate = context->GetIsolate();
8729 12 : v8::HandleScope scope(isolate);
8730 :
8731 : // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8732 : int size = 1024 * 63;
8733 6 : uint8_t* buffer = new uint8_t[size];
8734 129030 : for (int i = 0; i < size; i += 3) {
8735 129024 : buffer[i] = 0xe2;
8736 129024 : buffer[i + 1] = 0x80;
8737 129024 : buffer[i + 2] = 0xa6;
8738 : }
8739 :
8740 : // Now invoke the decoder without last 3 bytes
8741 : v8::Local<v8::String> str =
8742 : v8::String::NewFromUtf8(isolate, reinterpret_cast<char*>(buffer),
8743 : v8::NewStringType::kNormal, size)
8744 6 : .ToLocalChecked();
8745 :
8746 12 : v8::String::Value value(isolate, str);
8747 6 : CHECK_EQ(value.length(), size / 3);
8748 12 : CHECK_EQ((*value)[value.length() - 1], 0x2026);
8749 :
8750 12 : delete[] buffer;
8751 6 : }
8752 :
8753 :
8754 23724 : THREADED_TEST(ToArrayIndex) {
8755 6 : LocalContext context;
8756 6 : v8::Isolate* isolate = context->GetIsolate();
8757 12 : v8::HandleScope scope(isolate);
8758 :
8759 6 : v8::Local<String> str = v8_str("42");
8760 6 : v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
8761 6 : CHECK(!index.IsEmpty());
8762 18 : CHECK_EQ(42.0,
8763 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8764 6 : str = v8_str("42asdf");
8765 6 : index = str->ToArrayIndex(context.local());
8766 6 : CHECK(index.IsEmpty());
8767 6 : str = v8_str("-42");
8768 6 : index = str->ToArrayIndex(context.local());
8769 6 : CHECK(index.IsEmpty());
8770 6 : str = v8_str("4294967294");
8771 6 : index = str->ToArrayIndex(context.local());
8772 6 : CHECK(!index.IsEmpty());
8773 18 : CHECK_EQ(4294967294.0,
8774 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8775 6 : v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
8776 6 : index = num->ToArrayIndex(context.local());
8777 6 : CHECK(!index.IsEmpty());
8778 18 : CHECK_EQ(1.0,
8779 : index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8780 6 : num = v8::Number::New(isolate, -1);
8781 6 : index = num->ToArrayIndex(context.local());
8782 6 : CHECK(index.IsEmpty());
8783 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
8784 12 : index = obj->ToArrayIndex(context.local());
8785 12 : CHECK(index.IsEmpty());
8786 6 : }
8787 :
8788 :
8789 23724 : THREADED_TEST(ErrorConstruction) {
8790 6 : LocalContext context;
8791 12 : v8::HandleScope scope(context->GetIsolate());
8792 :
8793 6 : v8::Local<String> foo = v8_str("foo");
8794 6 : v8::Local<String> message = v8_str("message");
8795 6 : v8::Local<Value> range_error = v8::Exception::RangeError(foo);
8796 6 : CHECK(range_error->IsObject());
8797 24 : CHECK(range_error.As<v8::Object>()
8798 : ->Get(context.local(), message)
8799 : .ToLocalChecked()
8800 : ->Equals(context.local(), foo)
8801 : .FromJust());
8802 6 : v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
8803 6 : CHECK(reference_error->IsObject());
8804 24 : CHECK(reference_error.As<v8::Object>()
8805 : ->Get(context.local(), message)
8806 : .ToLocalChecked()
8807 : ->Equals(context.local(), foo)
8808 : .FromJust());
8809 6 : v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
8810 6 : CHECK(syntax_error->IsObject());
8811 24 : CHECK(syntax_error.As<v8::Object>()
8812 : ->Get(context.local(), message)
8813 : .ToLocalChecked()
8814 : ->Equals(context.local(), foo)
8815 : .FromJust());
8816 6 : v8::Local<Value> type_error = v8::Exception::TypeError(foo);
8817 6 : CHECK(type_error->IsObject());
8818 24 : CHECK(type_error.As<v8::Object>()
8819 : ->Get(context.local(), message)
8820 : .ToLocalChecked()
8821 : ->Equals(context.local(), foo)
8822 : .FromJust());
8823 6 : v8::Local<Value> error = v8::Exception::Error(foo);
8824 6 : CHECK(error->IsObject());
8825 24 : CHECK(error.As<v8::Object>()
8826 : ->Get(context.local(), message)
8827 : .ToLocalChecked()
8828 : ->Equals(context.local(), foo)
8829 6 : .FromJust());
8830 6 : }
8831 :
8832 :
8833 48 : static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8834 12 : ApiTestFuzzer::Fuzz();
8835 12 : v8::Local<String> foo = v8_str("foo");
8836 12 : v8::Local<String> message = v8_str("message");
8837 12 : v8::Local<Value> error = v8::Exception::Error(foo);
8838 12 : CHECK(error->IsObject());
8839 12 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8840 36 : CHECK(error.As<v8::Object>()
8841 : ->Get(context, message)
8842 : .ToLocalChecked()
8843 : ->Equals(context, foo)
8844 : .FromJust());
8845 12 : info.GetIsolate()->ThrowException(error);
8846 : info.GetReturnValue().SetUndefined();
8847 12 : }
8848 :
8849 :
8850 23724 : THREADED_TEST(ExceptionCreateMessage) {
8851 6 : LocalContext context;
8852 12 : v8::HandleScope scope(context->GetIsolate());
8853 6 : v8::Local<String> foo_str = v8_str("foo");
8854 6 : v8::Local<String> message_str = v8_str("message");
8855 :
8856 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
8857 :
8858 : Local<v8::FunctionTemplate> fun =
8859 6 : v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8860 6 : v8::Local<v8::Object> global = context->Global();
8861 36 : CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
8862 : fun->GetFunction(context.local()).ToLocalChecked())
8863 : .FromJust());
8864 :
8865 12 : TryCatch try_catch(context->GetIsolate());
8866 : CompileRun(
8867 : "function f1() {\n"
8868 : " throwV8Exception();\n"
8869 : "};\n"
8870 : "f1();");
8871 6 : CHECK(try_catch.HasCaught());
8872 :
8873 6 : v8::Local<v8::Value> error = try_catch.Exception();
8874 6 : CHECK(error->IsObject());
8875 24 : CHECK(error.As<v8::Object>()
8876 : ->Get(context.local(), message_str)
8877 : .ToLocalChecked()
8878 : ->Equals(context.local(), foo_str)
8879 : .FromJust());
8880 :
8881 : v8::Local<v8::Message> message =
8882 6 : v8::Exception::CreateMessage(context->GetIsolate(), error);
8883 6 : CHECK(!message.IsEmpty());
8884 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
8885 12 : CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
8886 :
8887 6 : v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
8888 6 : CHECK(!stackTrace.IsEmpty());
8889 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
8890 :
8891 6 : stackTrace = v8::Exception::GetStackTrace(error);
8892 6 : CHECK(!stackTrace.IsEmpty());
8893 6 : CHECK_EQ(2, stackTrace->GetFrameCount());
8894 :
8895 6 : context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
8896 :
8897 : // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8898 : // is false.
8899 6 : try_catch.Reset();
8900 :
8901 : CompileRun(
8902 : "function f2() {\n"
8903 : " return throwV8Exception();\n"
8904 : "};\n"
8905 : "f2();");
8906 6 : CHECK(try_catch.HasCaught());
8907 :
8908 6 : error = try_catch.Exception();
8909 6 : CHECK(error->IsObject());
8910 24 : CHECK(error.As<v8::Object>()
8911 : ->Get(context.local(), message_str)
8912 : .ToLocalChecked()
8913 : ->Equals(context.local(), foo_str)
8914 : .FromJust());
8915 :
8916 6 : message = v8::Exception::CreateMessage(context->GetIsolate(), error);
8917 6 : CHECK(!message.IsEmpty());
8918 12 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
8919 12 : CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust());
8920 :
8921 : // Should be empty stack trace.
8922 6 : stackTrace = message->GetStackTrace();
8923 6 : CHECK(stackTrace.IsEmpty());
8924 18 : CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
8925 6 : }
8926 :
8927 :
8928 23724 : THREADED_TEST(ExceptionCreateMessageLength) {
8929 6 : LocalContext context;
8930 12 : v8::HandleScope scope(context->GetIsolate());
8931 :
8932 : // Test that the message is not truncated.
8933 12 : TryCatch try_catch(context->GetIsolate());
8934 : CompileRun(
8935 : "var message = 'm';"
8936 : "while (message.length < 1000) message += message;"
8937 : "throw message;");
8938 6 : CHECK(try_catch.HasCaught());
8939 :
8940 24 : CHECK_LT(1000, try_catch.Message()->Get()->Length());
8941 6 : }
8942 :
8943 :
8944 0 : static void YGetter(Local<String> name,
8945 : const v8::PropertyCallbackInfo<v8::Value>& info) {
8946 0 : ApiTestFuzzer::Fuzz();
8947 0 : info.GetReturnValue().Set(v8_num(10));
8948 0 : }
8949 :
8950 :
8951 6 : static void YSetter(Local<String> name,
8952 : Local<Value> value,
8953 : const v8::PropertyCallbackInfo<void>& info) {
8954 : Local<Object> this_obj = Local<Object>::Cast(info.This());
8955 6 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8956 12 : if (this_obj->Has(context, name).FromJust())
8957 12 : this_obj->Delete(context, name).FromJust();
8958 12 : CHECK(this_obj->Set(context, name, value).FromJust());
8959 6 : }
8960 :
8961 :
8962 23724 : THREADED_TEST(DeleteAccessor) {
8963 6 : v8::Isolate* isolate = CcTest::isolate();
8964 6 : v8::HandleScope scope(isolate);
8965 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8966 6 : obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8967 12 : LocalContext context;
8968 : v8::Local<v8::Object> holder =
8969 6 : obj->NewInstance(context.local()).ToLocalChecked();
8970 30 : CHECK(context->Global()
8971 : ->Set(context.local(), v8_str("holder"), holder)
8972 : .FromJust());
8973 : v8::Local<Value> result =
8974 : CompileRun("holder.y = 11; holder.y = 12; holder.y");
8975 18 : CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
8976 6 : }
8977 :
8978 :
8979 : static int trouble_nesting = 0;
8980 45 : static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8981 15 : ApiTestFuzzer::Fuzz();
8982 15 : trouble_nesting++;
8983 :
8984 : // Call a JS function that throws an uncaught exception.
8985 15 : Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
8986 15 : Local<v8::Object> arg_this = context->Global();
8987 : Local<Value> trouble_callee =
8988 15 : (trouble_nesting == 3)
8989 30 : ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
8990 60 : : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
8991 15 : CHECK(trouble_callee->IsFunction());
8992 : args.GetReturnValue().Set(Function::Cast(*trouble_callee)
8993 15 : ->Call(context, arg_this, 0, nullptr)
8994 30 : .FromMaybe(v8::Local<v8::Value>()));
8995 15 : }
8996 :
8997 :
8998 : static int report_count = 0;
8999 5 : static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
9000 : v8::Local<Value>) {
9001 5 : report_count++;
9002 5 : }
9003 :
9004 :
9005 : // Counts uncaught exceptions, but other tests running in parallel
9006 : // also have uncaught exceptions.
9007 23723 : TEST(ApiUncaughtException) {
9008 5 : report_count = 0;
9009 5 : LocalContext env;
9010 5 : v8::Isolate* isolate = env->GetIsolate();
9011 10 : v8::HandleScope scope(isolate);
9012 5 : isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
9013 :
9014 : Local<v8::FunctionTemplate> fun =
9015 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9016 5 : v8::Local<v8::Object> global = env->Global();
9017 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9018 : fun->GetFunction(env.local()).ToLocalChecked())
9019 : .FromJust());
9020 :
9021 : CompileRun(
9022 : "function trouble_callee() {"
9023 : " var x = null;"
9024 : " return x.foo;"
9025 : "};"
9026 : "function trouble_caller() {"
9027 : " trouble();"
9028 : "};");
9029 : Local<Value> trouble =
9030 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9031 5 : CHECK(trouble->IsFunction());
9032 : Local<Value> trouble_callee =
9033 15 : global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9034 5 : CHECK(trouble_callee->IsFunction());
9035 : Local<Value> trouble_caller =
9036 15 : global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9037 5 : CHECK(trouble_caller->IsFunction());
9038 : Function::Cast(*trouble_caller)
9039 10 : ->Call(env.local(), global, 0, nullptr)
9040 5 : .FromMaybe(v8::Local<v8::Value>());
9041 5 : CHECK_EQ(1, report_count);
9042 10 : isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9043 5 : }
9044 :
9045 :
9046 : static const char* script_resource_name = "ExceptionInNativeScript.js";
9047 5 : static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9048 : v8::Local<Value>) {
9049 5 : v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9050 10 : CHECK(!name_val.IsEmpty() && name_val->IsString());
9051 : v8::String::Utf8Value name(v8::Isolate::GetCurrent(),
9052 5 : message->GetScriptOrigin().ResourceName());
9053 5 : CHECK_EQ(0, strcmp(script_resource_name, *name));
9054 : v8::Local<v8::Context> context =
9055 5 : v8::Isolate::GetCurrent()->GetCurrentContext();
9056 10 : CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9057 : v8::String::Utf8Value source_line(
9058 : v8::Isolate::GetCurrent(),
9059 15 : message->GetSourceLine(context).ToLocalChecked());
9060 10 : CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9061 5 : }
9062 :
9063 :
9064 23723 : TEST(ExceptionInNativeScript) {
9065 5 : LocalContext env;
9066 5 : v8::Isolate* isolate = env->GetIsolate();
9067 10 : v8::HandleScope scope(isolate);
9068 5 : isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9069 :
9070 : Local<v8::FunctionTemplate> fun =
9071 5 : v8::FunctionTemplate::New(isolate, TroubleCallback);
9072 5 : v8::Local<v8::Object> global = env->Global();
9073 25 : CHECK(global->Set(env.local(), v8_str("trouble"),
9074 : fun->GetFunction(env.local()).ToLocalChecked())
9075 : .FromJust());
9076 :
9077 : CompileRunWithOrigin(
9078 : "function trouble() {\n"
9079 : " var o = {};\n"
9080 : " new o.foo();\n"
9081 : "};",
9082 5 : script_resource_name);
9083 : Local<Value> trouble =
9084 15 : global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9085 5 : CHECK(trouble->IsFunction());
9086 10 : CHECK(Function::Cast(*trouble)
9087 : ->Call(env.local(), global, 0, nullptr)
9088 : .IsEmpty());
9089 10 : isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9090 5 : }
9091 :
9092 :
9093 23723 : TEST(CompilationErrorUsingTryCatchHandler) {
9094 5 : LocalContext env;
9095 10 : v8::HandleScope scope(env->GetIsolate());
9096 10 : v8::TryCatch try_catch(env->GetIsolate());
9097 : v8_compile("This doesn't &*&@#$&*^ compile.");
9098 10 : CHECK(*try_catch.Exception());
9099 10 : CHECK(try_catch.HasCaught());
9100 5 : }
9101 :
9102 :
9103 23723 : TEST(TryCatchFinallyUsingTryCatchHandler) {
9104 5 : LocalContext env;
9105 10 : v8::HandleScope scope(env->GetIsolate());
9106 10 : v8::TryCatch try_catch(env->GetIsolate());
9107 : CompileRun("try { throw ''; } catch (e) {}");
9108 5 : CHECK(!try_catch.HasCaught());
9109 : CompileRun("try { throw ''; } finally {}");
9110 5 : CHECK(try_catch.HasCaught());
9111 5 : try_catch.Reset();
9112 : CompileRun(
9113 : "(function() {"
9114 : "try { throw ''; } finally { return; }"
9115 : "})()");
9116 5 : CHECK(!try_catch.HasCaught());
9117 : CompileRun(
9118 : "(function()"
9119 : " { try { throw ''; } finally { throw 0; }"
9120 : "})()");
9121 10 : CHECK(try_catch.HasCaught());
9122 5 : }
9123 :
9124 :
9125 20 : void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9126 10 : v8::HandleScope scope(args.GetIsolate());
9127 : CompileRun(args[0]
9128 10 : ->ToString(args.GetIsolate()->GetCurrentContext())
9129 20 : .ToLocalChecked());
9130 10 : }
9131 :
9132 :
9133 23723 : TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9134 5 : v8::Isolate* isolate = CcTest::isolate();
9135 5 : v8::HandleScope scope(isolate);
9136 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9137 : templ->Set(v8_str("CEvaluate"),
9138 15 : v8::FunctionTemplate::New(isolate, CEvaluate));
9139 10 : LocalContext context(0, templ);
9140 10 : v8::TryCatch try_catch(isolate);
9141 : CompileRun("try {"
9142 : " CEvaluate('throw 1;');"
9143 : "} finally {"
9144 : "}");
9145 5 : CHECK(try_catch.HasCaught());
9146 10 : CHECK(!try_catch.Message().IsEmpty());
9147 10 : String::Utf8Value exception_value(isolate, try_catch.Exception());
9148 5 : CHECK_EQ(0, strcmp(*exception_value, "1"));
9149 5 : try_catch.Reset();
9150 : CompileRun("try {"
9151 : " CEvaluate('throw 1;');"
9152 : "} finally {"
9153 : " throw 2;"
9154 : "}");
9155 5 : CHECK(try_catch.HasCaught());
9156 10 : CHECK(!try_catch.Message().IsEmpty());
9157 10 : String::Utf8Value finally_exception_value(isolate, try_catch.Exception());
9158 10 : CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9159 5 : }
9160 :
9161 :
9162 : // For use within the TestSecurityHandler() test.
9163 : static bool g_security_callback_result = false;
9164 35 : static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9165 : Local<v8::Object> accessed_object,
9166 : Local<v8::Value> data) {
9167 : printf("a\n");
9168 35 : CHECK(!data.IsEmpty() && data->IsInt32());
9169 70 : CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9170 35 : return g_security_callback_result;
9171 : }
9172 :
9173 :
9174 : // SecurityHandler can't be run twice
9175 23723 : TEST(SecurityHandler) {
9176 5 : v8::Isolate* isolate = CcTest::isolate();
9177 5 : v8::HandleScope scope0(isolate);
9178 : v8::Local<v8::ObjectTemplate> global_template =
9179 5 : v8::ObjectTemplate::New(isolate);
9180 10 : global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9181 : // Create an environment
9182 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9183 5 : context0->Enter();
9184 :
9185 5 : v8::Local<v8::Object> global0 = context0->Global();
9186 : v8::Local<Script> script0 = v8_compile("foo = 111");
9187 5 : script0->Run(context0).ToLocalChecked();
9188 15 : CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9189 : v8::Local<Value> foo0 =
9190 15 : global0->Get(context0, v8_str("foo")).ToLocalChecked();
9191 10 : CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9192 15 : v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9193 10 : CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9194 :
9195 : // Create another environment, should fail security checks.
9196 10 : v8::HandleScope scope1(isolate);
9197 :
9198 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, global_template);
9199 5 : context1->Enter();
9200 :
9201 5 : v8::Local<v8::Object> global1 = context1->Global();
9202 15 : global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9203 : // This set will fail the security check.
9204 : v8::Local<Script> script1 =
9205 : v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9206 10 : CHECK(script1->Run(context1).IsEmpty());
9207 5 : g_security_callback_result = true;
9208 : // This read will pass the security check.
9209 : v8::Local<Value> foo1 =
9210 15 : global0->Get(context1, v8_str("foo")).ToLocalChecked();
9211 10 : CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9212 : // This read will pass the security check.
9213 15 : v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9214 10 : CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9215 :
9216 : // Create another environment, should pass security checks.
9217 : {
9218 5 : v8::HandleScope scope2(isolate);
9219 10 : LocalContext context2;
9220 5 : v8::Local<v8::Object> global2 = context2->Global();
9221 20 : CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9222 : .FromJust());
9223 : v8::Local<Script> script2 =
9224 : v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9225 5 : script2->Run(context2.local()).ToLocalChecked();
9226 : v8::Local<Value> foo2 =
9227 15 : global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9228 10 : CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9229 : v8::Local<Value> z2 =
9230 15 : global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9231 15 : CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9232 : }
9233 :
9234 5 : context1->Exit();
9235 10 : context0->Exit();
9236 5 : }
9237 :
9238 :
9239 23724 : THREADED_TEST(SecurityChecks) {
9240 6 : LocalContext env1;
9241 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9242 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9243 :
9244 6 : Local<Value> foo = v8_str("foo");
9245 6 : Local<Value> bar = v8_str("bar");
9246 :
9247 : // Set to the same domain.
9248 6 : env1->SetSecurityToken(foo);
9249 :
9250 : // Create a function in env1.
9251 : CompileRun("spy=function(){return spy;}");
9252 : Local<Value> spy =
9253 30 : env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9254 6 : CHECK(spy->IsFunction());
9255 :
9256 : // Create another function accessing global objects.
9257 : CompileRun("spy2=function(){return new this.Array();}");
9258 : Local<Value> spy2 =
9259 30 : env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9260 6 : CHECK(spy2->IsFunction());
9261 :
9262 : // Switch to env2 in the same domain and invoke spy on env2.
9263 : {
9264 6 : env2->SetSecurityToken(foo);
9265 : // Enter env2
9266 : Context::Scope scope_env2(env2);
9267 : Local<Value> result = Function::Cast(*spy)
9268 12 : ->Call(env2, env2->Global(), 0, nullptr)
9269 6 : .ToLocalChecked();
9270 6 : CHECK(result->IsFunction());
9271 : }
9272 :
9273 : {
9274 6 : env2->SetSecurityToken(bar);
9275 : Context::Scope scope_env2(env2);
9276 :
9277 : // Call cross_domain_call, it should throw an exception
9278 12 : v8::TryCatch try_catch(env1->GetIsolate());
9279 18 : CHECK(Function::Cast(*spy2)
9280 : ->Call(env2, env2->Global(), 0, nullptr)
9281 : .IsEmpty());
9282 6 : CHECK(try_catch.HasCaught());
9283 6 : }
9284 6 : }
9285 :
9286 :
9287 : // Regression test case for issue 1183439.
9288 23724 : THREADED_TEST(SecurityChecksForPrototypeChain) {
9289 6 : LocalContext current;
9290 12 : v8::HandleScope scope(current->GetIsolate());
9291 6 : v8::Local<Context> other = Context::New(current->GetIsolate());
9292 :
9293 : // Change context to be able to get to the Object function in the
9294 : // other context without hitting the security checks.
9295 : v8::Local<Value> other_object;
9296 : { Context::Scope scope(other);
9297 : other_object =
9298 24 : other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9299 18 : CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9300 : }
9301 :
9302 36 : CHECK(current->Global()
9303 : ->Set(current.local(), v8_str("other"), other->Global())
9304 : .FromJust());
9305 30 : CHECK(v8_compile("other")
9306 : ->Run(current.local())
9307 : .ToLocalChecked()
9308 : ->Equals(current.local(), other->Global())
9309 : .FromJust());
9310 :
9311 : // Make sure the security check fails here and we get an undefined
9312 : // result instead of getting the Object function. Repeat in a loop
9313 : // to make sure to exercise the IC code.
9314 : v8::Local<Script> access_other0 = v8_compile("other.Object");
9315 : v8::Local<Script> access_other1 = v8_compile("other[42]");
9316 36 : for (int i = 0; i < 5; i++) {
9317 60 : CHECK(access_other0->Run(current.local()).IsEmpty());
9318 60 : CHECK(access_other1->Run(current.local()).IsEmpty());
9319 : }
9320 :
9321 : // Create an object that has 'other' in its prototype chain and make
9322 : // sure we cannot access the Object function indirectly through
9323 : // that. Repeat in a loop to make sure to exercise the IC code.
9324 : v8_compile(
9325 : "function F() { };"
9326 : "F.prototype = other;"
9327 : "var f = new F();")
9328 6 : ->Run(current.local())
9329 6 : .ToLocalChecked();
9330 : v8::Local<Script> access_f0 = v8_compile("f.Object");
9331 : v8::Local<Script> access_f1 = v8_compile("f[42]");
9332 36 : for (int j = 0; j < 5; j++) {
9333 60 : CHECK(access_f0->Run(current.local()).IsEmpty());
9334 60 : CHECK(access_f1->Run(current.local()).IsEmpty());
9335 : }
9336 :
9337 : // Now it gets hairy: Set the prototype for the other global object
9338 : // to be the current global object. The prototype chain for 'f' now
9339 : // goes through 'other' but ends up in the current global object.
9340 : { Context::Scope scope(other);
9341 30 : CHECK(other->Global()
9342 : ->Set(other, v8_str("__proto__"), current->Global())
9343 : .FromJust());
9344 : }
9345 : // Set a named and an index property on the current global
9346 : // object. To force the lookup to go through the other global object,
9347 : // the properties must not exist in the other global object.
9348 30 : CHECK(current->Global()
9349 : ->Set(current.local(), v8_str("foo"), v8_num(100))
9350 : .FromJust());
9351 24 : CHECK(current->Global()
9352 : ->Set(current.local(), v8_num(99), v8_num(101))
9353 : .FromJust());
9354 : // Try to read the properties from f and make sure that the access
9355 : // gets stopped by the security checks on the other global object.
9356 : Local<Script> access_f2 = v8_compile("f.foo");
9357 : Local<Script> access_f3 = v8_compile("f[99]");
9358 36 : for (int k = 0; k < 5; k++) {
9359 60 : CHECK(access_f2->Run(current.local()).IsEmpty());
9360 60 : CHECK(access_f3->Run(current.local()).IsEmpty());
9361 6 : }
9362 6 : }
9363 :
9364 :
9365 : static bool security_check_with_gc_called;
9366 :
9367 10 : static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9368 : Local<v8::Object> accessed_object,
9369 : Local<v8::Value> data) {
9370 10 : CcTest::CollectAllGarbage();
9371 10 : security_check_with_gc_called = true;
9372 10 : return true;
9373 : }
9374 :
9375 :
9376 23723 : TEST(SecurityTestGCAllowed) {
9377 5 : v8::Isolate* isolate = CcTest::isolate();
9378 5 : v8::HandleScope handle_scope(isolate);
9379 : v8::Local<v8::ObjectTemplate> object_template =
9380 5 : v8::ObjectTemplate::New(isolate);
9381 5 : object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9382 :
9383 5 : v8::Local<Context> context = Context::New(isolate);
9384 : v8::Context::Scope context_scope(context);
9385 :
9386 25 : CHECK(context->Global()
9387 : ->Set(context, v8_str("obj"),
9388 : object_template->NewInstance(context).ToLocalChecked())
9389 : .FromJust());
9390 :
9391 5 : security_check_with_gc_called = false;
9392 : CompileRun("obj[0] = new String(1002);");
9393 5 : CHECK(security_check_with_gc_called);
9394 :
9395 5 : security_check_with_gc_called = false;
9396 20 : CHECK(CompileRun("obj[0]")
9397 : ->ToString(context)
9398 : .ToLocalChecked()
9399 : ->Equals(context, v8_str("1002"))
9400 : .FromJust());
9401 10 : CHECK(security_check_with_gc_called);
9402 5 : }
9403 :
9404 :
9405 23724 : THREADED_TEST(CrossDomainDelete) {
9406 6 : LocalContext env1;
9407 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9408 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9409 :
9410 6 : Local<Value> foo = v8_str("foo");
9411 6 : Local<Value> bar = v8_str("bar");
9412 :
9413 : // Set to the same domain.
9414 6 : env1->SetSecurityToken(foo);
9415 6 : env2->SetSecurityToken(foo);
9416 :
9417 30 : CHECK(
9418 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9419 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9420 :
9421 : // Change env2 to a different domain and delete env1.prop.
9422 6 : env2->SetSecurityToken(bar);
9423 : {
9424 : Context::Scope scope_env2(env2);
9425 : Local<Value> result =
9426 : CompileRun("delete env1.prop");
9427 6 : CHECK(result.IsEmpty());
9428 : }
9429 :
9430 : // Check that env1.prop still exists.
9431 : Local<Value> v =
9432 30 : env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9433 6 : CHECK(v->IsNumber());
9434 18 : CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9435 6 : }
9436 :
9437 :
9438 23724 : THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9439 6 : LocalContext env1;
9440 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9441 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9442 :
9443 6 : Local<Value> foo = v8_str("foo");
9444 6 : Local<Value> bar = v8_str("bar");
9445 :
9446 : // Set to the same domain.
9447 6 : env1->SetSecurityToken(foo);
9448 6 : env2->SetSecurityToken(foo);
9449 :
9450 30 : CHECK(
9451 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9452 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9453 :
9454 : // env1.prop is enumerable in env2.
9455 6 : Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9456 : {
9457 : Context::Scope scope_env2(env2);
9458 6 : Local<Value> result = CompileRun(test);
9459 6 : CHECK(result->IsTrue());
9460 : }
9461 :
9462 : // Change env2 to a different domain and test again.
9463 6 : env2->SetSecurityToken(bar);
9464 : {
9465 : Context::Scope scope_env2(env2);
9466 6 : Local<Value> result = CompileRun(test);
9467 6 : CHECK(result.IsEmpty());
9468 6 : }
9469 6 : }
9470 :
9471 :
9472 23724 : THREADED_TEST(CrossDomainFor) {
9473 6 : LocalContext env1;
9474 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9475 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9476 :
9477 6 : Local<Value> foo = v8_str("foo");
9478 6 : Local<Value> bar = v8_str("bar");
9479 :
9480 : // Set to the same domain.
9481 6 : env1->SetSecurityToken(foo);
9482 6 : env2->SetSecurityToken(foo);
9483 :
9484 30 : CHECK(
9485 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9486 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9487 :
9488 : // Change env2 to a different domain and set env1's global object
9489 : // as the __proto__ of an object in env2 and enumerate properties
9490 : // in for-in. It shouldn't enumerate properties on env1's global
9491 : // object. It shouldn't throw either, just silently ignore them.
9492 6 : env2->SetSecurityToken(bar);
9493 : {
9494 : Context::Scope scope_env2(env2);
9495 : Local<Value> result = CompileRun(
9496 : "(function() {"
9497 : " try {"
9498 : " for (var p in env1) {"
9499 : " if (p == 'prop') return false;"
9500 : " }"
9501 : " return true;"
9502 : " } catch (e) {"
9503 : " return false;"
9504 : " }"
9505 : "})()");
9506 6 : CHECK(result->IsTrue());
9507 6 : }
9508 6 : }
9509 :
9510 :
9511 23724 : THREADED_TEST(CrossDomainForInOnPrototype) {
9512 6 : LocalContext env1;
9513 12 : v8::HandleScope handle_scope(env1->GetIsolate());
9514 6 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9515 :
9516 6 : Local<Value> foo = v8_str("foo");
9517 6 : Local<Value> bar = v8_str("bar");
9518 :
9519 : // Set to the same domain.
9520 6 : env1->SetSecurityToken(foo);
9521 6 : env2->SetSecurityToken(foo);
9522 :
9523 30 : CHECK(
9524 : env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9525 30 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9526 :
9527 : // Change env2 to a different domain and set env1's global object
9528 : // as the __proto__ of an object in env2 and enumerate properties
9529 : // in for-in. It shouldn't enumerate properties on env1's global
9530 : // object.
9531 6 : env2->SetSecurityToken(bar);
9532 : {
9533 : Context::Scope scope_env2(env2);
9534 : Local<Value> result = CompileRun(
9535 : "(function() {"
9536 : " var obj = { '__proto__': env1 };"
9537 : " try {"
9538 : " for (var p in obj) {"
9539 : " if (p == 'prop') return false;"
9540 : " }"
9541 : " return true;"
9542 : " } catch (e) {"
9543 : " return false;"
9544 : " }"
9545 : "})()");
9546 6 : CHECK(result->IsTrue());
9547 6 : }
9548 6 : }
9549 :
9550 :
9551 23723 : TEST(ContextDetachGlobal) {
9552 5 : LocalContext env1;
9553 10 : v8::HandleScope handle_scope(env1->GetIsolate());
9554 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9555 :
9556 :
9557 5 : Local<Value> foo = v8_str("foo");
9558 :
9559 : // Set to the same domain.
9560 5 : env1->SetSecurityToken(foo);
9561 5 : env2->SetSecurityToken(foo);
9562 :
9563 : // Enter env2
9564 5 : env2->Enter();
9565 :
9566 : // Create a function in env2 and add a reference to it in env1.
9567 5 : Local<v8::Object> global2 = env2->Global();
9568 20 : CHECK(global2->Set(env2, v8_str("prop"),
9569 : v8::Integer::New(env2->GetIsolate(), 1))
9570 : .FromJust());
9571 : CompileRun("function getProp() {return prop;}");
9572 :
9573 35 : CHECK(env1->Global()
9574 : ->Set(env1.local(), v8_str("getProp"),
9575 : global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9576 : .FromJust());
9577 :
9578 : // Detach env2's global, and reuse the global object of env2
9579 5 : env2->Exit();
9580 5 : env2->DetachGlobal();
9581 :
9582 : v8::Local<Context> env3 = Context::New(
9583 5 : env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2);
9584 10 : env3->SetSecurityToken(v8_str("bar"));
9585 :
9586 5 : env3->Enter();
9587 5 : Local<v8::Object> global3 = env3->Global();
9588 10 : CHECK(global2->Equals(env3, global3).FromJust());
9589 15 : CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9590 15 : CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9591 20 : CHECK(global3->Set(env3, v8_str("prop"),
9592 : v8::Integer::New(env3->GetIsolate(), -1))
9593 : .FromJust());
9594 20 : CHECK(global3->Set(env3, v8_str("prop2"),
9595 : v8::Integer::New(env3->GetIsolate(), 2))
9596 : .FromJust());
9597 5 : env3->Exit();
9598 :
9599 : // Call getProp in env1, and it should return the value 1
9600 : {
9601 5 : Local<v8::Object> global1 = env1->Global();
9602 : Local<Value> get_prop =
9603 20 : global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9604 5 : CHECK(get_prop->IsFunction());
9605 5 : v8::TryCatch try_catch(env1->GetIsolate());
9606 : Local<Value> r = Function::Cast(*get_prop)
9607 10 : ->Call(env1.local(), global1, 0, nullptr)
9608 5 : .ToLocalChecked();
9609 5 : CHECK(!try_catch.HasCaught());
9610 10 : CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9611 : }
9612 :
9613 : // Check that env3 is not accessible from env1
9614 : {
9615 10 : v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9616 5 : CHECK(r.IsEmpty());
9617 5 : }
9618 5 : }
9619 :
9620 :
9621 23723 : TEST(DetachGlobal) {
9622 5 : LocalContext env1;
9623 10 : v8::HandleScope scope(env1->GetIsolate());
9624 :
9625 : // Create second environment.
9626 5 : v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9627 :
9628 5 : Local<Value> foo = v8_str("foo");
9629 :
9630 : // Set same security token for env1 and env2.
9631 5 : env1->SetSecurityToken(foo);
9632 5 : env2->SetSecurityToken(foo);
9633 :
9634 : // Create a property on the global object in env2.
9635 : {
9636 : v8::Context::Scope scope(env2);
9637 25 : CHECK(env2->Global()
9638 : ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9639 : .FromJust());
9640 : }
9641 :
9642 : // Create a reference to env2 global from env1 global.
9643 30 : CHECK(env1->Global()
9644 : ->Set(env1.local(), v8_str("other"), env2->Global())
9645 : .FromJust());
9646 :
9647 : // Check that we have access to other.p in env2 from env1.
9648 : Local<Value> result = CompileRun("other.p");
9649 5 : CHECK(result->IsInt32());
9650 10 : CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9651 :
9652 : // Hold on to global from env2 and detach global from env2.
9653 5 : Local<v8::Object> global2 = env2->Global();
9654 5 : env2->DetachGlobal();
9655 :
9656 : // Check that the global has been detached. No other.p property can
9657 : // be found.
9658 : result = CompileRun("other.p");
9659 5 : CHECK(result.IsEmpty());
9660 :
9661 : // Reuse global2 for env3.
9662 : v8::Local<Context> env3 = Context::New(
9663 5 : env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2);
9664 15 : CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9665 :
9666 : // Start by using the same security token for env3 as for env1 and env2.
9667 5 : env3->SetSecurityToken(foo);
9668 :
9669 : // Create a property on the global object in env3.
9670 : {
9671 : v8::Context::Scope scope(env3);
9672 25 : CHECK(env3->Global()
9673 : ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9674 : .FromJust());
9675 : }
9676 :
9677 : // Check that other.p is now the property in env3 and that we have access.
9678 : result = CompileRun("other.p");
9679 5 : CHECK(result->IsInt32());
9680 15 : CHECK_EQ(24, result->Int32Value(env3).FromJust());
9681 5 : }
9682 :
9683 :
9684 130 : void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9685 65 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9686 : info.GetReturnValue().Set(
9687 260 : context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9688 65 : }
9689 :
9690 :
9691 23723 : TEST(DetachedAccesses) {
9692 5 : LocalContext env1;
9693 10 : v8::HandleScope scope(env1->GetIsolate());
9694 :
9695 : // Create second environment.
9696 : Local<ObjectTemplate> inner_global_template =
9697 10 : FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9698 : inner_global_template ->SetAccessorProperty(
9699 10 : v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9700 : v8::Local<Context> env2 =
9701 5 : Context::New(env1->GetIsolate(), nullptr, inner_global_template);
9702 :
9703 5 : Local<Value> foo = v8_str("foo");
9704 :
9705 : // Set same security token for env1 and env2.
9706 5 : env1->SetSecurityToken(foo);
9707 5 : env2->SetSecurityToken(foo);
9708 :
9709 30 : CHECK(env1->Global()
9710 : ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
9711 : .FromJust());
9712 :
9713 : {
9714 : v8::Context::Scope scope(env2);
9715 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
9716 : CompileRun(
9717 : "function bound_x() { return x; }"
9718 : "function get_x() { return this.x; }"
9719 : "function get_x_w() { return (function() {return this.x;})(); }");
9720 25 : CHECK(env1->Global()
9721 : ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
9722 : .FromJust());
9723 25 : CHECK(env1->Global()
9724 : ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
9725 : .FromJust());
9726 25 : CHECK(env1->Global()
9727 : ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
9728 : .FromJust());
9729 : env1->Global()
9730 : ->Set(env1.local(), v8_str("this_x"),
9731 20 : CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
9732 10 : .FromJust();
9733 : }
9734 :
9735 5 : Local<Object> env2_global = env2->Global();
9736 5 : env2->DetachGlobal();
9737 :
9738 : Local<Value> result;
9739 : result = CompileRun("bound_x()");
9740 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
9741 : result = CompileRun("get_x()");
9742 5 : CHECK(result.IsEmpty());
9743 : result = CompileRun("get_x_w()");
9744 5 : CHECK(result.IsEmpty());
9745 : result = CompileRun("this_x()");
9746 15 : CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
9747 :
9748 : // Reattach env2's proxy
9749 : env2 = Context::New(env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(),
9750 5 : env2_global);
9751 5 : env2->SetSecurityToken(foo);
9752 : {
9753 : v8::Context::Scope scope(env2);
9754 25 : CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
9755 25 : CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9756 : result = CompileRun(
9757 : "results = [];"
9758 : "for (var i = 0; i < 4; i++ ) {"
9759 : " results.push(env1.bound_x());"
9760 : " results.push(env1.get_x());"
9761 : " results.push(env1.get_x_w());"
9762 : " results.push(env1.this_x());"
9763 : "}"
9764 : "results");
9765 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
9766 5 : CHECK_EQ(16u, results->Length());
9767 20 : for (int i = 0; i < 16; i += 4) {
9768 80 : CHECK(v8_str("env2_x")
9769 : ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
9770 : .FromJust());
9771 80 : CHECK(v8_str("env1_x")
9772 : ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
9773 : .FromJust());
9774 80 : CHECK(v8_str("env3_x")
9775 : ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
9776 : .FromJust());
9777 80 : CHECK(v8_str("env2_x")
9778 : ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
9779 : .FromJust());
9780 : }
9781 : }
9782 :
9783 : result = CompileRun(
9784 : "results = [];"
9785 : "for (var i = 0; i < 4; i++ ) {"
9786 : " results.push(bound_x());"
9787 : " results.push(get_x());"
9788 : " results.push(get_x_w());"
9789 : " results.push(this_x());"
9790 : "}"
9791 : "results");
9792 : Local<v8::Array> results = Local<v8::Array>::Cast(result);
9793 5 : CHECK_EQ(16u, results->Length());
9794 20 : for (int i = 0; i < 16; i += 4) {
9795 80 : CHECK(v8_str("env2_x")
9796 : ->Equals(env1.local(),
9797 : results->Get(env1.local(), i + 0).ToLocalChecked())
9798 : .FromJust());
9799 80 : CHECK(v8_str("env3_x")
9800 : ->Equals(env1.local(),
9801 : results->Get(env1.local(), i + 1).ToLocalChecked())
9802 : .FromJust());
9803 80 : CHECK(v8_str("env3_x")
9804 : ->Equals(env1.local(),
9805 : results->Get(env1.local(), i + 2).ToLocalChecked())
9806 : .FromJust());
9807 80 : CHECK(v8_str("env2_x")
9808 : ->Equals(env1.local(),
9809 : results->Get(env1.local(), i + 3).ToLocalChecked())
9810 : .FromJust());
9811 : }
9812 :
9813 : result = CompileRun(
9814 : "results = [];"
9815 : "for (var i = 0; i < 4; i++ ) {"
9816 : " results.push(this.bound_x());"
9817 : " results.push(this.get_x());"
9818 : " results.push(this.get_x_w());"
9819 : " results.push(this.this_x());"
9820 : "}"
9821 : "results");
9822 : results = Local<v8::Array>::Cast(result);
9823 5 : CHECK_EQ(16u, results->Length());
9824 20 : for (int i = 0; i < 16; i += 4) {
9825 80 : CHECK(v8_str("env2_x")
9826 : ->Equals(env1.local(),
9827 : results->Get(env1.local(), i + 0).ToLocalChecked())
9828 : .FromJust());
9829 80 : CHECK(v8_str("env1_x")
9830 : ->Equals(env1.local(),
9831 : results->Get(env1.local(), i + 1).ToLocalChecked())
9832 : .FromJust());
9833 80 : CHECK(v8_str("env3_x")
9834 : ->Equals(env1.local(),
9835 : results->Get(env1.local(), i + 2).ToLocalChecked())
9836 : .FromJust());
9837 80 : CHECK(v8_str("env2_x")
9838 : ->Equals(env1.local(),
9839 : results->Get(env1.local(), i + 3).ToLocalChecked())
9840 : .FromJust());
9841 5 : }
9842 5 : }
9843 :
9844 :
9845 : static bool allowed_access = false;
9846 430 : static bool AccessBlocker(Local<v8::Context> accessing_context,
9847 : Local<v8::Object> accessed_object,
9848 : Local<v8::Value> data) {
9849 430 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
9850 1290 : return context->Global()->Equals(context, accessed_object).FromJust() ||
9851 430 : allowed_access;
9852 : }
9853 :
9854 :
9855 : static int g_echo_value = -1;
9856 :
9857 :
9858 15 : static void EchoGetter(
9859 : Local<String> name,
9860 : const v8::PropertyCallbackInfo<v8::Value>& info) {
9861 15 : info.GetReturnValue().Set(v8_num(g_echo_value));
9862 15 : }
9863 :
9864 :
9865 10 : static void EchoSetter(Local<String> name, Local<Value> value,
9866 : const v8::PropertyCallbackInfo<void>& args) {
9867 10 : if (value->IsNumber())
9868 : g_echo_value =
9869 20 : value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
9870 10 : }
9871 :
9872 :
9873 0 : static void UnreachableGetter(
9874 : Local<String> name,
9875 : const v8::PropertyCallbackInfo<v8::Value>& info) {
9876 0 : CHECK(false); // This function should not be called..
9877 : }
9878 :
9879 :
9880 0 : static void UnreachableSetter(Local<String>,
9881 : Local<Value>,
9882 : const v8::PropertyCallbackInfo<void>&) {
9883 0 : CHECK(false); // This function should not be called.
9884 : }
9885 :
9886 :
9887 0 : static void UnreachableFunction(
9888 : const v8::FunctionCallbackInfo<v8::Value>& info) {
9889 0 : CHECK(false); // This function should not be called..
9890 : }
9891 :
9892 :
9893 23723 : TEST(AccessControl) {
9894 5 : v8::Isolate* isolate = CcTest::isolate();
9895 5 : v8::HandleScope handle_scope(isolate);
9896 : v8::Local<v8::ObjectTemplate> global_template =
9897 5 : v8::ObjectTemplate::New(isolate);
9898 :
9899 5 : global_template->SetAccessCheckCallback(AccessBlocker);
9900 :
9901 : // Add an accessor accessible by cross-domain JS code.
9902 : global_template->SetAccessor(
9903 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
9904 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9905 :
9906 :
9907 : // Add an accessor that is not accessible by cross-domain JS code.
9908 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
9909 : UnreachableSetter, v8::Local<Value>(),
9910 5 : v8::DEFAULT);
9911 :
9912 : global_template->SetAccessorProperty(
9913 : v8_str("blocked_js_prop"),
9914 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
9915 : v8::FunctionTemplate::New(isolate, UnreachableFunction),
9916 : v8::None,
9917 15 : v8::DEFAULT);
9918 :
9919 : // Create an environment
9920 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9921 5 : context0->Enter();
9922 :
9923 5 : v8::Local<v8::Object> global0 = context0->Global();
9924 :
9925 : // Define a property with JS getter and setter.
9926 : CompileRun(
9927 : "function getter() { return 'getter'; };\n"
9928 : "function setter() { return 'setter'; }\n"
9929 : "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9930 :
9931 : Local<Value> getter =
9932 15 : global0->Get(context0, v8_str("getter")).ToLocalChecked();
9933 : Local<Value> setter =
9934 15 : global0->Get(context0, v8_str("setter")).ToLocalChecked();
9935 :
9936 : // And define normal element.
9937 15 : CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
9938 :
9939 : // Define an element with JS getter and setter.
9940 : CompileRun(
9941 : "function el_getter() { return 'el_getter'; };\n"
9942 : "function el_setter() { return 'el_setter'; };\n"
9943 : "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9944 :
9945 : Local<Value> el_getter =
9946 15 : global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
9947 : Local<Value> el_setter =
9948 15 : global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
9949 :
9950 10 : v8::HandleScope scope1(isolate);
9951 :
9952 5 : v8::Local<Context> context1 = Context::New(isolate);
9953 5 : context1->Enter();
9954 :
9955 5 : v8::Local<v8::Object> global1 = context1->Global();
9956 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
9957 :
9958 : // Access blocked property.
9959 : CompileRun("other.blocked_prop = 1");
9960 :
9961 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
9962 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9963 : .IsEmpty());
9964 5 : CHECK(
9965 : CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9966 :
9967 : // Access blocked element.
9968 5 : CHECK(CompileRun("other[239] = 1").IsEmpty());
9969 :
9970 5 : CHECK(CompileRun("other[239]").IsEmpty());
9971 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9972 5 : CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9973 :
9974 5 : allowed_access = true;
9975 : // Now we can enumerate the property.
9976 : ExpectTrue("propertyIsEnumerable.call(other, '239')");
9977 5 : allowed_access = false;
9978 :
9979 : // Access a property with JS accessor.
9980 5 : CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9981 :
9982 5 : CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9983 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9984 : .IsEmpty());
9985 :
9986 5 : allowed_access = true;
9987 :
9988 5 : ExpectString("other.js_accessor_p", "getter");
9989 : ExpectObject(
9990 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9991 : ExpectObject(
9992 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9993 : ExpectUndefined(
9994 5 : "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9995 :
9996 5 : allowed_access = false;
9997 :
9998 : // Access an element with JS accessor.
9999 5 : CHECK(CompileRun("other[42] = 2").IsEmpty());
10000 :
10001 5 : CHECK(CompileRun("other[42]").IsEmpty());
10002 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10003 :
10004 5 : allowed_access = true;
10005 :
10006 5 : ExpectString("other[42]", "el_getter");
10007 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10008 5 : ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10009 5 : ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10010 :
10011 5 : allowed_access = false;
10012 :
10013 : v8::Local<Value> value;
10014 :
10015 : // Access accessible property
10016 : value = CompileRun("other.accessible_prop = 3");
10017 5 : CHECK(value->IsNumber());
10018 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10019 5 : CHECK_EQ(3, g_echo_value);
10020 :
10021 : value = CompileRun("other.accessible_prop");
10022 5 : CHECK(value->IsNumber());
10023 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10024 :
10025 : value = CompileRun(
10026 : "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10027 5 : CHECK(value->IsNumber());
10028 10 : CHECK_EQ(3, value->Int32Value(context1).FromJust());
10029 :
10030 : value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10031 5 : CHECK(value->IsTrue());
10032 :
10033 : // Enumeration doesn't enumerate accessors from inaccessible objects in
10034 : // the prototype chain even if the accessors are in themselves accessible.
10035 : // Enumeration doesn't throw, it silently ignores what it can't access.
10036 : value = CompileRun(
10037 : "(function() {"
10038 : " var obj = { '__proto__': other };"
10039 : " try {"
10040 : " for (var p in obj) {"
10041 : " if (p == 'accessible_prop' ||"
10042 : " p == 'blocked_js_prop' ||"
10043 : " p == 'blocked_js_prop') {"
10044 : " return false;"
10045 : " }"
10046 : " }"
10047 : " return true;"
10048 : " } catch (e) {"
10049 : " return false;"
10050 : " }"
10051 : "})()");
10052 5 : CHECK(value->IsTrue());
10053 :
10054 : // Test that preventExtensions fails on a non-accessible object even if that
10055 : // object is already non-extensible.
10056 20 : CHECK(global1->Set(context1, v8_str("checked_object"),
10057 : global_template->NewInstance(context1).ToLocalChecked())
10058 : .FromJust());
10059 5 : allowed_access = true;
10060 : CompileRun("Object.preventExtensions(checked_object)");
10061 : ExpectFalse("Object.isExtensible(checked_object)");
10062 5 : allowed_access = false;
10063 5 : CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10064 :
10065 5 : context1->Exit();
10066 10 : context0->Exit();
10067 5 : }
10068 :
10069 :
10070 23723 : TEST(AccessControlES5) {
10071 5 : v8::Isolate* isolate = CcTest::isolate();
10072 5 : v8::HandleScope handle_scope(isolate);
10073 : v8::Local<v8::ObjectTemplate> global_template =
10074 5 : v8::ObjectTemplate::New(isolate);
10075 :
10076 5 : global_template->SetAccessCheckCallback(AccessBlocker);
10077 :
10078 : // Add accessible accessor.
10079 : global_template->SetAccessor(
10080 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10081 5 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10082 :
10083 :
10084 : // Add an accessor that is not accessible by cross-domain JS code.
10085 : global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10086 : UnreachableSetter, v8::Local<Value>(),
10087 5 : v8::DEFAULT);
10088 :
10089 : // Create an environment
10090 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10091 5 : context0->Enter();
10092 :
10093 5 : v8::Local<v8::Object> global0 = context0->Global();
10094 :
10095 5 : v8::Local<Context> context1 = Context::New(isolate);
10096 5 : context1->Enter();
10097 5 : v8::Local<v8::Object> global1 = context1->Global();
10098 15 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10099 :
10100 : // Regression test for issue 1154.
10101 10 : CHECK(CompileRun("Object.keys(other).length == 1")
10102 : ->BooleanValue(context1)
10103 : .FromJust());
10104 10 : CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10105 : ->BooleanValue(context1)
10106 : .FromJust());
10107 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10108 :
10109 : // Regression test for issue 1027.
10110 : CompileRun("Object.defineProperty(\n"
10111 : " other, 'blocked_prop', {configurable: false})");
10112 5 : CHECK(CompileRun("other.blocked_prop").IsEmpty());
10113 5 : CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10114 : .IsEmpty());
10115 :
10116 : // Regression test for issue 1171.
10117 : ExpectTrue("Object.isExtensible(other)");
10118 : CompileRun("Object.preventExtensions(other)");
10119 : ExpectTrue("Object.isExtensible(other)");
10120 :
10121 : // Object.seal and Object.freeze.
10122 : CompileRun("Object.freeze(other)");
10123 : ExpectTrue("Object.isExtensible(other)");
10124 :
10125 : CompileRun("Object.seal(other)");
10126 : ExpectTrue("Object.isExtensible(other)");
10127 :
10128 : // Regression test for issue 1250.
10129 : // Make sure that we can set the accessible accessors value using normal
10130 : // assignment.
10131 : CompileRun("other.accessible_prop = 42");
10132 5 : CHECK_EQ(42, g_echo_value);
10133 :
10134 : // [[DefineOwnProperty]] always throws for access-checked objects.
10135 5 : CHECK(
10136 : CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10137 : .IsEmpty());
10138 5 : CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10139 5 : CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10140 5 : }
10141 :
10142 255 : static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10143 : Local<v8::Object> global,
10144 : Local<v8::Value> data) {
10145 255 : i::PrintF("Access blocked.\n");
10146 255 : return false;
10147 : }
10148 :
10149 5 : static bool AccessAlwaysAllowed(Local<v8::Context> accessing_context,
10150 : Local<v8::Object> global,
10151 : Local<v8::Value> data) {
10152 5 : i::PrintF("Access allowed.\n");
10153 5 : return true;
10154 : }
10155 :
10156 23724 : THREADED_TEST(AccessControlGetOwnPropertyNames) {
10157 6 : v8::Isolate* isolate = CcTest::isolate();
10158 6 : v8::HandleScope handle_scope(isolate);
10159 6 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10160 :
10161 18 : obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10162 6 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10163 :
10164 : // Add an accessor accessible by cross-domain JS code.
10165 : obj_template->SetAccessor(
10166 : v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10167 6 : v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10168 :
10169 : // Create an environment
10170 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
10171 6 : context0->Enter();
10172 :
10173 6 : v8::Local<v8::Object> global0 = context0->Global();
10174 :
10175 12 : v8::HandleScope scope1(CcTest::isolate());
10176 :
10177 6 : v8::Local<Context> context1 = Context::New(isolate);
10178 6 : context1->Enter();
10179 :
10180 6 : v8::Local<v8::Object> global1 = context1->Global();
10181 18 : CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10182 24 : CHECK(global1->Set(context1, v8_str("object"),
10183 : obj_template->NewInstance(context1).ToLocalChecked())
10184 : .FromJust());
10185 :
10186 : v8::Local<Value> value;
10187 :
10188 : // Attempt to get the property names of the other global object and
10189 : // of an object that requires access checks. Accessing the other
10190 : // global object should be blocked by access checks on the global
10191 : // proxy object. Accessing the object that requires access checks
10192 : // is blocked by the access checks on the object itself.
10193 : value = CompileRun(
10194 : "var names = Object.getOwnPropertyNames(other);"
10195 : "names.length == 1 && names[0] == 'accessible_prop';");
10196 12 : CHECK(value->BooleanValue(context1).FromJust());
10197 :
10198 : value = CompileRun(
10199 : "var names = Object.getOwnPropertyNames(object);"
10200 : "names.length == 1 && names[0] == 'accessible_prop';");
10201 12 : CHECK(value->BooleanValue(context1).FromJust());
10202 :
10203 6 : context1->Exit();
10204 12 : context0->Exit();
10205 6 : }
10206 :
10207 :
10208 23723 : TEST(Regress470113) {
10209 5 : v8::Isolate* isolate = CcTest::isolate();
10210 5 : v8::HandleScope handle_scope(isolate);
10211 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10212 5 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10213 10 : LocalContext env;
10214 30 : CHECK(env->Global()
10215 : ->Set(env.local(), v8_str("prohibited"),
10216 : obj_template->NewInstance(env.local()).ToLocalChecked())
10217 : .FromJust());
10218 :
10219 : {
10220 5 : v8::TryCatch try_catch(isolate);
10221 : CompileRun(
10222 : "'use strict';\n"
10223 : "class C extends Object {\n"
10224 : " m() { super.powned = 'Powned!'; }\n"
10225 : "}\n"
10226 : "let c = new C();\n"
10227 : "c.m.call(prohibited)");
10228 :
10229 5 : CHECK(try_catch.HasCaught());
10230 5 : }
10231 5 : }
10232 :
10233 :
10234 6 : static void ConstTenGetter(Local<String> name,
10235 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10236 6 : info.GetReturnValue().Set(v8_num(10));
10237 6 : }
10238 :
10239 :
10240 23724 : THREADED_TEST(CrossDomainAccessors) {
10241 6 : v8::Isolate* isolate = CcTest::isolate();
10242 6 : v8::HandleScope handle_scope(isolate);
10243 :
10244 : v8::Local<v8::FunctionTemplate> func_template =
10245 6 : v8::FunctionTemplate::New(isolate);
10246 :
10247 : v8::Local<v8::ObjectTemplate> global_template =
10248 6 : func_template->InstanceTemplate();
10249 :
10250 : v8::Local<v8::ObjectTemplate> proto_template =
10251 6 : func_template->PrototypeTemplate();
10252 :
10253 : // Add an accessor to proto that's accessible by cross-domain JS code.
10254 : proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, 0,
10255 12 : v8::Local<Value>(), v8::ALL_CAN_READ);
10256 :
10257 : // Add an accessor that is not accessible by cross-domain JS code.
10258 : global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter, 0,
10259 12 : v8::Local<Value>(), v8::DEFAULT);
10260 :
10261 6 : v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10262 6 : context0->Enter();
10263 :
10264 6 : Local<v8::Object> global = context0->Global();
10265 : // Add a normal property that shadows 'accessible'
10266 18 : CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10267 :
10268 : // Enter a new context.
10269 12 : v8::HandleScope scope1(CcTest::isolate());
10270 6 : v8::Local<Context> context1 = Context::New(isolate);
10271 6 : context1->Enter();
10272 :
10273 6 : v8::Local<v8::Object> global1 = context1->Global();
10274 18 : CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10275 :
10276 : // Should return 10, instead of 11
10277 : v8::Local<Value> value =
10278 6 : v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10279 6 : CHECK(value->IsNumber());
10280 12 : CHECK_EQ(10, value->Int32Value(context1).FromJust());
10281 :
10282 : v8::MaybeLocal<v8::Value> maybe_value =
10283 6 : v8_compile("other.unreachable")->Run(context1);
10284 6 : CHECK(maybe_value.IsEmpty());
10285 :
10286 6 : context1->Exit();
10287 12 : context0->Exit();
10288 6 : }
10289 :
10290 :
10291 : static int access_count = 0;
10292 :
10293 825 : static bool AccessCounter(Local<v8::Context> accessing_context,
10294 : Local<v8::Object> accessed_object,
10295 : Local<v8::Value> data) {
10296 825 : access_count++;
10297 825 : return true;
10298 : }
10299 :
10300 :
10301 : // This one is too easily disturbed by other tests.
10302 23723 : TEST(AccessControlIC) {
10303 5 : access_count = 0;
10304 :
10305 5 : v8::Isolate* isolate = CcTest::isolate();
10306 5 : v8::HandleScope handle_scope(isolate);
10307 :
10308 : // Create an environment.
10309 5 : v8::Local<Context> context0 = Context::New(isolate);
10310 5 : context0->Enter();
10311 :
10312 : // Create an object that requires access-check functions to be
10313 : // called for cross-domain access.
10314 : v8::Local<v8::ObjectTemplate> object_template =
10315 5 : v8::ObjectTemplate::New(isolate);
10316 5 : object_template->SetAccessCheckCallback(AccessCounter);
10317 : Local<v8::Object> object =
10318 5 : object_template->NewInstance(context0).ToLocalChecked();
10319 :
10320 10 : v8::HandleScope scope1(isolate);
10321 :
10322 : // Create another environment.
10323 5 : v8::Local<Context> context1 = Context::New(isolate);
10324 5 : context1->Enter();
10325 :
10326 : // Make easy access to the object from the other environment.
10327 5 : v8::Local<v8::Object> global1 = context1->Global();
10328 15 : CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10329 :
10330 : v8::Local<Value> value;
10331 :
10332 : // Check that the named access-control function is called every time.
10333 : CompileRun("function testProp(obj) {"
10334 : " for (var i = 0; i < 10; i++) obj.prop = 1;"
10335 : " for (var j = 0; j < 10; j++) obj.prop;"
10336 : " return obj.prop"
10337 : "}");
10338 : value = CompileRun("testProp(obj)");
10339 5 : CHECK(value->IsNumber());
10340 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10341 5 : CHECK_EQ(21, access_count);
10342 :
10343 : // Check that the named access-control function is called every time.
10344 : CompileRun("var p = 'prop';"
10345 : "function testKeyed(obj) {"
10346 : " for (var i = 0; i < 10; i++) obj[p] = 1;"
10347 : " for (var j = 0; j < 10; j++) obj[p];"
10348 : " return obj[p];"
10349 : "}");
10350 : // Use obj which requires access checks. No inline caching is used
10351 : // in that case.
10352 : value = CompileRun("testKeyed(obj)");
10353 5 : CHECK(value->IsNumber());
10354 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10355 5 : CHECK_EQ(42, access_count);
10356 : // Force the inline caches into generic state and try again.
10357 : CompileRun("testKeyed({ a: 0 })");
10358 : CompileRun("testKeyed({ b: 0 })");
10359 : value = CompileRun("testKeyed(obj)");
10360 5 : CHECK(value->IsNumber());
10361 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10362 5 : CHECK_EQ(63, access_count);
10363 :
10364 : // Check that the indexed access-control function is called every time.
10365 5 : access_count = 0;
10366 :
10367 : CompileRun("function testIndexed(obj) {"
10368 : " for (var i = 0; i < 10; i++) obj[0] = 1;"
10369 : " for (var j = 0; j < 10; j++) obj[0];"
10370 : " return obj[0]"
10371 : "}");
10372 : value = CompileRun("testIndexed(obj)");
10373 5 : CHECK(value->IsNumber());
10374 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10375 5 : CHECK_EQ(21, access_count);
10376 : // Force the inline caches into generic state.
10377 : CompileRun("testIndexed(new Array(1))");
10378 : // Test that the indexed access check is called.
10379 : value = CompileRun("testIndexed(obj)");
10380 5 : CHECK(value->IsNumber());
10381 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10382 5 : CHECK_EQ(42, access_count);
10383 :
10384 5 : access_count = 0;
10385 : // Check that the named access check is called when invoking
10386 : // functions on an object that requires access checks.
10387 : CompileRun("obj.f = function() {}");
10388 : CompileRun("function testCallNormal(obj) {"
10389 : " for (var i = 0; i < 10; i++) obj.f();"
10390 : "}");
10391 : CompileRun("testCallNormal(obj)");
10392 5 : printf("%i\n", access_count);
10393 5 : CHECK_EQ(11, access_count);
10394 :
10395 : // Force obj into slow case.
10396 : value = CompileRun("delete obj.prop");
10397 10 : CHECK(value->BooleanValue(context1).FromJust());
10398 : // Force inline caches into dictionary probing mode.
10399 : CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10400 : // Test that the named access check is called.
10401 : value = CompileRun("testProp(obj);");
10402 5 : CHECK(value->IsNumber());
10403 10 : CHECK_EQ(1, value->Int32Value(context1).FromJust());
10404 5 : CHECK_EQ(33, access_count);
10405 :
10406 : // Force the call inline cache into dictionary probing mode.
10407 : CompileRun("o.f = function() {}; testCallNormal(o)");
10408 : // Test that the named access check is still called for each
10409 : // invocation of the function.
10410 : value = CompileRun("testCallNormal(obj)");
10411 5 : CHECK_EQ(43, access_count);
10412 :
10413 5 : context1->Exit();
10414 10 : context0->Exit();
10415 5 : }
10416 :
10417 :
10418 23724 : THREADED_TEST(Version) { v8::V8::GetVersion(); }
10419 :
10420 :
10421 18 : static void InstanceFunctionCallback(
10422 18 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10423 18 : ApiTestFuzzer::Fuzz();
10424 18 : args.GetReturnValue().Set(v8_num(12));
10425 18 : }
10426 :
10427 :
10428 23724 : THREADED_TEST(InstanceProperties) {
10429 6 : LocalContext context;
10430 6 : v8::Isolate* isolate = context->GetIsolate();
10431 12 : v8::HandleScope handle_scope(isolate);
10432 :
10433 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10434 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10435 :
10436 18 : instance->Set(v8_str("x"), v8_num(42));
10437 : instance->Set(v8_str("f"),
10438 18 : v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10439 :
10440 6 : Local<Value> o = t->GetFunction(context.local())
10441 6 : .ToLocalChecked()
10442 6 : ->NewInstance(context.local())
10443 : .ToLocalChecked();
10444 :
10445 30 : CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10446 : Local<Value> value = CompileRun("i.x");
10447 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10448 :
10449 : value = CompileRun("i.f()");
10450 18 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10451 6 : }
10452 :
10453 :
10454 696 : static void GlobalObjectInstancePropertiesGet(
10455 : Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10456 696 : ApiTestFuzzer::Fuzz();
10457 696 : }
10458 :
10459 :
10460 23724 : THREADED_TEST(GlobalObjectInstanceProperties) {
10461 6 : v8::Isolate* isolate = CcTest::isolate();
10462 6 : v8::HandleScope handle_scope(isolate);
10463 :
10464 : Local<Value> global_object;
10465 :
10466 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10467 : t->InstanceTemplate()->SetHandler(
10468 12 : v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10469 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10470 18 : instance_template->Set(v8_str("x"), v8_num(42));
10471 : instance_template->Set(v8_str("f"),
10472 : v8::FunctionTemplate::New(isolate,
10473 18 : InstanceFunctionCallback));
10474 :
10475 : // The script to check how Crankshaft compiles missing global function
10476 : // invocations. function g is not defined and should throw on call.
10477 : const char* script =
10478 : "function wrapper(call) {"
10479 : " var x = 0, y = 1;"
10480 : " for (var i = 0; i < 1000; i++) {"
10481 : " x += i * 100;"
10482 : " y += i * 100;"
10483 : " }"
10484 : " if (call) g();"
10485 : "}"
10486 : "for (var i = 0; i < 17; i++) wrapper(false);"
10487 : "var thrown = 0;"
10488 : "try { wrapper(true); } catch (e) { thrown = 1; };"
10489 : "thrown";
10490 :
10491 : {
10492 6 : LocalContext env(nullptr, instance_template);
10493 : // Hold on to the global object so it can be used again in another
10494 : // environment initialization.
10495 6 : global_object = env->Global();
10496 :
10497 : Local<Value> value = CompileRun("x");
10498 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10499 : value = CompileRun("f()");
10500 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10501 : value = CompileRun(script);
10502 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10503 : }
10504 :
10505 : {
10506 : // Create new environment reusing the global object.
10507 6 : LocalContext env(nullptr, instance_template, global_object);
10508 : Local<Value> value = CompileRun("x");
10509 12 : CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10510 : value = CompileRun("f()");
10511 12 : CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10512 : value = CompileRun(script);
10513 12 : CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10514 6 : }
10515 6 : }
10516 :
10517 23724 : THREADED_TEST(ObjectGetOwnPropertyNames) {
10518 6 : LocalContext context;
10519 6 : v8::Isolate* isolate = context->GetIsolate();
10520 12 : v8::HandleScope handle_scope(isolate);
10521 :
10522 : v8::Local<v8::Object> value =
10523 6 : v8::Local<v8::Object>::Cast(v8::StringObject::New(v8_str("test")));
10524 : v8::Local<v8::Array> properties;
10525 :
10526 12 : CHECK(value
10527 : ->GetOwnPropertyNames(context.local(),
10528 : static_cast<v8::PropertyFilter>(
10529 : v8::PropertyFilter::ALL_PROPERTIES |
10530 : v8::PropertyFilter::SKIP_SYMBOLS))
10531 : .ToLocal(&properties));
10532 6 : CHECK_EQ(5u, properties->Length());
10533 : v8::Local<v8::Value> property;
10534 18 : CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10535 : property->IsString());
10536 18 : CHECK(property.As<v8::String>()
10537 : ->Equals(context.local(), v8_str("length"))
10538 : .FromMaybe(false));
10539 24 : for (int i = 0; i < 4; ++i) {
10540 : v8::Local<v8::Value> property;
10541 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10542 : property->IsInt32());
10543 24 : CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10544 : }
10545 :
10546 12 : CHECK(value->GetOwnPropertyNames(context.local(), v8::ONLY_ENUMERABLE)
10547 : .ToLocal(&properties));
10548 6 : CHECK_EQ(4u, properties->Length());
10549 24 : for (int i = 0; i < 4; ++i) {
10550 : v8::Local<v8::Value> property;
10551 48 : CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10552 : property->IsInt32());
10553 24 : CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10554 : }
10555 :
10556 6 : value = value->GetPrototype().As<v8::Object>();
10557 12 : CHECK(value
10558 : ->GetOwnPropertyNames(context.local(),
10559 : static_cast<v8::PropertyFilter>(
10560 : v8::PropertyFilter::ALL_PROPERTIES |
10561 : v8::PropertyFilter::SKIP_SYMBOLS))
10562 : .ToLocal(&properties));
10563 : bool concat_found = false;
10564 : bool starts_with_found = false;
10565 270 : for (uint32_t i = 0; i < properties->Length(); ++i) {
10566 : v8::Local<v8::Value> property;
10567 540 : CHECK(properties->Get(context.local(), i).ToLocal(&property));
10568 270 : if (!property->IsString()) continue;
10569 270 : if (!concat_found)
10570 : concat_found = property.As<v8::String>()
10571 180 : ->Equals(context.local(), v8_str("concat"))
10572 120 : .FromMaybe(false);
10573 270 : if (!starts_with_found)
10574 : starts_with_found = property.As<v8::String>()
10575 648 : ->Equals(context.local(), v8_str("startsWith"))
10576 432 : .FromMaybe(false);
10577 : }
10578 12 : CHECK(concat_found && starts_with_found);
10579 6 : }
10580 :
10581 23724 : THREADED_TEST(CallKnownGlobalReceiver) {
10582 6 : v8::Isolate* isolate = CcTest::isolate();
10583 6 : v8::HandleScope handle_scope(isolate);
10584 :
10585 : Local<Value> global_object;
10586 :
10587 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10588 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10589 :
10590 : // The script to check that we leave global object not
10591 : // global object proxy on stack when we deoptimize from inside
10592 : // arguments evaluation.
10593 : // To provoke error we need to both force deoptimization
10594 : // from arguments evaluation and to force CallIC to take
10595 : // CallIC_Miss code path that can't cope with global proxy.
10596 : const char* script =
10597 : "function bar(x, y) { try { } finally { } }"
10598 : "function baz(x) { try { } finally { } }"
10599 : "function bom(x) { try { } finally { } }"
10600 : "function foo(x) { bar([x], bom(2)); }"
10601 : "for (var i = 0; i < 10000; i++) foo(1);"
10602 : "foo";
10603 :
10604 : Local<Value> foo;
10605 : {
10606 6 : LocalContext env(nullptr, instance_template);
10607 : // Hold on to the global object so it can be used again in another
10608 : // environment initialization.
10609 6 : global_object = env->Global();
10610 6 : foo = CompileRun(script);
10611 : }
10612 :
10613 : {
10614 : // Create new environment reusing the global object.
10615 6 : LocalContext env(nullptr, instance_template, global_object);
10616 30 : CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10617 6 : CompileRun("foo()");
10618 6 : }
10619 6 : }
10620 :
10621 :
10622 6 : static void ShadowFunctionCallback(
10623 6 : const v8::FunctionCallbackInfo<v8::Value>& args) {
10624 6 : ApiTestFuzzer::Fuzz();
10625 6 : args.GetReturnValue().Set(v8_num(42));
10626 6 : }
10627 :
10628 :
10629 : static int shadow_y;
10630 : static int shadow_y_setter_call_count;
10631 : static int shadow_y_getter_call_count;
10632 :
10633 :
10634 6 : static void ShadowYSetter(Local<String>,
10635 : Local<Value>,
10636 : const v8::PropertyCallbackInfo<void>&) {
10637 6 : shadow_y_setter_call_count++;
10638 6 : shadow_y = 42;
10639 6 : }
10640 :
10641 :
10642 6 : static void ShadowYGetter(Local<String> name,
10643 : const v8::PropertyCallbackInfo<v8::Value>& info) {
10644 6 : ApiTestFuzzer::Fuzz();
10645 6 : shadow_y_getter_call_count++;
10646 6 : info.GetReturnValue().Set(v8_num(shadow_y));
10647 6 : }
10648 :
10649 :
10650 0 : static void ShadowIndexedGet(uint32_t index,
10651 : const v8::PropertyCallbackInfo<v8::Value>&) {
10652 0 : }
10653 :
10654 :
10655 30 : static void ShadowNamedGet(Local<Name> key,
10656 30 : const v8::PropertyCallbackInfo<v8::Value>&) {}
10657 :
10658 :
10659 23724 : THREADED_TEST(ShadowObject) {
10660 6 : shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10661 6 : v8::Isolate* isolate = CcTest::isolate();
10662 6 : v8::HandleScope handle_scope(isolate);
10663 :
10664 6 : Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10665 12 : LocalContext context(nullptr, global_template);
10666 :
10667 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10668 : t->InstanceTemplate()->SetHandler(
10669 12 : v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10670 : t->InstanceTemplate()->SetHandler(
10671 12 : v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10672 6 : Local<ObjectTemplate> proto = t->PrototypeTemplate();
10673 6 : Local<ObjectTemplate> instance = t->InstanceTemplate();
10674 :
10675 : proto->Set(v8_str("f"),
10676 : v8::FunctionTemplate::New(isolate,
10677 : ShadowFunctionCallback,
10678 18 : Local<Value>()));
10679 18 : proto->Set(v8_str("x"), v8_num(12));
10680 :
10681 12 : instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10682 :
10683 6 : Local<Value> o = t->GetFunction(context.local())
10684 6 : .ToLocalChecked()
10685 6 : ->NewInstance(context.local())
10686 : .ToLocalChecked();
10687 30 : CHECK(context->Global()
10688 : ->Set(context.local(), v8_str("__proto__"), o)
10689 : .FromJust());
10690 :
10691 : Local<Value> value =
10692 : CompileRun("this.propertyIsEnumerable(0)");
10693 6 : CHECK(value->IsBoolean());
10694 12 : CHECK(!value->BooleanValue(context.local()).FromJust());
10695 :
10696 : value = CompileRun("x");
10697 12 : CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10698 :
10699 : value = CompileRun("f()");
10700 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10701 :
10702 : CompileRun("y = 43");
10703 6 : CHECK_EQ(1, shadow_y_setter_call_count);
10704 : value = CompileRun("y");
10705 6 : CHECK_EQ(1, shadow_y_getter_call_count);
10706 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10707 6 : }
10708 :
10709 :
10710 23724 : THREADED_TEST(HiddenPrototype) {
10711 6 : LocalContext context;
10712 6 : v8::Isolate* isolate = context->GetIsolate();
10713 12 : v8::HandleScope handle_scope(isolate);
10714 :
10715 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10716 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10717 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10718 6 : t1->SetHiddenPrototype(true);
10719 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10720 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10721 6 : t2->SetHiddenPrototype(true);
10722 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10723 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10724 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10725 :
10726 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
10727 6 : .ToLocalChecked()
10728 6 : ->NewInstance(context.local())
10729 : .ToLocalChecked();
10730 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
10731 6 : .ToLocalChecked()
10732 6 : ->NewInstance(context.local())
10733 : .ToLocalChecked();
10734 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
10735 6 : .ToLocalChecked()
10736 6 : ->NewInstance(context.local())
10737 : .ToLocalChecked();
10738 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
10739 6 : .ToLocalChecked()
10740 6 : ->NewInstance(context.local())
10741 : .ToLocalChecked();
10742 :
10743 : // Setting the prototype on an object skips hidden prototypes.
10744 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10745 : .ToLocalChecked()
10746 : ->Int32Value(context.local())
10747 : .FromJust());
10748 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o1).FromJust());
10749 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10750 : .ToLocalChecked()
10751 : ->Int32Value(context.local())
10752 : .FromJust());
10753 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10754 : .ToLocalChecked()
10755 : ->Int32Value(context.local())
10756 : .FromJust());
10757 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o2).FromJust());
10758 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10759 : .ToLocalChecked()
10760 : ->Int32Value(context.local())
10761 : .FromJust());
10762 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10763 : .ToLocalChecked()
10764 : ->Int32Value(context.local())
10765 : .FromJust());
10766 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10767 : .ToLocalChecked()
10768 : ->Int32Value(context.local())
10769 : .FromJust());
10770 18 : CHECK(o0->Set(context.local(), v8_str("__proto__"), o3).FromJust());
10771 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10772 : .ToLocalChecked()
10773 : ->Int32Value(context.local())
10774 : .FromJust());
10775 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10776 : .ToLocalChecked()
10777 : ->Int32Value(context.local())
10778 : .FromJust());
10779 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10780 : .ToLocalChecked()
10781 : ->Int32Value(context.local())
10782 : .FromJust());
10783 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
10784 : .ToLocalChecked()
10785 : ->Int32Value(context.local())
10786 : .FromJust());
10787 :
10788 : // Getting the prototype of o0 should get the first visible one
10789 : // which is o3. Therefore, z should not be defined on the prototype
10790 : // object.
10791 : Local<Value> proto =
10792 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
10793 6 : CHECK(proto->IsObject());
10794 18 : CHECK(proto.As<v8::Object>()
10795 : ->Get(context.local(), v8_str("z"))
10796 : .ToLocalChecked()
10797 6 : ->IsUndefined());
10798 6 : }
10799 :
10800 :
10801 23724 : THREADED_TEST(HiddenPrototypeSet) {
10802 6 : LocalContext context;
10803 6 : v8::Isolate* isolate = context->GetIsolate();
10804 12 : v8::HandleScope handle_scope(isolate);
10805 :
10806 6 : Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10807 6 : Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10808 6 : ht->SetHiddenPrototype(true);
10809 6 : Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10810 24 : ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10811 :
10812 6 : Local<v8::Object> o = ot->GetFunction(context.local())
10813 6 : .ToLocalChecked()
10814 6 : ->NewInstance(context.local())
10815 : .ToLocalChecked();
10816 6 : Local<v8::Object> h = ht->GetFunction(context.local())
10817 6 : .ToLocalChecked()
10818 6 : ->NewInstance(context.local())
10819 : .ToLocalChecked();
10820 6 : Local<v8::Object> p = pt->GetFunction(context.local())
10821 6 : .ToLocalChecked()
10822 6 : ->NewInstance(context.local())
10823 : .ToLocalChecked();
10824 18 : CHECK(o->Set(context.local(), v8_str("__proto__"), h).FromJust());
10825 18 : CHECK(h->Set(context.local(), v8_str("__proto__"), p).FromJust());
10826 :
10827 : // Setting a property that exists on the hidden prototype goes there.
10828 18 : CHECK(o->Set(context.local(), v8_str("x"), v8_num(7)).FromJust());
10829 24 : CHECK_EQ(7, o->Get(context.local(), v8_str("x"))
10830 : .ToLocalChecked()
10831 : ->Int32Value(context.local())
10832 : .FromJust());
10833 24 : CHECK_EQ(7, h->Get(context.local(), v8_str("x"))
10834 : .ToLocalChecked()
10835 : ->Int32Value(context.local())
10836 : .FromJust());
10837 18 : CHECK(p->Get(context.local(), v8_str("x")).ToLocalChecked()->IsUndefined());
10838 :
10839 : // Setting a new property should not be forwarded to the hidden prototype.
10840 18 : CHECK(o->Set(context.local(), v8_str("y"), v8_num(6)).FromJust());
10841 24 : CHECK_EQ(6, o->Get(context.local(), v8_str("y"))
10842 : .ToLocalChecked()
10843 : ->Int32Value(context.local())
10844 : .FromJust());
10845 18 : CHECK(h->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
10846 18 : CHECK(p->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
10847 :
10848 : // Setting a property that only exists on a prototype of the hidden prototype
10849 : // is treated normally again.
10850 18 : CHECK(p->Set(context.local(), v8_str("z"), v8_num(8)).FromJust());
10851 24 : CHECK_EQ(8, o->Get(context.local(), v8_str("z"))
10852 : .ToLocalChecked()
10853 : ->Int32Value(context.local())
10854 : .FromJust());
10855 24 : CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
10856 : .ToLocalChecked()
10857 : ->Int32Value(context.local())
10858 : .FromJust());
10859 24 : CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
10860 : .ToLocalChecked()
10861 : ->Int32Value(context.local())
10862 : .FromJust());
10863 18 : CHECK(o->Set(context.local(), v8_str("z"), v8_num(9)).FromJust());
10864 24 : CHECK_EQ(9, o->Get(context.local(), v8_str("z"))
10865 : .ToLocalChecked()
10866 : ->Int32Value(context.local())
10867 : .FromJust());
10868 24 : CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
10869 : .ToLocalChecked()
10870 : ->Int32Value(context.local())
10871 : .FromJust());
10872 24 : CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
10873 : .ToLocalChecked()
10874 : ->Int32Value(context.local())
10875 6 : .FromJust());
10876 6 : }
10877 :
10878 :
10879 : // Regression test for issue 2457.
10880 23724 : THREADED_TEST(HiddenPrototypeIdentityHash) {
10881 6 : LocalContext context;
10882 12 : v8::HandleScope handle_scope(context->GetIsolate());
10883 :
10884 6 : Local<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10885 6 : t->SetHiddenPrototype(true);
10886 24 : t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10887 6 : Local<Object> p = t->GetFunction(context.local())
10888 6 : .ToLocalChecked()
10889 6 : ->NewInstance(context.local())
10890 : .ToLocalChecked();
10891 6 : Local<Object> o = Object::New(context->GetIsolate());
10892 12 : CHECK(o->SetPrototype(context.local(), p).FromJust());
10893 :
10894 6 : int hash = o->GetIdentityHash();
10895 : USE(hash);
10896 18 : CHECK(o->Set(context.local(), v8_str("foo"), v8_num(42)).FromJust());
10897 12 : CHECK_EQ(hash, o->GetIdentityHash());
10898 6 : }
10899 :
10900 :
10901 23724 : THREADED_TEST(SetPrototype) {
10902 6 : LocalContext context;
10903 6 : v8::Isolate* isolate = context->GetIsolate();
10904 12 : v8::HandleScope handle_scope(isolate);
10905 :
10906 6 : Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10907 24 : t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10908 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10909 6 : t1->SetHiddenPrototype(true);
10910 24 : t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10911 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10912 6 : t2->SetHiddenPrototype(true);
10913 24 : t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10914 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10915 24 : t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10916 :
10917 6 : Local<v8::Object> o0 = t0->GetFunction(context.local())
10918 6 : .ToLocalChecked()
10919 6 : ->NewInstance(context.local())
10920 : .ToLocalChecked();
10921 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
10922 6 : .ToLocalChecked()
10923 6 : ->NewInstance(context.local())
10924 : .ToLocalChecked();
10925 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
10926 6 : .ToLocalChecked()
10927 6 : ->NewInstance(context.local())
10928 : .ToLocalChecked();
10929 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
10930 6 : .ToLocalChecked()
10931 6 : ->NewInstance(context.local())
10932 : .ToLocalChecked();
10933 :
10934 : // Setting the prototype on an object does not skip hidden prototypes.
10935 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10936 : .ToLocalChecked()
10937 : ->Int32Value(context.local())
10938 : .FromJust());
10939 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
10940 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10941 : .ToLocalChecked()
10942 : ->Int32Value(context.local())
10943 : .FromJust());
10944 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10945 : .ToLocalChecked()
10946 : ->Int32Value(context.local())
10947 : .FromJust());
10948 12 : CHECK(o1->SetPrototype(context.local(), o2).FromJust());
10949 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10950 : .ToLocalChecked()
10951 : ->Int32Value(context.local())
10952 : .FromJust());
10953 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10954 : .ToLocalChecked()
10955 : ->Int32Value(context.local())
10956 : .FromJust());
10957 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10958 : .ToLocalChecked()
10959 : ->Int32Value(context.local())
10960 : .FromJust());
10961 12 : CHECK(o2->SetPrototype(context.local(), o3).FromJust());
10962 24 : CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10963 : .ToLocalChecked()
10964 : ->Int32Value(context.local())
10965 : .FromJust());
10966 24 : CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10967 : .ToLocalChecked()
10968 : ->Int32Value(context.local())
10969 : .FromJust());
10970 24 : CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10971 : .ToLocalChecked()
10972 : ->Int32Value(context.local())
10973 : .FromJust());
10974 24 : CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
10975 : .ToLocalChecked()
10976 : ->Int32Value(context.local())
10977 : .FromJust());
10978 :
10979 : // Getting the prototype of o0 should get the first visible one
10980 : // which is o3. Therefore, z should not be defined on the prototype
10981 : // object.
10982 : Local<Value> proto =
10983 18 : o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
10984 6 : CHECK(proto->IsObject());
10985 12 : CHECK(proto.As<v8::Object>()->Equals(context.local(), o3).FromJust());
10986 :
10987 : // However, Object::GetPrototype ignores hidden prototype.
10988 6 : Local<Value> proto0 = o0->GetPrototype();
10989 6 : CHECK(proto0->IsObject());
10990 12 : CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
10991 :
10992 6 : Local<Value> proto1 = o1->GetPrototype();
10993 6 : CHECK(proto1->IsObject());
10994 12 : CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
10995 :
10996 6 : Local<Value> proto2 = o2->GetPrototype();
10997 6 : CHECK(proto2->IsObject());
10998 18 : CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
10999 6 : }
11000 :
11001 :
11002 : // Getting property names of an object with a prototype chain that
11003 : // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11004 : // crash the runtime.
11005 23724 : THREADED_TEST(Regress91517) {
11006 6 : i::FLAG_allow_natives_syntax = true;
11007 6 : LocalContext context;
11008 6 : v8::Isolate* isolate = context->GetIsolate();
11009 12 : v8::HandleScope handle_scope(isolate);
11010 :
11011 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11012 6 : t1->SetHiddenPrototype(true);
11013 24 : t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11014 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11015 6 : t2->SetHiddenPrototype(true);
11016 24 : t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11017 12 : t2->InstanceTemplate()->Set(v8_str("objects"),
11018 24 : v8::ObjectTemplate::New(isolate));
11019 24 : t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11020 6 : Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11021 6 : t3->SetHiddenPrototype(true);
11022 24 : t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11023 6 : Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11024 24 : t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11025 :
11026 : // Force dictionary-based properties.
11027 : i::ScopedVector<char> name_buf(1024);
11028 6006 : for (int i = 1; i <= 1000; i++) {
11029 6000 : i::SNPrintF(name_buf, "sdf%d", i);
11030 24000 : t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11031 : }
11032 :
11033 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11034 6 : .ToLocalChecked()
11035 6 : ->NewInstance(context.local())
11036 : .ToLocalChecked();
11037 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11038 6 : .ToLocalChecked()
11039 6 : ->NewInstance(context.local())
11040 : .ToLocalChecked();
11041 6 : Local<v8::Object> o3 = t3->GetFunction(context.local())
11042 6 : .ToLocalChecked()
11043 6 : ->NewInstance(context.local())
11044 : .ToLocalChecked();
11045 6 : Local<v8::Object> o4 = t4->GetFunction(context.local())
11046 6 : .ToLocalChecked()
11047 6 : ->NewInstance(context.local())
11048 : .ToLocalChecked();
11049 :
11050 : // Create prototype chain of hidden prototypes.
11051 12 : CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11052 12 : CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11053 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11054 :
11055 : // Call the runtime version of GetOwnPropertyNames() on the natively
11056 : // created object through JavaScript.
11057 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11058 : // PROPERTY_FILTER_NONE = 0
11059 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11060 :
11061 6 : ExpectInt32("names.length", 1006);
11062 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11063 : ExpectTrue("names.indexOf(\"boo\") >= 0");
11064 : ExpectTrue("names.indexOf(\"foo\") >= 0");
11065 : ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11066 : ExpectTrue("names.indexOf(\"objects\") >= 0");
11067 : ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11068 6 : ExpectFalse("names[1005] == undefined");
11069 6 : }
11070 :
11071 :
11072 : // Getting property names of an object with a hidden and inherited
11073 : // prototype should not duplicate the accessor properties inherited.
11074 23724 : THREADED_TEST(Regress269562) {
11075 6 : i::FLAG_allow_natives_syntax = true;
11076 6 : LocalContext context;
11077 12 : v8::HandleScope handle_scope(context->GetIsolate());
11078 :
11079 : Local<v8::FunctionTemplate> t1 =
11080 6 : v8::FunctionTemplate::New(context->GetIsolate());
11081 6 : t1->SetHiddenPrototype(true);
11082 :
11083 6 : Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11084 : i1->SetAccessor(v8_str("foo"),
11085 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11086 : i1->SetAccessor(v8_str("bar"),
11087 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11088 : i1->SetAccessor(v8_str("baz"),
11089 6 : SimpleAccessorGetter, SimpleAccessorSetter);
11090 18 : i1->Set(v8_str("n1"), v8_num(1));
11091 18 : i1->Set(v8_str("n2"), v8_num(2));
11092 :
11093 6 : Local<v8::Object> o1 = t1->GetFunction(context.local())
11094 6 : .ToLocalChecked()
11095 6 : ->NewInstance(context.local())
11096 : .ToLocalChecked();
11097 : Local<v8::FunctionTemplate> t2 =
11098 6 : v8::FunctionTemplate::New(context->GetIsolate());
11099 6 : t2->SetHiddenPrototype(true);
11100 :
11101 : // Inherit from t1 and mark prototype as hidden.
11102 6 : t2->Inherit(t1);
11103 24 : t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11104 :
11105 6 : Local<v8::Object> o2 = t2->GetFunction(context.local())
11106 6 : .ToLocalChecked()
11107 6 : ->NewInstance(context.local())
11108 : .ToLocalChecked();
11109 12 : CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11110 :
11111 : v8::Local<v8::Symbol> sym =
11112 12 : v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11113 18 : CHECK(o1->Set(context.local(), sym, v8_num(3)).FromJust());
11114 : o1->SetPrivate(context.local(),
11115 : v8::Private::New(context->GetIsolate(), v8_str("h1")),
11116 24 : v8::Integer::New(context->GetIsolate(), 2013))
11117 12 : .FromJust();
11118 :
11119 : // Call the runtime version of GetOwnPropertyNames() on
11120 : // the natively created object through JavaScript.
11121 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), o2).FromJust());
11122 30 : CHECK(context->Global()->Set(context.local(), v8_str("sym"), sym).FromJust());
11123 : // PROPERTY_FILTER_NONE = 0
11124 : CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11125 :
11126 6 : ExpectInt32("names.length", 7);
11127 : ExpectTrue("names.indexOf(\"foo\") >= 0");
11128 : ExpectTrue("names.indexOf(\"bar\") >= 0");
11129 : ExpectTrue("names.indexOf(\"baz\") >= 0");
11130 : ExpectTrue("names.indexOf(\"n1\") >= 0");
11131 : ExpectTrue("names.indexOf(\"n2\") >= 0");
11132 : ExpectTrue("names.indexOf(sym) >= 0");
11133 6 : ExpectTrue("names.indexOf(\"mine\") >= 0");
11134 6 : }
11135 :
11136 :
11137 23724 : THREADED_TEST(FunctionReadOnlyPrototype) {
11138 6 : LocalContext context;
11139 6 : v8::Isolate* isolate = context->GetIsolate();
11140 12 : v8::HandleScope handle_scope(isolate);
11141 :
11142 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11143 24 : t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11144 6 : t1->ReadOnlyPrototype();
11145 36 : CHECK(context->Global()
11146 : ->Set(context.local(), v8_str("func1"),
11147 : t1->GetFunction(context.local()).ToLocalChecked())
11148 : .FromJust());
11149 : // Configured value of ReadOnly flag.
11150 18 : CHECK(
11151 : CompileRun(
11152 : "(function() {"
11153 : " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11154 : " return (descriptor['writable'] == false);"
11155 : "})()")
11156 : ->BooleanValue(context.local())
11157 : .FromJust());
11158 18 : CHECK_EQ(
11159 : 42,
11160 : CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11161 18 : CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11162 : ->Int32Value(context.local())
11163 : .FromJust());
11164 :
11165 6 : Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11166 24 : t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11167 36 : CHECK(context->Global()
11168 : ->Set(context.local(), v8_str("func2"),
11169 : t2->GetFunction(context.local()).ToLocalChecked())
11170 : .FromJust());
11171 : // Default value of ReadOnly flag.
11172 18 : CHECK(
11173 : CompileRun(
11174 : "(function() {"
11175 : " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11176 : " return (descriptor['writable'] == true);"
11177 : "})()")
11178 : ->BooleanValue(context.local())
11179 : .FromJust());
11180 18 : CHECK_EQ(
11181 : 42,
11182 6 : CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11183 6 : }
11184 :
11185 :
11186 23724 : THREADED_TEST(SetPrototypeThrows) {
11187 6 : LocalContext context;
11188 6 : v8::Isolate* isolate = context->GetIsolate();
11189 12 : v8::HandleScope handle_scope(isolate);
11190 :
11191 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11192 :
11193 6 : Local<v8::Object> o0 = t->GetFunction(context.local())
11194 6 : .ToLocalChecked()
11195 6 : ->NewInstance(context.local())
11196 : .ToLocalChecked();
11197 6 : Local<v8::Object> o1 = t->GetFunction(context.local())
11198 6 : .ToLocalChecked()
11199 6 : ->NewInstance(context.local())
11200 : .ToLocalChecked();
11201 :
11202 12 : CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11203 : // If setting the prototype leads to the cycle, SetPrototype should
11204 : // return false and keep VM in sane state.
11205 12 : v8::TryCatch try_catch(isolate);
11206 12 : CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11207 6 : CHECK(!try_catch.HasCaught());
11208 6 : CHECK(!CcTest::i_isolate()->has_pending_exception());
11209 :
11210 18 : CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11211 : ->Int32Value(context.local())
11212 6 : .FromJust());
11213 6 : }
11214 :
11215 :
11216 23724 : THREADED_TEST(FunctionRemovePrototype) {
11217 6 : LocalContext context;
11218 6 : v8::Isolate* isolate = context->GetIsolate();
11219 12 : v8::HandleScope handle_scope(isolate);
11220 :
11221 6 : Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11222 6 : t1->RemovePrototype();
11223 6 : Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11224 6 : CHECK(!fun->IsConstructor());
11225 30 : CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11226 18 : CHECK(!CompileRun("'prototype' in fun")
11227 : ->BooleanValue(context.local())
11228 : .FromJust());
11229 :
11230 12 : v8::TryCatch try_catch(isolate);
11231 : CompileRun("new fun()");
11232 6 : CHECK(try_catch.HasCaught());
11233 :
11234 6 : try_catch.Reset();
11235 12 : CHECK(fun->NewInstance(context.local()).IsEmpty());
11236 12 : CHECK(try_catch.HasCaught());
11237 6 : }
11238 :
11239 :
11240 23724 : THREADED_TEST(GetterSetterExceptions) {
11241 6 : LocalContext context;
11242 6 : v8::Isolate* isolate = context->GetIsolate();
11243 12 : v8::HandleScope handle_scope(isolate);
11244 : CompileRun(
11245 : "function Foo() { };"
11246 : "function Throw() { throw 5; };"
11247 : "var x = { };"
11248 : "x.__defineSetter__('set', Throw);"
11249 : "x.__defineGetter__('get', Throw);");
11250 : Local<v8::Object> x = Local<v8::Object>::Cast(
11251 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11252 12 : v8::TryCatch try_catch(isolate);
11253 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11254 : .IsNothing());
11255 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11256 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11257 : .IsNothing());
11258 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11259 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11260 : .IsNothing());
11261 18 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11262 24 : CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11263 : .IsNothing());
11264 24 : CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11265 6 : }
11266 :
11267 :
11268 23724 : THREADED_TEST(Constructor) {
11269 6 : LocalContext context;
11270 6 : v8::Isolate* isolate = context->GetIsolate();
11271 12 : v8::HandleScope handle_scope(isolate);
11272 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11273 6 : templ->SetClassName(v8_str("Fun"));
11274 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11275 30 : CHECK(
11276 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11277 6 : Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11278 : i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11279 6 : CHECK(obj->IsJSObject());
11280 : Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11281 18 : CHECK(value->BooleanValue(context.local()).FromJust());
11282 6 : }
11283 :
11284 :
11285 48 : static void ConstructorCallback(
11286 96 : const v8::FunctionCallbackInfo<v8::Value>& args) {
11287 48 : ApiTestFuzzer::Fuzz();
11288 : Local<Object> This;
11289 :
11290 48 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
11291 48 : if (args.IsConstructCall()) {
11292 : Local<Object> Holder = args.Holder();
11293 48 : This = Object::New(args.GetIsolate());
11294 48 : Local<Value> proto = Holder->GetPrototype();
11295 48 : if (proto->IsObject()) {
11296 96 : This->SetPrototype(context, proto).FromJust();
11297 : }
11298 : } else {
11299 : This = args.This();
11300 : }
11301 :
11302 144 : This->Set(context, v8_str("a"), args[0]).FromJust();
11303 : args.GetReturnValue().Set(This);
11304 48 : }
11305 :
11306 :
11307 48 : static void FakeConstructorCallback(
11308 48 : const v8::FunctionCallbackInfo<v8::Value>& args) {
11309 48 : ApiTestFuzzer::Fuzz();
11310 : args.GetReturnValue().Set(args[0]);
11311 48 : }
11312 :
11313 :
11314 23724 : THREADED_TEST(ConstructorForObject) {
11315 6 : LocalContext context;
11316 6 : v8::Isolate* isolate = context->GetIsolate();
11317 12 : v8::HandleScope handle_scope(isolate);
11318 :
11319 : {
11320 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11321 6 : instance_template->SetCallAsFunctionHandler(ConstructorCallback);
11322 : Local<Object> instance =
11323 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11324 30 : CHECK(context->Global()
11325 : ->Set(context.local(), v8_str("obj"), instance)
11326 : .FromJust());
11327 6 : v8::TryCatch try_catch(isolate);
11328 : Local<Value> value;
11329 6 : CHECK(!try_catch.HasCaught());
11330 :
11331 : // Call the Object's constructor with a 32-bit signed integer.
11332 : value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11333 6 : CHECK(!try_catch.HasCaught());
11334 6 : CHECK(value->IsInt32());
11335 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11336 :
11337 6 : Local<Value> args1[] = {v8_num(28)};
11338 : Local<Value> value_obj1 =
11339 6 : instance->CallAsConstructor(context.local(), 1, args1).ToLocalChecked();
11340 6 : CHECK(value_obj1->IsObject());
11341 : Local<Object> object1 = Local<Object>::Cast(value_obj1);
11342 18 : value = object1->Get(context.local(), v8_str("a")).ToLocalChecked();
11343 6 : CHECK(value->IsInt32());
11344 6 : CHECK(!try_catch.HasCaught());
11345 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11346 :
11347 : // Call the Object's constructor with a String.
11348 : value =
11349 : CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
11350 6 : CHECK(!try_catch.HasCaught());
11351 6 : CHECK(value->IsString());
11352 : String::Utf8Value string_value1(
11353 18 : isolate, value->ToString(context.local()).ToLocalChecked());
11354 6 : CHECK_EQ(0, strcmp("tipli", *string_value1));
11355 :
11356 6 : Local<Value> args2[] = {v8_str("tipli")};
11357 : Local<Value> value_obj2 =
11358 6 : instance->CallAsConstructor(context.local(), 1, args2).ToLocalChecked();
11359 6 : CHECK(value_obj2->IsObject());
11360 : Local<Object> object2 = Local<Object>::Cast(value_obj2);
11361 18 : value = object2->Get(context.local(), v8_str("a")).ToLocalChecked();
11362 6 : CHECK(!try_catch.HasCaught());
11363 6 : CHECK(value->IsString());
11364 : String::Utf8Value string_value2(
11365 18 : isolate, value->ToString(context.local()).ToLocalChecked());
11366 6 : CHECK_EQ(0, strcmp("tipli", *string_value2));
11367 :
11368 : // Call the Object's constructor with a Boolean.
11369 : value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11370 6 : CHECK(!try_catch.HasCaught());
11371 6 : CHECK(value->IsBoolean());
11372 12 : CHECK(value->BooleanValue(context.local()).FromJust());
11373 :
11374 : Local<Value> args3[] = {v8::True(isolate)};
11375 : Local<Value> value_obj3 =
11376 6 : instance->CallAsConstructor(context.local(), 1, args3).ToLocalChecked();
11377 6 : CHECK(value_obj3->IsObject());
11378 : Local<Object> object3 = Local<Object>::Cast(value_obj3);
11379 18 : value = object3->Get(context.local(), v8_str("a")).ToLocalChecked();
11380 6 : CHECK(!try_catch.HasCaught());
11381 6 : CHECK(value->IsBoolean());
11382 12 : CHECK(value->BooleanValue(context.local()).FromJust());
11383 :
11384 : // Call the Object's constructor with undefined.
11385 : Local<Value> args4[] = {v8::Undefined(isolate)};
11386 : Local<Value> value_obj4 =
11387 6 : instance->CallAsConstructor(context.local(), 1, args4).ToLocalChecked();
11388 6 : CHECK(value_obj4->IsObject());
11389 : Local<Object> object4 = Local<Object>::Cast(value_obj4);
11390 18 : value = object4->Get(context.local(), v8_str("a")).ToLocalChecked();
11391 6 : CHECK(!try_catch.HasCaught());
11392 6 : CHECK(value->IsUndefined());
11393 :
11394 : // Call the Object's constructor with null.
11395 : Local<Value> args5[] = {v8::Null(isolate)};
11396 : Local<Value> value_obj5 =
11397 6 : instance->CallAsConstructor(context.local(), 1, args5).ToLocalChecked();
11398 6 : CHECK(value_obj5->IsObject());
11399 : Local<Object> object5 = Local<Object>::Cast(value_obj5);
11400 18 : value = object5->Get(context.local(), v8_str("a")).ToLocalChecked();
11401 6 : CHECK(!try_catch.HasCaught());
11402 12 : CHECK(value->IsNull());
11403 : }
11404 :
11405 : // Check exception handling when there is no constructor set for the Object.
11406 : {
11407 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11408 : Local<Object> instance =
11409 12 : instance_template->NewInstance(context.local()).ToLocalChecked();
11410 30 : CHECK(context->Global()
11411 : ->Set(context.local(), v8_str("obj2"), instance)
11412 : .FromJust());
11413 6 : v8::TryCatch try_catch(isolate);
11414 : Local<Value> value;
11415 6 : CHECK(!try_catch.HasCaught());
11416 :
11417 : value = CompileRun("new obj2(28)");
11418 6 : CHECK(try_catch.HasCaught());
11419 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11420 6 : CHECK_EQ(0,
11421 : strcmp("TypeError: obj2 is not a constructor", *exception_value1));
11422 6 : try_catch.Reset();
11423 :
11424 6 : Local<Value> args[] = {v8_num(29)};
11425 12 : CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
11426 6 : CHECK(try_catch.HasCaught());
11427 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11428 6 : CHECK_EQ(
11429 : 0, strcmp("TypeError: object is not a constructor", *exception_value2));
11430 12 : try_catch.Reset();
11431 : }
11432 :
11433 : // Check the case when constructor throws exception.
11434 : {
11435 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11436 6 : instance_template->SetCallAsFunctionHandler(ThrowValue);
11437 : Local<Object> instance =
11438 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11439 30 : CHECK(context->Global()
11440 : ->Set(context.local(), v8_str("obj3"), instance)
11441 : .FromJust());
11442 6 : v8::TryCatch try_catch(isolate);
11443 : Local<Value> value;
11444 6 : CHECK(!try_catch.HasCaught());
11445 :
11446 : value = CompileRun("new obj3(22)");
11447 6 : CHECK(try_catch.HasCaught());
11448 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11449 6 : CHECK_EQ(0, strcmp("22", *exception_value1));
11450 6 : try_catch.Reset();
11451 :
11452 6 : Local<Value> args[] = {v8_num(23)};
11453 12 : CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
11454 6 : CHECK(try_catch.HasCaught());
11455 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11456 6 : CHECK_EQ(0, strcmp("23", *exception_value2));
11457 12 : try_catch.Reset();
11458 : }
11459 :
11460 : // Check whether constructor returns with an object or non-object.
11461 : {
11462 : Local<FunctionTemplate> function_template =
11463 6 : FunctionTemplate::New(isolate, FakeConstructorCallback);
11464 : Local<Function> function =
11465 12 : function_template->GetFunction(context.local()).ToLocalChecked();
11466 : Local<Object> instance1 = function;
11467 6 : CHECK(instance1->IsObject());
11468 6 : CHECK(instance1->IsFunction());
11469 30 : CHECK(context->Global()
11470 : ->Set(context.local(), v8_str("obj4"), instance1)
11471 : .FromJust());
11472 6 : v8::TryCatch try_catch(isolate);
11473 6 : CHECK(!try_catch.HasCaught());
11474 :
11475 : {
11476 : Local<Value> value = CompileRun("new obj4(28)");
11477 6 : CHECK(!try_catch.HasCaught());
11478 6 : CHECK(value->IsObject());
11479 :
11480 6 : Local<Value> args[] = {v8_num(28)};
11481 6 : value = instance1->CallAsConstructor(context.local(), 1, args)
11482 6 : .ToLocalChecked();
11483 6 : CHECK(!try_catch.HasCaught());
11484 6 : CHECK(value->IsObject());
11485 : }
11486 :
11487 : Local<Value> proxy = CompileRun("proxy = new Proxy({},{})");
11488 6 : CHECK(!try_catch.HasCaught());
11489 6 : CHECK(proxy->IsProxy());
11490 :
11491 : {
11492 : Local<Value> value = CompileRun("new obj4(proxy)");
11493 6 : CHECK(!try_catch.HasCaught());
11494 6 : CHECK(value->IsProxy());
11495 6 : CHECK(value->SameValue(proxy));
11496 :
11497 6 : Local<Value> args[] = {proxy};
11498 6 : value = instance1->CallAsConstructor(context.local(), 1, args)
11499 6 : .ToLocalChecked();
11500 6 : CHECK(!try_catch.HasCaught());
11501 6 : CHECK(value->SameValue(proxy));
11502 : }
11503 :
11504 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11505 6 : instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11506 : Local<Object> instance2 =
11507 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
11508 6 : CHECK(instance2->IsObject());
11509 6 : CHECK(instance2->IsFunction());
11510 30 : CHECK(context->Global()
11511 : ->Set(context.local(), v8_str("obj5"), instance2)
11512 : .FromJust());
11513 6 : CHECK(!try_catch.HasCaught());
11514 :
11515 : {
11516 : Local<Value> value = CompileRun("new obj5(28)");
11517 6 : CHECK(!try_catch.HasCaught());
11518 6 : CHECK(!value->IsObject());
11519 :
11520 6 : Local<Value> args[] = {v8_num(28)};
11521 6 : value = instance2->CallAsConstructor(context.local(), 1, args)
11522 6 : .ToLocalChecked();
11523 6 : CHECK(!try_catch.HasCaught());
11524 6 : CHECK(!value->IsObject());
11525 : }
11526 :
11527 : {
11528 : Local<Value> value = CompileRun("new obj5(proxy)");
11529 6 : CHECK(!try_catch.HasCaught());
11530 6 : CHECK(value->IsProxy());
11531 6 : CHECK(value->SameValue(proxy));
11532 :
11533 6 : Local<Value> args[] = {proxy};
11534 6 : value = instance2->CallAsConstructor(context.local(), 1, args)
11535 6 : .ToLocalChecked();
11536 6 : CHECK(!try_catch.HasCaught());
11537 6 : CHECK(value->SameValue(proxy));
11538 6 : }
11539 6 : }
11540 6 : }
11541 :
11542 :
11543 23724 : THREADED_TEST(FunctionDescriptorException) {
11544 6 : LocalContext context;
11545 6 : v8::Isolate* isolate = context->GetIsolate();
11546 12 : v8::HandleScope handle_scope(isolate);
11547 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11548 6 : templ->SetClassName(v8_str("Fun"));
11549 6 : Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11550 30 : CHECK(
11551 : context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11552 : Local<Value> value = CompileRun(
11553 : "function test() {"
11554 : " try {"
11555 : " (new Fun()).blah()"
11556 : " } catch (e) {"
11557 : " var str = String(e);"
11558 : // " if (str.indexOf('TypeError') == -1) return 1;"
11559 : // " if (str.indexOf('[object Fun]') != -1) return 2;"
11560 : // " if (str.indexOf('#<Fun>') == -1) return 3;"
11561 : " return 0;"
11562 : " }"
11563 : " return 4;"
11564 : "}"
11565 : "test();");
11566 18 : CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11567 6 : }
11568 :
11569 :
11570 23724 : THREADED_TEST(EvalAliasedDynamic) {
11571 6 : LocalContext current;
11572 12 : v8::HandleScope scope(current->GetIsolate());
11573 :
11574 : // Tests where aliased eval can only be resolved dynamically.
11575 : Local<Script> script = v8_compile(
11576 : "function f(x) { "
11577 : " var foo = 2;"
11578 : " with (x) { return eval('foo'); }"
11579 : "}"
11580 : "foo = 0;"
11581 : "result1 = f(new Object());"
11582 : "result2 = f(this);"
11583 : "var x = new Object();"
11584 : "x.eval = function(x) { return 1; };"
11585 : "result3 = f(x);");
11586 6 : script->Run(current.local()).ToLocalChecked();
11587 36 : CHECK_EQ(2, current->Global()
11588 : ->Get(current.local(), v8_str("result1"))
11589 : .ToLocalChecked()
11590 : ->Int32Value(current.local())
11591 : .FromJust());
11592 36 : CHECK_EQ(0, current->Global()
11593 : ->Get(current.local(), v8_str("result2"))
11594 : .ToLocalChecked()
11595 : ->Int32Value(current.local())
11596 : .FromJust());
11597 36 : CHECK_EQ(1, current->Global()
11598 : ->Get(current.local(), v8_str("result3"))
11599 : .ToLocalChecked()
11600 : ->Int32Value(current.local())
11601 : .FromJust());
11602 :
11603 12 : v8::TryCatch try_catch(current->GetIsolate());
11604 : script = v8_compile(
11605 : "function f(x) { "
11606 : " var bar = 2;"
11607 : " with (x) { return eval('bar'); }"
11608 : "}"
11609 : "result4 = f(this)");
11610 6 : script->Run(current.local()).ToLocalChecked();
11611 6 : CHECK(!try_catch.HasCaught());
11612 36 : CHECK_EQ(2, current->Global()
11613 : ->Get(current.local(), v8_str("result4"))
11614 : .ToLocalChecked()
11615 : ->Int32Value(current.local())
11616 : .FromJust());
11617 :
11618 12 : try_catch.Reset();
11619 6 : }
11620 :
11621 :
11622 23724 : THREADED_TEST(CrossEval) {
11623 6 : v8::HandleScope scope(CcTest::isolate());
11624 12 : LocalContext other;
11625 12 : LocalContext current;
11626 :
11627 6 : Local<String> token = v8_str("<security token>");
11628 6 : other->SetSecurityToken(token);
11629 6 : current->SetSecurityToken(token);
11630 :
11631 : // Set up reference from current to other.
11632 36 : CHECK(current->Global()
11633 : ->Set(current.local(), v8_str("other"), other->Global())
11634 : .FromJust());
11635 :
11636 : // Check that new variables are introduced in other context.
11637 : Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11638 6 : script->Run(current.local()).ToLocalChecked();
11639 : Local<Value> foo =
11640 30 : other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11641 12 : CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11642 30 : CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11643 :
11644 : // Check that writing to non-existing properties introduces them in
11645 : // the other context.
11646 : script = v8_compile("other.eval('na = 1234')");
11647 6 : script->Run(current.local()).ToLocalChecked();
11648 36 : CHECK_EQ(1234, other->Global()
11649 : ->Get(current.local(), v8_str("na"))
11650 : .ToLocalChecked()
11651 : ->Int32Value(other.local())
11652 : .FromJust());
11653 30 : CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11654 :
11655 : // Check that global variables in current context are not visible in other
11656 : // context.
11657 12 : v8::TryCatch try_catch(CcTest::isolate());
11658 : script = v8_compile("var bar = 42; other.eval('bar');");
11659 12 : CHECK(script->Run(current.local()).IsEmpty());
11660 6 : CHECK(try_catch.HasCaught());
11661 6 : try_catch.Reset();
11662 :
11663 : // Check that local variables in current context are not visible in other
11664 : // context.
11665 : script = v8_compile(
11666 : "(function() { "
11667 : " var baz = 87;"
11668 : " return other.eval('baz');"
11669 : "})();");
11670 12 : CHECK(script->Run(current.local()).IsEmpty());
11671 6 : CHECK(try_catch.HasCaught());
11672 6 : try_catch.Reset();
11673 :
11674 : // Check that global variables in the other environment are visible
11675 : // when evaluting code.
11676 30 : CHECK(other->Global()
11677 : ->Set(other.local(), v8_str("bis"), v8_num(1234))
11678 : .FromJust());
11679 : script = v8_compile("other.eval('bis')");
11680 18 : CHECK_EQ(1234, script->Run(current.local())
11681 : .ToLocalChecked()
11682 : ->Int32Value(current.local())
11683 : .FromJust());
11684 6 : CHECK(!try_catch.HasCaught());
11685 :
11686 : // Check that the 'this' pointer points to the global object evaluating
11687 : // code.
11688 36 : CHECK(other->Global()
11689 : ->Set(current.local(), v8_str("t"), other->Global())
11690 : .FromJust());
11691 : script = v8_compile("other.eval('this == t')");
11692 6 : Local<Value> result = script->Run(current.local()).ToLocalChecked();
11693 6 : CHECK(result->IsTrue());
11694 6 : CHECK(!try_catch.HasCaught());
11695 :
11696 : // Check that variables introduced in with-statement are not visible in
11697 : // other context.
11698 : script = v8_compile("with({x:2}){other.eval('x')}");
11699 12 : CHECK(script->Run(current.local()).IsEmpty());
11700 6 : CHECK(try_catch.HasCaught());
11701 6 : try_catch.Reset();
11702 :
11703 : // Check that you cannot use 'eval.call' with another object than the
11704 : // current global object.
11705 : script = v8_compile("other.y = 1; eval.call(other, 'y')");
11706 12 : CHECK(script->Run(current.local()).IsEmpty());
11707 12 : CHECK(try_catch.HasCaught());
11708 6 : }
11709 :
11710 :
11711 : // Test that calling eval in a context which has been detached from
11712 : // its global proxy works.
11713 23724 : THREADED_TEST(EvalInDetachedGlobal) {
11714 6 : v8::Isolate* isolate = CcTest::isolate();
11715 6 : v8::HandleScope scope(isolate);
11716 :
11717 6 : v8::Local<Context> context0 = Context::New(isolate);
11718 6 : v8::Local<Context> context1 = Context::New(isolate);
11719 6 : Local<String> token = v8_str("<security token>");
11720 6 : context0->SetSecurityToken(token);
11721 6 : context1->SetSecurityToken(token);
11722 :
11723 : // Set up function in context0 that uses eval from context0.
11724 6 : context0->Enter();
11725 : v8::Local<v8::Value> fun = CompileRun(
11726 : "var x = 42;"
11727 : "(function() {"
11728 : " var e = eval;"
11729 : " return function(s) { return e(s); }"
11730 6 : "})()");
11731 6 : context0->Exit();
11732 :
11733 : // Put the function into context1 and call it before and after
11734 : // detaching the global. Before detaching, the call succeeds and
11735 : // after detaching undefined is returned.
11736 6 : context1->Enter();
11737 24 : CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11738 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11739 12 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11740 6 : context0->DetachGlobal();
11741 : x_value = CompileRun("fun('x')");
11742 6 : CHECK(x_value->IsUndefined());
11743 6 : context1->Exit();
11744 6 : }
11745 :
11746 :
11747 23724 : THREADED_TEST(CrossLazyLoad) {
11748 6 : v8::HandleScope scope(CcTest::isolate());
11749 12 : LocalContext other;
11750 12 : LocalContext current;
11751 :
11752 6 : Local<String> token = v8_str("<security token>");
11753 6 : other->SetSecurityToken(token);
11754 6 : current->SetSecurityToken(token);
11755 :
11756 : // Set up reference from current to other.
11757 36 : CHECK(current->Global()
11758 : ->Set(current.local(), v8_str("other"), other->Global())
11759 : .FromJust());
11760 :
11761 : // Trigger lazy loading in other context.
11762 : Local<Script> script = v8_compile("other.eval('new Date(42)')");
11763 6 : Local<Value> value = script->Run(current.local()).ToLocalChecked();
11764 18 : CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11765 6 : }
11766 :
11767 :
11768 102 : static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11769 48 : ApiTestFuzzer::Fuzz();
11770 48 : if (args.IsConstructCall()) {
11771 6 : if (args[0]->IsInt32()) {
11772 : args.GetReturnValue().Set(
11773 : v8_num(-args[0]
11774 6 : ->Int32Value(args.GetIsolate()->GetCurrentContext())
11775 18 : .FromJust()));
11776 54 : return;
11777 : }
11778 : }
11779 :
11780 : args.GetReturnValue().Set(args[0]);
11781 : }
11782 :
11783 :
11784 : // Test that a call handler can be set for objects which will allow
11785 : // non-function objects created through the API to be called as
11786 : // functions.
11787 23724 : THREADED_TEST(CallAsFunction) {
11788 6 : LocalContext context;
11789 6 : v8::Isolate* isolate = context->GetIsolate();
11790 12 : v8::HandleScope scope(isolate);
11791 :
11792 : {
11793 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11794 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11795 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
11796 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11797 6 : .ToLocalChecked()
11798 6 : ->NewInstance(context.local())
11799 : .ToLocalChecked();
11800 30 : CHECK(context->Global()
11801 : ->Set(context.local(), v8_str("obj"), instance)
11802 : .FromJust());
11803 6 : v8::TryCatch try_catch(isolate);
11804 : Local<Value> value;
11805 6 : CHECK(!try_catch.HasCaught());
11806 :
11807 : value = CompileRun("obj(42)");
11808 6 : CHECK(!try_catch.HasCaught());
11809 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11810 :
11811 : value = CompileRun("(function(o){return o(49)})(obj)");
11812 6 : CHECK(!try_catch.HasCaught());
11813 12 : CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11814 :
11815 : // test special case of call as function
11816 : value = CompileRun("[obj]['0'](45)");
11817 6 : CHECK(!try_catch.HasCaught());
11818 12 : CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11819 :
11820 : value = CompileRun(
11821 : "obj.call = Function.prototype.call;"
11822 : "obj.call(null, 87)");
11823 6 : CHECK(!try_catch.HasCaught());
11824 12 : CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11825 :
11826 : // Regression tests for bug #1116356: Calling call through call/apply
11827 : // must work for non-function receivers.
11828 : const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11829 : value = CompileRun(apply_99);
11830 6 : CHECK(!try_catch.HasCaught());
11831 12 : CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11832 :
11833 : const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11834 : value = CompileRun(call_17);
11835 6 : CHECK(!try_catch.HasCaught());
11836 12 : CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11837 :
11838 : // Check that the call-as-function handler can be called through
11839 : // new.
11840 : value = CompileRun("new obj(43)");
11841 6 : CHECK(!try_catch.HasCaught());
11842 12 : CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11843 :
11844 : // Check that the call-as-function handler can be called through
11845 : // the API.
11846 6 : v8::Local<Value> args[] = {v8_num(28)};
11847 12 : value = instance->CallAsFunction(context.local(), instance, 1, args)
11848 6 : .ToLocalChecked();
11849 6 : CHECK(!try_catch.HasCaught());
11850 12 : CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11851 : }
11852 :
11853 : {
11854 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11855 6 : Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11856 : USE(instance_template);
11857 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11858 6 : .ToLocalChecked()
11859 6 : ->NewInstance(context.local())
11860 : .ToLocalChecked();
11861 30 : CHECK(context->Global()
11862 : ->Set(context.local(), v8_str("obj2"), instance)
11863 : .FromJust());
11864 6 : v8::TryCatch try_catch(isolate);
11865 : Local<Value> value;
11866 6 : CHECK(!try_catch.HasCaught());
11867 :
11868 : // Call an object without call-as-function handler through the JS
11869 : value = CompileRun("obj2(28)");
11870 6 : CHECK(value.IsEmpty());
11871 6 : CHECK(try_catch.HasCaught());
11872 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11873 : // TODO(verwaest): Better message
11874 6 : CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11875 6 : try_catch.Reset();
11876 :
11877 : // Call an object without call-as-function handler through the API
11878 : value = CompileRun("obj2(28)");
11879 6 : v8::Local<Value> args[] = {v8_num(28)};
11880 12 : CHECK(
11881 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11882 6 : CHECK(try_catch.HasCaught());
11883 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11884 6 : CHECK_EQ(0,
11885 : strcmp("TypeError: object is not a function", *exception_value2));
11886 12 : try_catch.Reset();
11887 : }
11888 :
11889 : {
11890 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11891 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11892 6 : instance_template->SetCallAsFunctionHandler(ThrowValue);
11893 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11894 6 : .ToLocalChecked()
11895 6 : ->NewInstance(context.local())
11896 : .ToLocalChecked();
11897 30 : CHECK(context->Global()
11898 : ->Set(context.local(), v8_str("obj3"), instance)
11899 : .FromJust());
11900 6 : v8::TryCatch try_catch(isolate);
11901 : Local<Value> value;
11902 6 : CHECK(!try_catch.HasCaught());
11903 :
11904 : // Catch the exception which is thrown by call-as-function handler
11905 : value = CompileRun("obj3(22)");
11906 6 : CHECK(try_catch.HasCaught());
11907 12 : String::Utf8Value exception_value1(isolate, try_catch.Exception());
11908 6 : CHECK_EQ(0, strcmp("22", *exception_value1));
11909 6 : try_catch.Reset();
11910 :
11911 6 : v8::Local<Value> args[] = {v8_num(23)};
11912 12 : CHECK(
11913 : instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11914 6 : CHECK(try_catch.HasCaught());
11915 12 : String::Utf8Value exception_value2(isolate, try_catch.Exception());
11916 6 : CHECK_EQ(0, strcmp("23", *exception_value2));
11917 12 : try_catch.Reset();
11918 : }
11919 :
11920 : {
11921 6 : Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11922 6 : Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11923 6 : instance_template->SetCallAsFunctionHandler(ReturnThis);
11924 6 : Local<v8::Object> instance = t->GetFunction(context.local())
11925 6 : .ToLocalChecked()
11926 6 : ->NewInstance(context.local())
11927 : .ToLocalChecked();
11928 :
11929 : Local<v8::Value> a1 =
11930 : instance
11931 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11932 12 : nullptr)
11933 6 : .ToLocalChecked();
11934 6 : CHECK(a1->StrictEquals(instance));
11935 : Local<v8::Value> a2 =
11936 12 : instance->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11937 6 : .ToLocalChecked();
11938 6 : CHECK(a2->StrictEquals(instance));
11939 : Local<v8::Value> a3 =
11940 6 : instance->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11941 6 : .ToLocalChecked();
11942 6 : CHECK(a3->StrictEquals(instance));
11943 : Local<v8::Value> a4 =
11944 18 : instance->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11945 6 : .ToLocalChecked();
11946 6 : CHECK(a4->StrictEquals(instance));
11947 : Local<v8::Value> a5 =
11948 12 : instance->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11949 6 : .ToLocalChecked();
11950 6 : CHECK(a5->StrictEquals(instance));
11951 : }
11952 :
11953 : {
11954 : CompileRun(
11955 : "function ReturnThisSloppy() {"
11956 : " return this;"
11957 : "}"
11958 : "function ReturnThisStrict() {"
11959 : " 'use strict';"
11960 : " return this;"
11961 : "}");
11962 : Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11963 : context->Global()
11964 24 : ->Get(context.local(), v8_str("ReturnThisSloppy"))
11965 6 : .ToLocalChecked());
11966 : Local<Function> ReturnThisStrict = Local<Function>::Cast(
11967 : context->Global()
11968 24 : ->Get(context.local(), v8_str("ReturnThisStrict"))
11969 6 : .ToLocalChecked());
11970 :
11971 : Local<v8::Value> a1 =
11972 : ReturnThisSloppy
11973 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11974 12 : nullptr)
11975 6 : .ToLocalChecked();
11976 12 : CHECK(a1->StrictEquals(context->Global()));
11977 : Local<v8::Value> a2 =
11978 : ReturnThisSloppy
11979 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11980 6 : .ToLocalChecked();
11981 12 : CHECK(a2->StrictEquals(context->Global()));
11982 : Local<v8::Value> a3 =
11983 : ReturnThisSloppy
11984 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11985 6 : .ToLocalChecked();
11986 6 : CHECK(a3->IsNumberObject());
11987 6 : CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11988 : Local<v8::Value> a4 =
11989 : ReturnThisSloppy
11990 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11991 6 : .ToLocalChecked();
11992 6 : CHECK(a4->IsStringObject());
11993 18 : CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11994 : Local<v8::Value> a5 =
11995 : ReturnThisSloppy
11996 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11997 6 : .ToLocalChecked();
11998 6 : CHECK(a5->IsBooleanObject());
11999 6 : CHECK(a5.As<v8::BooleanObject>()->ValueOf());
12000 :
12001 : Local<v8::Value> a6 =
12002 : ReturnThisStrict
12003 : ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
12004 12 : nullptr)
12005 6 : .ToLocalChecked();
12006 6 : CHECK(a6->IsUndefined());
12007 : Local<v8::Value> a7 =
12008 : ReturnThisStrict
12009 12 : ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
12010 6 : .ToLocalChecked();
12011 6 : CHECK(a7->IsNull());
12012 : Local<v8::Value> a8 =
12013 : ReturnThisStrict
12014 6 : ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
12015 6 : .ToLocalChecked();
12016 6 : CHECK(a8->StrictEquals(v8_num(42)));
12017 : Local<v8::Value> a9 =
12018 : ReturnThisStrict
12019 18 : ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
12020 6 : .ToLocalChecked();
12021 12 : CHECK(a9->StrictEquals(v8_str("hello")));
12022 : Local<v8::Value> a10 =
12023 : ReturnThisStrict
12024 12 : ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
12025 6 : .ToLocalChecked();
12026 6 : CHECK(a10->StrictEquals(v8::True(isolate)));
12027 6 : }
12028 6 : }
12029 :
12030 :
12031 : // Check whether a non-function object is callable.
12032 23724 : THREADED_TEST(CallableObject) {
12033 6 : LocalContext context;
12034 6 : v8::Isolate* isolate = context->GetIsolate();
12035 12 : v8::HandleScope scope(isolate);
12036 :
12037 : {
12038 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
12039 6 : instance_template->SetCallAsFunctionHandler(call_as_function);
12040 : Local<Object> instance =
12041 6 : instance_template->NewInstance(context.local()).ToLocalChecked();
12042 6 : v8::TryCatch try_catch(isolate);
12043 :
12044 6 : CHECK(instance->IsCallable());
12045 6 : CHECK(!try_catch.HasCaught());
12046 : }
12047 :
12048 : {
12049 6 : Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
12050 : Local<Object> instance =
12051 12 : instance_template->NewInstance(context.local()).ToLocalChecked();
12052 6 : v8::TryCatch try_catch(isolate);
12053 :
12054 6 : CHECK(!instance->IsCallable());
12055 6 : CHECK(!try_catch.HasCaught());
12056 : }
12057 :
12058 : {
12059 : Local<FunctionTemplate> function_template =
12060 6 : FunctionTemplate::New(isolate, call_as_function);
12061 : Local<Function> function =
12062 12 : function_template->GetFunction(context.local()).ToLocalChecked();
12063 : Local<Object> instance = function;
12064 6 : v8::TryCatch try_catch(isolate);
12065 :
12066 6 : CHECK(instance->IsCallable());
12067 6 : CHECK(!try_catch.HasCaught());
12068 : }
12069 :
12070 : {
12071 6 : Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
12072 : Local<Function> function =
12073 12 : function_template->GetFunction(context.local()).ToLocalChecked();
12074 : Local<Object> instance = function;
12075 6 : v8::TryCatch try_catch(isolate);
12076 :
12077 6 : CHECK(instance->IsCallable());
12078 6 : CHECK(!try_catch.HasCaught());
12079 6 : }
12080 6 : }
12081 :
12082 :
12083 23724 : THREADED_TEST(Regress567998) {
12084 6 : LocalContext env;
12085 12 : v8::HandleScope scope(env->GetIsolate());
12086 :
12087 : Local<v8::FunctionTemplate> desc =
12088 6 : v8::FunctionTemplate::New(env->GetIsolate());
12089 12 : desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
12090 12 : desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
12091 :
12092 6 : Local<v8::Object> obj = desc->GetFunction(env.local())
12093 6 : .ToLocalChecked()
12094 6 : ->NewInstance(env.local())
12095 : .ToLocalChecked();
12096 30 : CHECK(
12097 : env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
12098 :
12099 6 : ExpectString("undetectable.toString()", "[object Object]");
12100 6 : ExpectString("typeof undetectable", "undefined");
12101 6 : ExpectString("typeof(undetectable)", "undefined");
12102 6 : ExpectBoolean("typeof undetectable == 'undefined'", true);
12103 6 : ExpectBoolean("typeof undetectable == 'object'", false);
12104 6 : ExpectBoolean("if (undetectable) { true; } else { false; }", false);
12105 6 : ExpectBoolean("!undetectable", true);
12106 :
12107 6 : ExpectObject("true&&undetectable", obj);
12108 6 : ExpectBoolean("false&&undetectable", false);
12109 6 : ExpectBoolean("true||undetectable", true);
12110 6 : ExpectObject("false||undetectable", obj);
12111 :
12112 6 : ExpectObject("undetectable&&true", obj);
12113 6 : ExpectObject("undetectable&&false", obj);
12114 6 : ExpectBoolean("undetectable||true", true);
12115 6 : ExpectBoolean("undetectable||false", false);
12116 :
12117 6 : ExpectBoolean("undetectable==null", true);
12118 6 : ExpectBoolean("null==undetectable", true);
12119 6 : ExpectBoolean("undetectable==undefined", true);
12120 6 : ExpectBoolean("undefined==undetectable", true);
12121 6 : ExpectBoolean("undetectable==undetectable", true);
12122 :
12123 6 : ExpectBoolean("undetectable===null", false);
12124 6 : ExpectBoolean("null===undetectable", false);
12125 6 : ExpectBoolean("undetectable===undefined", false);
12126 6 : ExpectBoolean("undefined===undetectable", false);
12127 12 : ExpectBoolean("undetectable===undetectable", true);
12128 6 : }
12129 :
12130 :
12131 1206 : static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
12132 1206 : v8::HandleScope scope(isolate);
12133 1206 : if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
12134 600000 : for (int i = 0; i < iterations; i++) {
12135 600000 : Local<v8::Number> n(v8::Integer::New(isolate, 42));
12136 : }
12137 1200 : return Recurse(isolate, depth - 1, iterations);
12138 : }
12139 :
12140 :
12141 23724 : THREADED_TEST(HandleIteration) {
12142 : static const int kIterations = 500;
12143 : static const int kNesting = 200;
12144 6 : LocalContext context;
12145 6 : v8::Isolate* isolate = context->GetIsolate();
12146 12 : v8::HandleScope scope0(isolate);
12147 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12148 : {
12149 6 : v8::HandleScope scope1(isolate);
12150 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12151 3006 : for (int i = 0; i < kIterations; i++) {
12152 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12153 3000 : CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12154 : }
12155 :
12156 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12157 : {
12158 6 : v8::HandleScope scope2(CcTest::isolate());
12159 3006 : for (int j = 0; j < kIterations; j++) {
12160 3000 : Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12161 3000 : CHECK_EQ(j + 1 + kIterations,
12162 : v8::HandleScope::NumberOfHandles(isolate));
12163 6 : }
12164 : }
12165 6 : CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12166 : }
12167 6 : CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12168 12 : CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12169 6 : }
12170 :
12171 :
12172 4994 : static void InterceptorCallICFastApi(
12173 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12174 4994 : ApiTestFuzzer::Fuzz();
12175 4994 : CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12176 : int* call_count =
12177 4994 : reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12178 4994 : ++(*call_count);
12179 4994 : if ((*call_count) % 20 == 0) {
12180 231 : CcTest::CollectAllGarbage();
12181 : }
12182 4994 : }
12183 :
12184 2200 : static void FastApiCallback_TrivialSignature(
12185 8800 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12186 2200 : ApiTestFuzzer::Fuzz();
12187 2200 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12188 2200 : v8::Isolate* isolate = CcTest::isolate();
12189 2200 : CHECK_EQ(isolate, args.GetIsolate());
12190 6600 : CHECK(args.This()
12191 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12192 : .FromJust());
12193 8800 : CHECK(args.Data()
12194 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12195 : .FromJust());
12196 : args.GetReturnValue().Set(
12197 8800 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12198 2200 : }
12199 :
12200 6127 : static void FastApiCallback_SimpleSignature(
12201 30635 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12202 6127 : ApiTestFuzzer::Fuzz();
12203 6127 : CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12204 6127 : v8::Isolate* isolate = CcTest::isolate();
12205 6127 : CHECK_EQ(isolate, args.GetIsolate());
12206 24508 : CHECK(args.This()
12207 : ->GetPrototype()
12208 : ->Equals(isolate->GetCurrentContext(), args.Holder())
12209 : .FromJust());
12210 24508 : CHECK(args.Data()
12211 : ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12212 : .FromJust());
12213 : // Note, we're using HasRealNamedProperty instead of Has to avoid
12214 : // invoking the interceptor again.
12215 24508 : CHECK(args.Holder()
12216 : ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12217 : .FromJust());
12218 : args.GetReturnValue().Set(
12219 24508 : args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12220 6127 : }
12221 :
12222 :
12223 : // Helper to maximize the odds of object moving.
12224 291 : static void GenerateSomeGarbage() {
12225 : CompileRun(
12226 : "var garbage;"
12227 : "for (var i = 0; i < 1000; i++) {"
12228 : " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12229 : "}"
12230 : "garbage = undefined;");
12231 291 : }
12232 :
12233 :
12234 180 : void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12235 : static int count = 0;
12236 180 : if (count++ % 3 == 0) {
12237 60 : CcTest::CollectAllGarbage();
12238 : // This should move the stub
12239 60 : GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12240 : }
12241 180 : }
12242 :
12243 :
12244 23724 : THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12245 6 : LocalContext context;
12246 6 : v8::Isolate* isolate = context->GetIsolate();
12247 12 : v8::HandleScope scope(isolate);
12248 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12249 6 : v8::ObjectTemplate::New(isolate);
12250 : nativeobject_templ->Set(isolate, "callback",
12251 : v8::FunctionTemplate::New(isolate,
12252 12 : DirectApiCallback));
12253 : v8::Local<v8::Object> nativeobject_obj =
12254 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12255 30 : CHECK(context->Global()
12256 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12257 : .FromJust());
12258 : // call the api function multiple times to ensure direct call stub creation.
12259 : CompileRun(
12260 : "function f() {"
12261 : " for (var i = 1; i <= 30; i++) {"
12262 : " nativeobject.callback();"
12263 : " }"
12264 : "}"
12265 6 : "f();");
12266 6 : }
12267 :
12268 :
12269 30 : void ThrowingDirectApiCallback(
12270 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12271 60 : args.GetIsolate()->ThrowException(v8_str("g"));
12272 30 : }
12273 :
12274 :
12275 23724 : THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12276 6 : LocalContext context;
12277 6 : v8::Isolate* isolate = context->GetIsolate();
12278 12 : v8::HandleScope scope(isolate);
12279 : v8::Local<v8::ObjectTemplate> nativeobject_templ =
12280 6 : v8::ObjectTemplate::New(isolate);
12281 : nativeobject_templ->Set(isolate, "callback",
12282 : v8::FunctionTemplate::New(isolate,
12283 12 : ThrowingDirectApiCallback));
12284 : v8::Local<v8::Object> nativeobject_obj =
12285 6 : nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12286 30 : CHECK(context->Global()
12287 : ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12288 : .FromJust());
12289 : // call the api function multiple times to ensure direct call stub creation.
12290 : v8::Local<Value> result = CompileRun(
12291 : "var result = '';"
12292 : "function f() {"
12293 : " for (var i = 1; i <= 5; i++) {"
12294 : " try { nativeobject.callback(); } catch (e) { result += e; }"
12295 : " }"
12296 : "}"
12297 6 : "f(); result;");
12298 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12299 6 : }
12300 :
12301 :
12302 : static int p_getter_count_3;
12303 :
12304 :
12305 341 : static Local<Value> DoDirectGetter() {
12306 341 : if (++p_getter_count_3 % 3 == 0) {
12307 110 : CcTest::CollectAllGarbage();
12308 110 : GenerateSomeGarbage();
12309 : }
12310 341 : return v8_str("Direct Getter Result");
12311 : }
12312 :
12313 :
12314 341 : static void DirectGetterCallback(
12315 : Local<String> name,
12316 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12317 341 : CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12318 341 : info.GetReturnValue().Set(DoDirectGetter());
12319 341 : }
12320 :
12321 :
12322 : template<typename Accessor>
12323 11 : static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12324 11 : LocalContext context;
12325 11 : v8::Isolate* isolate = context->GetIsolate();
12326 22 : v8::HandleScope scope(isolate);
12327 11 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12328 11 : obj->SetAccessor(v8_str("p1"), accessor);
12329 66 : CHECK(context->Global()
12330 : ->Set(context.local(), v8_str("o1"),
12331 : obj->NewInstance(context.local()).ToLocalChecked())
12332 : .FromJust());
12333 11 : p_getter_count_3 = 0;
12334 : v8::Local<v8::Value> result = CompileRun(
12335 : "function f() {"
12336 : " for (var i = 0; i < 30; i++) o1.p1;"
12337 : " return o1.p1"
12338 : "}"
12339 11 : "f();");
12340 33 : CHECK(v8_str("Direct Getter Result")
12341 : ->Equals(context.local(), result)
12342 : .FromJust());
12343 22 : CHECK_EQ(31, p_getter_count_3);
12344 11 : }
12345 :
12346 :
12347 47452 : THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12348 11 : LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12349 11 : }
12350 :
12351 :
12352 30 : void ThrowingDirectGetterCallback(
12353 : Local<String> name,
12354 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12355 60 : info.GetIsolate()->ThrowException(v8_str("g"));
12356 30 : }
12357 :
12358 :
12359 23724 : THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12360 6 : LocalContext context;
12361 6 : v8::Isolate* isolate = context->GetIsolate();
12362 12 : v8::HandleScope scope(isolate);
12363 6 : v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12364 6 : obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12365 36 : CHECK(context->Global()
12366 : ->Set(context.local(), v8_str("o1"),
12367 : obj->NewInstance(context.local()).ToLocalChecked())
12368 : .FromJust());
12369 : v8::Local<Value> result = CompileRun(
12370 : "var result = '';"
12371 : "for (var i = 0; i < 5; i++) {"
12372 : " try { o1.p1; } catch (e) { result += e; }"
12373 : "}"
12374 6 : "result;");
12375 24 : CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12376 6 : }
12377 :
12378 :
12379 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12380 11 : int interceptor_call_count = 0;
12381 11 : v8::Isolate* isolate = CcTest::isolate();
12382 11 : v8::HandleScope scope(isolate);
12383 : v8::Local<v8::FunctionTemplate> fun_templ =
12384 11 : v8::FunctionTemplate::New(isolate);
12385 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12386 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12387 22 : v8::Local<v8::Signature>());
12388 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12389 22 : proto_templ->Set(v8_str("method"), method_templ);
12390 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12391 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12392 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12393 22 : v8::External::New(isolate, &interceptor_call_count)));
12394 22 : LocalContext context;
12395 : v8::Local<v8::Function> fun =
12396 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12397 11 : GenerateSomeGarbage();
12398 66 : CHECK(context->Global()
12399 : ->Set(context.local(), v8_str("o"),
12400 : fun->NewInstance(context.local()).ToLocalChecked())
12401 : .FromJust());
12402 : CompileRun(
12403 : "var result = 0;"
12404 : "for (var i = 0; i < 100; i++) {"
12405 : " result = o.method(41);"
12406 : "}");
12407 66 : CHECK_EQ(42, context->Global()
12408 : ->Get(context.local(), v8_str("result"))
12409 : .ToLocalChecked()
12410 : ->Int32Value(context.local())
12411 : .FromJust());
12412 22 : CHECK_EQ(100, interceptor_call_count);
12413 11 : }
12414 :
12415 :
12416 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12417 11 : int interceptor_call_count = 0;
12418 11 : v8::Isolate* isolate = CcTest::isolate();
12419 11 : v8::HandleScope scope(isolate);
12420 : v8::Local<v8::FunctionTemplate> fun_templ =
12421 11 : v8::FunctionTemplate::New(isolate);
12422 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12423 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12424 22 : v8::Signature::New(isolate, fun_templ));
12425 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12426 22 : proto_templ->Set(v8_str("method"), method_templ);
12427 11 : fun_templ->SetHiddenPrototype(true);
12428 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12429 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12430 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12431 22 : v8::External::New(isolate, &interceptor_call_count)));
12432 22 : LocalContext context;
12433 : v8::Local<v8::Function> fun =
12434 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12435 11 : GenerateSomeGarbage();
12436 66 : CHECK(context->Global()
12437 : ->Set(context.local(), v8_str("o"),
12438 : fun->NewInstance(context.local()).ToLocalChecked())
12439 : .FromJust());
12440 : CompileRun(
12441 : "o.foo = 17;"
12442 : "var receiver = {};"
12443 : "receiver.__proto__ = o;"
12444 : "var result = 0;"
12445 : "for (var i = 0; i < 100; i++) {"
12446 : " result = receiver.method(41);"
12447 : "}");
12448 66 : CHECK_EQ(42, context->Global()
12449 : ->Get(context.local(), v8_str("result"))
12450 : .ToLocalChecked()
12451 : ->Int32Value(context.local())
12452 : .FromJust());
12453 22 : CHECK_EQ(100, interceptor_call_count);
12454 11 : }
12455 :
12456 :
12457 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12458 11 : int interceptor_call_count = 0;
12459 11 : v8::Isolate* isolate = CcTest::isolate();
12460 11 : v8::HandleScope scope(isolate);
12461 : v8::Local<v8::FunctionTemplate> fun_templ =
12462 11 : v8::FunctionTemplate::New(isolate);
12463 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12464 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12465 22 : v8::Signature::New(isolate, fun_templ));
12466 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12467 22 : proto_templ->Set(v8_str("method"), method_templ);
12468 11 : fun_templ->SetHiddenPrototype(true);
12469 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12470 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12471 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12472 22 : v8::External::New(isolate, &interceptor_call_count)));
12473 22 : LocalContext context;
12474 : v8::Local<v8::Function> fun =
12475 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12476 11 : GenerateSomeGarbage();
12477 66 : CHECK(context->Global()
12478 : ->Set(context.local(), v8_str("o"),
12479 : fun->NewInstance(context.local()).ToLocalChecked())
12480 : .FromJust());
12481 : CompileRun(
12482 : "o.foo = 17;"
12483 : "var receiver = {};"
12484 : "receiver.__proto__ = o;"
12485 : "var result = 0;"
12486 : "var saved_result = 0;"
12487 : "for (var i = 0; i < 100; i++) {"
12488 : " result = receiver.method(41);"
12489 : " if (i == 50) {"
12490 : " saved_result = result;"
12491 : " receiver = {method: function(x) { return x - 1 }};"
12492 : " }"
12493 : "}");
12494 66 : CHECK_EQ(40, context->Global()
12495 : ->Get(context.local(), v8_str("result"))
12496 : .ToLocalChecked()
12497 : ->Int32Value(context.local())
12498 : .FromJust());
12499 66 : CHECK_EQ(42, context->Global()
12500 : ->Get(context.local(), v8_str("saved_result"))
12501 : .ToLocalChecked()
12502 : ->Int32Value(context.local())
12503 : .FromJust());
12504 22 : CHECK_GE(interceptor_call_count, 50);
12505 11 : }
12506 :
12507 :
12508 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12509 11 : int interceptor_call_count = 0;
12510 11 : v8::Isolate* isolate = CcTest::isolate();
12511 11 : v8::HandleScope scope(isolate);
12512 : v8::Local<v8::FunctionTemplate> fun_templ =
12513 11 : v8::FunctionTemplate::New(isolate);
12514 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12515 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12516 22 : v8::Signature::New(isolate, fun_templ));
12517 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12518 22 : proto_templ->Set(v8_str("method"), method_templ);
12519 11 : fun_templ->SetHiddenPrototype(true);
12520 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12521 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12522 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12523 22 : v8::External::New(isolate, &interceptor_call_count)));
12524 22 : LocalContext context;
12525 : v8::Local<v8::Function> fun =
12526 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12527 11 : GenerateSomeGarbage();
12528 66 : CHECK(context->Global()
12529 : ->Set(context.local(), v8_str("o"),
12530 : fun->NewInstance(context.local()).ToLocalChecked())
12531 : .FromJust());
12532 : CompileRun(
12533 : "o.foo = 17;"
12534 : "var receiver = {};"
12535 : "receiver.__proto__ = o;"
12536 : "var result = 0;"
12537 : "var saved_result = 0;"
12538 : "for (var i = 0; i < 100; i++) {"
12539 : " result = receiver.method(41);"
12540 : " if (i == 50) {"
12541 : " saved_result = result;"
12542 : " o.method = function(x) { return x - 1 };"
12543 : " }"
12544 : "}");
12545 66 : CHECK_EQ(40, context->Global()
12546 : ->Get(context.local(), v8_str("result"))
12547 : .ToLocalChecked()
12548 : ->Int32Value(context.local())
12549 : .FromJust());
12550 66 : CHECK_EQ(42, context->Global()
12551 : ->Get(context.local(), v8_str("saved_result"))
12552 : .ToLocalChecked()
12553 : ->Int32Value(context.local())
12554 : .FromJust());
12555 22 : CHECK_GE(interceptor_call_count, 50);
12556 11 : }
12557 :
12558 :
12559 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12560 11 : int interceptor_call_count = 0;
12561 11 : v8::Isolate* isolate = CcTest::isolate();
12562 11 : v8::HandleScope scope(isolate);
12563 : v8::Local<v8::FunctionTemplate> fun_templ =
12564 11 : v8::FunctionTemplate::New(isolate);
12565 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12566 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12567 22 : v8::Signature::New(isolate, fun_templ));
12568 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12569 22 : proto_templ->Set(v8_str("method"), method_templ);
12570 11 : fun_templ->SetHiddenPrototype(true);
12571 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12572 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12573 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12574 22 : v8::External::New(isolate, &interceptor_call_count)));
12575 22 : LocalContext context;
12576 : v8::Local<v8::Function> fun =
12577 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12578 11 : GenerateSomeGarbage();
12579 66 : CHECK(context->Global()
12580 : ->Set(context.local(), v8_str("o"),
12581 : fun->NewInstance(context.local()).ToLocalChecked())
12582 : .FromJust());
12583 22 : v8::TryCatch try_catch(isolate);
12584 : CompileRun(
12585 : "o.foo = 17;"
12586 : "var receiver = {};"
12587 : "receiver.__proto__ = o;"
12588 : "var result = 0;"
12589 : "var saved_result = 0;"
12590 : "for (var i = 0; i < 100; i++) {"
12591 : " result = receiver.method(41);"
12592 : " if (i == 50) {"
12593 : " saved_result = result;"
12594 : " receiver = 333;"
12595 : " }"
12596 : "}");
12597 11 : CHECK(try_catch.HasCaught());
12598 : // TODO(verwaest): Adjust message.
12599 55 : CHECK(
12600 : v8_str("TypeError: receiver.method is not a function")
12601 : ->Equals(
12602 : context.local(),
12603 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12604 : .FromJust());
12605 66 : CHECK_EQ(42, context->Global()
12606 : ->Get(context.local(), v8_str("saved_result"))
12607 : .ToLocalChecked()
12608 : ->Int32Value(context.local())
12609 : .FromJust());
12610 22 : CHECK_GE(interceptor_call_count, 50);
12611 11 : }
12612 :
12613 :
12614 47452 : THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12615 11 : int interceptor_call_count = 0;
12616 11 : v8::Isolate* isolate = CcTest::isolate();
12617 11 : v8::HandleScope scope(isolate);
12618 : v8::Local<v8::FunctionTemplate> fun_templ =
12619 11 : v8::FunctionTemplate::New(isolate);
12620 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12621 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12622 22 : v8::Signature::New(isolate, fun_templ));
12623 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12624 22 : proto_templ->Set(v8_str("method"), method_templ);
12625 11 : fun_templ->SetHiddenPrototype(true);
12626 11 : v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12627 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12628 : InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12629 22 : v8::External::New(isolate, &interceptor_call_count)));
12630 22 : LocalContext context;
12631 : v8::Local<v8::Function> fun =
12632 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12633 11 : GenerateSomeGarbage();
12634 66 : CHECK(context->Global()
12635 : ->Set(context.local(), v8_str("o"),
12636 : fun->NewInstance(context.local()).ToLocalChecked())
12637 : .FromJust());
12638 22 : v8::TryCatch try_catch(isolate);
12639 : CompileRun(
12640 : "o.foo = 17;"
12641 : "var receiver = {};"
12642 : "receiver.__proto__ = o;"
12643 : "var result = 0;"
12644 : "var saved_result = 0;"
12645 : "for (var i = 0; i < 100; i++) {"
12646 : " result = receiver.method(41);"
12647 : " if (i == 50) {"
12648 : " saved_result = result;"
12649 : " receiver = {method: receiver.method};"
12650 : " }"
12651 : "}");
12652 11 : CHECK(try_catch.HasCaught());
12653 55 : CHECK(
12654 : v8_str("TypeError: Illegal invocation")
12655 : ->Equals(
12656 : context.local(),
12657 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12658 : .FromJust());
12659 66 : CHECK_EQ(42, context->Global()
12660 : ->Get(context.local(), v8_str("saved_result"))
12661 : .ToLocalChecked()
12662 : ->Int32Value(context.local())
12663 : .FromJust());
12664 22 : CHECK_GE(interceptor_call_count, 50);
12665 11 : }
12666 :
12667 :
12668 47452 : THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12669 11 : v8::Isolate* isolate = CcTest::isolate();
12670 11 : v8::HandleScope scope(isolate);
12671 : v8::Local<v8::FunctionTemplate> fun_templ =
12672 11 : v8::FunctionTemplate::New(isolate);
12673 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12674 : isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12675 22 : v8::Local<v8::Signature>());
12676 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12677 22 : proto_templ->Set(v8_str("method"), method_templ);
12678 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12679 : USE(templ);
12680 22 : LocalContext context;
12681 : v8::Local<v8::Function> fun =
12682 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12683 11 : GenerateSomeGarbage();
12684 66 : CHECK(context->Global()
12685 : ->Set(context.local(), v8_str("o"),
12686 : fun->NewInstance(context.local()).ToLocalChecked())
12687 : .FromJust());
12688 : CompileRun(
12689 : "var result = 0;"
12690 : "for (var i = 0; i < 100; i++) {"
12691 : " result = o.method(41);"
12692 : "}");
12693 :
12694 66 : CHECK_EQ(42, context->Global()
12695 : ->Get(context.local(), v8_str("result"))
12696 : .ToLocalChecked()
12697 : ->Int32Value(context.local())
12698 11 : .FromJust());
12699 11 : }
12700 :
12701 :
12702 47452 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12703 11 : v8::Isolate* isolate = CcTest::isolate();
12704 11 : v8::HandleScope scope(isolate);
12705 : v8::Local<v8::FunctionTemplate> fun_templ =
12706 11 : v8::FunctionTemplate::New(isolate);
12707 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12708 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12709 22 : v8::Signature::New(isolate, fun_templ));
12710 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12711 22 : proto_templ->Set(v8_str("method"), method_templ);
12712 11 : fun_templ->SetHiddenPrototype(true);
12713 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12714 11 : CHECK(!templ.IsEmpty());
12715 22 : LocalContext context;
12716 : v8::Local<v8::Function> fun =
12717 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12718 11 : GenerateSomeGarbage();
12719 66 : CHECK(context->Global()
12720 : ->Set(context.local(), v8_str("o"),
12721 : fun->NewInstance(context.local()).ToLocalChecked())
12722 : .FromJust());
12723 : CompileRun(
12724 : "o.foo = 17;"
12725 : "var receiver = {};"
12726 : "receiver.__proto__ = o;"
12727 : "var result = 0;"
12728 : "for (var i = 0; i < 100; i++) {"
12729 : " result = receiver.method(41);"
12730 : "}");
12731 :
12732 66 : CHECK_EQ(42, context->Global()
12733 : ->Get(context.local(), v8_str("result"))
12734 : .ToLocalChecked()
12735 : ->Int32Value(context.local())
12736 11 : .FromJust());
12737 11 : }
12738 :
12739 :
12740 47452 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12741 11 : v8::Isolate* isolate = CcTest::isolate();
12742 11 : v8::HandleScope scope(isolate);
12743 : v8::Local<v8::FunctionTemplate> fun_templ =
12744 11 : v8::FunctionTemplate::New(isolate);
12745 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12746 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12747 22 : v8::Signature::New(isolate, fun_templ));
12748 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12749 22 : proto_templ->Set(v8_str("method"), method_templ);
12750 11 : fun_templ->SetHiddenPrototype(true);
12751 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12752 11 : CHECK(!templ.IsEmpty());
12753 22 : LocalContext context;
12754 : v8::Local<v8::Function> fun =
12755 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12756 11 : GenerateSomeGarbage();
12757 66 : CHECK(context->Global()
12758 : ->Set(context.local(), v8_str("o"),
12759 : fun->NewInstance(context.local()).ToLocalChecked())
12760 : .FromJust());
12761 : CompileRun(
12762 : "o.foo = 17;"
12763 : "var receiver = {};"
12764 : "receiver.__proto__ = o;"
12765 : "var result = 0;"
12766 : "var saved_result = 0;"
12767 : "for (var i = 0; i < 100; i++) {"
12768 : " result = receiver.method(41);"
12769 : " if (i == 50) {"
12770 : " saved_result = result;"
12771 : " receiver = {method: function(x) { return x - 1 }};"
12772 : " }"
12773 : "}");
12774 66 : CHECK_EQ(40, context->Global()
12775 : ->Get(context.local(), v8_str("result"))
12776 : .ToLocalChecked()
12777 : ->Int32Value(context.local())
12778 : .FromJust());
12779 66 : CHECK_EQ(42, context->Global()
12780 : ->Get(context.local(), v8_str("saved_result"))
12781 : .ToLocalChecked()
12782 : ->Int32Value(context.local())
12783 11 : .FromJust());
12784 11 : }
12785 :
12786 :
12787 47452 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12788 11 : v8::Isolate* isolate = CcTest::isolate();
12789 11 : v8::HandleScope scope(isolate);
12790 : v8::Local<v8::FunctionTemplate> fun_templ =
12791 11 : v8::FunctionTemplate::New(isolate);
12792 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12793 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12794 22 : v8::Signature::New(isolate, fun_templ));
12795 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12796 22 : proto_templ->Set(v8_str("method"), method_templ);
12797 11 : fun_templ->SetHiddenPrototype(true);
12798 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12799 11 : CHECK(!templ.IsEmpty());
12800 22 : LocalContext context;
12801 : v8::Local<v8::Function> fun =
12802 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12803 11 : GenerateSomeGarbage();
12804 66 : CHECK(context->Global()
12805 : ->Set(context.local(), v8_str("o"),
12806 : fun->NewInstance(context.local()).ToLocalChecked())
12807 : .FromJust());
12808 22 : v8::TryCatch try_catch(isolate);
12809 : CompileRun(
12810 : "o.foo = 17;"
12811 : "var receiver = {};"
12812 : "receiver.__proto__ = o;"
12813 : "var result = 0;"
12814 : "var saved_result = 0;"
12815 : "for (var i = 0; i < 100; i++) {"
12816 : " result = receiver.method(41);"
12817 : " if (i == 50) {"
12818 : " saved_result = result;"
12819 : " receiver = 333;"
12820 : " }"
12821 : "}");
12822 11 : CHECK(try_catch.HasCaught());
12823 : // TODO(verwaest): Adjust message.
12824 55 : CHECK(
12825 : v8_str("TypeError: receiver.method is not a function")
12826 : ->Equals(
12827 : context.local(),
12828 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12829 : .FromJust());
12830 66 : CHECK_EQ(42, context->Global()
12831 : ->Get(context.local(), v8_str("saved_result"))
12832 : .ToLocalChecked()
12833 : ->Int32Value(context.local())
12834 11 : .FromJust());
12835 11 : }
12836 :
12837 :
12838 47452 : THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12839 11 : v8::Isolate* isolate = CcTest::isolate();
12840 11 : v8::HandleScope scope(isolate);
12841 : v8::Local<v8::FunctionTemplate> fun_templ =
12842 11 : v8::FunctionTemplate::New(isolate);
12843 : v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12844 : isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12845 22 : v8::Signature::New(isolate, fun_templ));
12846 11 : v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12847 22 : proto_templ->Set(v8_str("method"), method_templ);
12848 11 : fun_templ->SetHiddenPrototype(true);
12849 11 : v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12850 11 : CHECK(!templ.IsEmpty());
12851 22 : LocalContext context;
12852 : v8::Local<v8::Function> fun =
12853 11 : fun_templ->GetFunction(context.local()).ToLocalChecked();
12854 11 : GenerateSomeGarbage();
12855 66 : CHECK(context->Global()
12856 : ->Set(context.local(), v8_str("o"),
12857 : fun->NewInstance(context.local()).ToLocalChecked())
12858 : .FromJust());
12859 22 : v8::TryCatch try_catch(isolate);
12860 : CompileRun(
12861 : "o.foo = 17;"
12862 : "var receiver = {};"
12863 : "receiver.__proto__ = o;"
12864 : "var result = 0;"
12865 : "var saved_result = 0;"
12866 : "for (var i = 0; i < 100; i++) {"
12867 : " result = receiver.method(41);"
12868 : " if (i == 50) {"
12869 : " saved_result = result;"
12870 : " receiver = Object.create(receiver);"
12871 : " }"
12872 : "}");
12873 11 : CHECK(try_catch.HasCaught());
12874 55 : CHECK(
12875 : v8_str("TypeError: Illegal invocation")
12876 : ->Equals(
12877 : context.local(),
12878 : try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12879 : .FromJust());
12880 66 : CHECK_EQ(42, context->Global()
12881 : ->Get(context.local(), v8_str("saved_result"))
12882 : .ToLocalChecked()
12883 : ->Int32Value(context.local())
12884 11 : .FromJust());
12885 11 : }
12886 :
12887 :
12888 24 : static void ThrowingGetter(Local<String> name,
12889 : const v8::PropertyCallbackInfo<v8::Value>& info) {
12890 24 : ApiTestFuzzer::Fuzz();
12891 24 : info.GetIsolate()->ThrowException(Local<Value>());
12892 : info.GetReturnValue().SetUndefined();
12893 24 : }
12894 :
12895 :
12896 23724 : THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12897 6 : LocalContext context;
12898 12 : HandleScope scope(context->GetIsolate());
12899 :
12900 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12901 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12902 12 : instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12903 :
12904 6 : Local<Object> instance = templ->GetFunction(context.local())
12905 6 : .ToLocalChecked()
12906 6 : ->NewInstance(context.local())
12907 : .ToLocalChecked();
12908 :
12909 6 : Local<Object> another = Object::New(context->GetIsolate());
12910 12 : CHECK(another->SetPrototype(context.local(), instance).FromJust());
12911 :
12912 : Local<Object> with_js_getter = CompileRun(
12913 : "o = {};\n"
12914 : "o.__defineGetter__('f', function() { throw undefined; });\n"
12915 : "o\n").As<Object>();
12916 6 : CHECK(!with_js_getter.IsEmpty());
12917 :
12918 12 : TryCatch try_catch(context->GetIsolate());
12919 :
12920 : v8::MaybeLocal<Value> result =
12921 12 : instance->GetRealNamedProperty(context.local(), v8_str("f"));
12922 6 : CHECK(try_catch.HasCaught());
12923 6 : try_catch.Reset();
12924 6 : CHECK(result.IsEmpty());
12925 :
12926 : Maybe<PropertyAttribute> attr =
12927 12 : instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12928 6 : CHECK(!try_catch.HasCaught());
12929 6 : CHECK(Just(None) == attr);
12930 :
12931 12 : result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12932 6 : CHECK(try_catch.HasCaught());
12933 6 : try_catch.Reset();
12934 6 : CHECK(result.IsEmpty());
12935 :
12936 12 : attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12937 6 : CHECK(!try_catch.HasCaught());
12938 6 : CHECK(Just(None) == attr);
12939 :
12940 : result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12941 12 : v8_str("f"));
12942 6 : CHECK(try_catch.HasCaught());
12943 6 : try_catch.Reset();
12944 6 : CHECK(result.IsEmpty());
12945 :
12946 : attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12947 12 : context.local(), v8_str("f"));
12948 6 : CHECK(!try_catch.HasCaught());
12949 6 : CHECK(Just(None) == attr);
12950 :
12951 12 : result = another->Get(context.local(), v8_str("f"));
12952 6 : CHECK(try_catch.HasCaught());
12953 6 : try_catch.Reset();
12954 6 : CHECK(result.IsEmpty());
12955 :
12956 12 : result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12957 6 : CHECK(try_catch.HasCaught());
12958 6 : try_catch.Reset();
12959 6 : CHECK(result.IsEmpty());
12960 :
12961 : attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12962 12 : v8_str("f"));
12963 6 : CHECK(!try_catch.HasCaught());
12964 6 : CHECK(Just(None) == attr);
12965 :
12966 12 : result = with_js_getter->Get(context.local(), v8_str("f"));
12967 6 : CHECK(try_catch.HasCaught());
12968 6 : try_catch.Reset();
12969 6 : CHECK(result.IsEmpty());
12970 :
12971 : Local<Object> target = CompileRun("({})").As<Object>();
12972 6 : Local<Object> handler = CompileRun("({})").As<Object>();
12973 : Local<v8::Proxy> proxy =
12974 6 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12975 :
12976 12 : result = target->GetRealNamedProperty(context.local(), v8_str("f"));
12977 6 : CHECK(!try_catch.HasCaught());
12978 6 : CHECK(result.IsEmpty());
12979 :
12980 12 : result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
12981 6 : CHECK(!try_catch.HasCaught());
12982 12 : CHECK(result.IsEmpty());
12983 6 : }
12984 :
12985 :
12986 30 : static void ThrowingCallbackWithTryCatch(
12987 30 : const v8::FunctionCallbackInfo<v8::Value>& args) {
12988 30 : TryCatch try_catch(args.GetIsolate());
12989 : // Verboseness is important: it triggers message delivery which can call into
12990 : // external code.
12991 30 : try_catch.SetVerbose(true);
12992 : CompileRun("throw 'from JS';");
12993 30 : CHECK(try_catch.HasCaught());
12994 30 : CHECK(!CcTest::i_isolate()->has_pending_exception());
12995 30 : CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12996 30 : }
12997 :
12998 :
12999 : static int call_depth;
13000 :
13001 :
13002 6 : static void WithTryCatch(Local<Message> message, Local<Value> data) {
13003 6 : TryCatch try_catch(CcTest::isolate());
13004 6 : }
13005 :
13006 :
13007 6 : static void ThrowFromJS(Local<Message> message, Local<Value> data) {
13008 6 : if (--call_depth) CompileRun("throw 'ThrowInJS';");
13009 6 : }
13010 :
13011 :
13012 6 : static void ThrowViaApi(Local<Message> message, Local<Value> data) {
13013 12 : if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13014 6 : }
13015 :
13016 :
13017 6 : static void WebKitLike(Local<Message> message, Local<Value> data) {
13018 6 : Local<String> errorMessageString = message->Get();
13019 6 : CHECK(!errorMessageString.IsEmpty());
13020 6 : message->GetStackTrace();
13021 6 : message->GetScriptOrigin().ResourceName();
13022 6 : }
13023 :
13024 :
13025 23724 : THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13026 6 : LocalContext context;
13027 6 : v8::Isolate* isolate = context->GetIsolate();
13028 12 : HandleScope scope(isolate);
13029 :
13030 : Local<Function> func =
13031 6 : FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
13032 18 : ->GetFunction(context.local())
13033 6 : .ToLocalChecked();
13034 30 : CHECK(
13035 : context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
13036 :
13037 : MessageCallback callbacks[] = {nullptr, WebKitLike, ThrowViaApi, ThrowFromJS,
13038 6 : WithTryCatch};
13039 36 : for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13040 30 : MessageCallback callback = callbacks[i];
13041 30 : if (callback != nullptr) {
13042 24 : isolate->AddMessageListener(callback);
13043 : }
13044 : // Some small number to control number of times message handler should
13045 : // throw an exception.
13046 30 : call_depth = 5;
13047 : ExpectFalse(
13048 : "var thrown = false;\n"
13049 : "try { func(); } catch(e) { thrown = true; }\n"
13050 : "thrown\n");
13051 30 : if (callback != nullptr) {
13052 24 : isolate->RemoveMessageListeners(callback);
13053 : }
13054 6 : }
13055 6 : }
13056 :
13057 :
13058 6 : static void ParentGetter(Local<String> name,
13059 : const v8::PropertyCallbackInfo<v8::Value>& info) {
13060 6 : ApiTestFuzzer::Fuzz();
13061 6 : info.GetReturnValue().Set(v8_num(1));
13062 6 : }
13063 :
13064 :
13065 18 : static void ChildGetter(Local<String> name,
13066 : const v8::PropertyCallbackInfo<v8::Value>& info) {
13067 18 : ApiTestFuzzer::Fuzz();
13068 18 : info.GetReturnValue().Set(v8_num(42));
13069 18 : }
13070 :
13071 :
13072 23724 : THREADED_TEST(Overriding) {
13073 6 : LocalContext context;
13074 6 : v8::Isolate* isolate = context->GetIsolate();
13075 12 : v8::HandleScope scope(isolate);
13076 :
13077 : // Parent template.
13078 6 : Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13079 : Local<ObjectTemplate> parent_instance_templ =
13080 6 : parent_templ->InstanceTemplate();
13081 12 : parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13082 :
13083 : // Template that inherits from the parent template.
13084 6 : Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13085 : Local<ObjectTemplate> child_instance_templ =
13086 6 : child_templ->InstanceTemplate();
13087 6 : child_templ->Inherit(parent_templ);
13088 : // Override 'f'. The child version of 'f' should get called for child
13089 : // instances.
13090 6 : child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13091 : // Add 'g' twice. The 'g' added last should get called for instances.
13092 6 : child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13093 6 : child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13094 :
13095 : // Add 'h' as an accessor to the proto template with ReadOnly attributes
13096 : // so 'h' can be shadowed on the instance object.
13097 6 : Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13098 : child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13099 12 : v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
13100 :
13101 : // Add 'i' as an accessor to the instance template with ReadOnly attributes
13102 : // but the attribute does not have effect because it is duplicated with
13103 : // nullptr setter.
13104 : child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13105 : v8::Local<Value>(), v8::DEFAULT,
13106 6 : v8::ReadOnly);
13107 :
13108 :
13109 : // Instantiate the child template.
13110 6 : Local<v8::Object> instance = child_templ->GetFunction(context.local())
13111 6 : .ToLocalChecked()
13112 6 : ->NewInstance(context.local())
13113 : .ToLocalChecked();
13114 :
13115 : // Check that the child function overrides the parent one.
13116 30 : CHECK(context->Global()
13117 : ->Set(context.local(), v8_str("o"), instance)
13118 : .FromJust());
13119 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13120 : // Check that the 'g' that was added last is hit.
13121 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13122 12 : value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
13123 12 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13124 :
13125 : // Check that 'h' cannot be shadowed.
13126 12 : value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
13127 12 : CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
13128 :
13129 : // Check that 'i' cannot be shadowed or changed.
13130 12 : value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
13131 18 : CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13132 6 : }
13133 :
13134 :
13135 24 : static void ShouldThrowOnErrorGetter(
13136 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13137 24 : ApiTestFuzzer::Fuzz();
13138 : v8::Isolate* isolate = info.GetIsolate();
13139 : Local<Boolean> should_throw_on_error =
13140 : Boolean::New(isolate, info.ShouldThrowOnError());
13141 : info.GetReturnValue().Set(should_throw_on_error);
13142 24 : }
13143 :
13144 :
13145 : template <typename T>
13146 24 : static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
13147 : const v8::PropertyCallbackInfo<T>& info) {
13148 24 : ApiTestFuzzer::Fuzz();
13149 : v8::Isolate* isolate = info.GetIsolate();
13150 24 : auto context = isolate->GetCurrentContext();
13151 : Local<Boolean> should_throw_on_error_value =
13152 : Boolean::New(isolate, info.ShouldThrowOnError());
13153 120 : CHECK(context->Global()
13154 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
13155 : should_throw_on_error_value)
13156 : .FromJust());
13157 24 : }
13158 :
13159 :
13160 23724 : THREADED_TEST(AccessorShouldThrowOnError) {
13161 6 : LocalContext context;
13162 6 : v8::Isolate* isolate = context->GetIsolate();
13163 12 : v8::HandleScope scope(isolate);
13164 6 : Local<Object> global = context->Global();
13165 :
13166 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13167 6 : Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13168 : instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
13169 12 : ShouldThrowOnErrorSetter<void>);
13170 :
13171 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13172 6 : .ToLocalChecked()
13173 6 : ->NewInstance(context.local())
13174 : .ToLocalChecked();
13175 :
13176 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13177 :
13178 : // SLOPPY mode
13179 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13180 6 : CHECK(value->IsFalse());
13181 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13182 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13183 6 : .ToLocalChecked();
13184 6 : CHECK(value->IsFalse());
13185 :
13186 : // STRICT mode
13187 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13188 6 : CHECK(value->IsFalse());
13189 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13190 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13191 6 : .ToLocalChecked();
13192 12 : CHECK(value->IsTrue());
13193 6 : }
13194 :
13195 :
13196 0 : static void ShouldThrowOnErrorQuery(
13197 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
13198 0 : ApiTestFuzzer::Fuzz();
13199 : v8::Isolate* isolate = info.GetIsolate();
13200 : info.GetReturnValue().Set(v8::None);
13201 :
13202 0 : auto context = isolate->GetCurrentContext();
13203 : Local<Boolean> should_throw_on_error_value =
13204 : Boolean::New(isolate, info.ShouldThrowOnError());
13205 0 : CHECK(context->Global()
13206 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
13207 : should_throw_on_error_value)
13208 : .FromJust());
13209 0 : }
13210 :
13211 :
13212 12 : static void ShouldThrowOnErrorDeleter(
13213 : Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
13214 12 : ApiTestFuzzer::Fuzz();
13215 : v8::Isolate* isolate = info.GetIsolate();
13216 : info.GetReturnValue().Set(v8::True(isolate));
13217 :
13218 12 : auto context = isolate->GetCurrentContext();
13219 : Local<Boolean> should_throw_on_error_value =
13220 : Boolean::New(isolate, info.ShouldThrowOnError());
13221 60 : CHECK(context->Global()
13222 : ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
13223 : should_throw_on_error_value)
13224 : .FromJust());
13225 12 : }
13226 :
13227 :
13228 12 : static void ShouldThrowOnErrorPropertyEnumerator(
13229 : const v8::PropertyCallbackInfo<v8::Array>& info) {
13230 12 : ApiTestFuzzer::Fuzz();
13231 : v8::Isolate* isolate = info.GetIsolate();
13232 12 : Local<v8::Array> names = v8::Array::New(isolate, 1);
13233 36 : CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
13234 : info.GetReturnValue().Set(names);
13235 :
13236 12 : auto context = isolate->GetCurrentContext();
13237 : Local<Boolean> should_throw_on_error_value =
13238 : Boolean::New(isolate, info.ShouldThrowOnError());
13239 60 : CHECK(context->Global()
13240 : ->Set(isolate->GetCurrentContext(),
13241 : v8_str("should_throw_enumerator"),
13242 : should_throw_on_error_value)
13243 : .FromJust());
13244 12 : }
13245 :
13246 :
13247 23724 : THREADED_TEST(InterceptorShouldThrowOnError) {
13248 6 : LocalContext context;
13249 6 : v8::Isolate* isolate = context->GetIsolate();
13250 12 : v8::HandleScope scope(isolate);
13251 6 : Local<Object> global = context->Global();
13252 :
13253 6 : auto interceptor_templ = v8::ObjectTemplate::New(isolate);
13254 : v8::NamedPropertyHandlerConfiguration handler(
13255 : ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
13256 : ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
13257 : ShouldThrowOnErrorPropertyEnumerator);
13258 6 : interceptor_templ->SetHandler(handler);
13259 :
13260 : Local<v8::Object> instance =
13261 6 : interceptor_templ->NewInstance(context.local()).ToLocalChecked();
13262 :
13263 18 : CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13264 :
13265 : // SLOPPY mode
13266 12 : Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13267 6 : CHECK(value->IsFalse());
13268 12 : v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13269 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13270 6 : .ToLocalChecked();
13271 6 : CHECK(value->IsFalse());
13272 :
13273 12 : v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
13274 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
13275 6 : .ToLocalChecked();
13276 6 : CHECK(value->IsFalse());
13277 :
13278 : v8_compile("Object.getOwnPropertyNames(o)")
13279 6 : ->Run(context.local())
13280 6 : .ToLocalChecked();
13281 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13282 6 : .ToLocalChecked();
13283 6 : CHECK(value->IsFalse());
13284 :
13285 : // STRICT mode
13286 12 : value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13287 6 : CHECK(value->IsFalse());
13288 12 : v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13289 18 : value = global->Get(context.local(), v8_str("should_throw_setter"))
13290 6 : .ToLocalChecked();
13291 6 : CHECK(value->IsTrue());
13292 :
13293 12 : v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
13294 18 : value = global->Get(context.local(), v8_str("should_throw_deleter"))
13295 6 : .ToLocalChecked();
13296 6 : CHECK(value->IsTrue());
13297 :
13298 : v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
13299 6 : ->Run(context.local())
13300 6 : .ToLocalChecked();
13301 18 : value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13302 6 : .ToLocalChecked();
13303 12 : CHECK(value->IsFalse());
13304 6 : }
13305 :
13306 :
13307 12 : static void IsConstructHandler(
13308 : const v8::FunctionCallbackInfo<v8::Value>& args) {
13309 12 : ApiTestFuzzer::Fuzz();
13310 : args.GetReturnValue().Set(args.IsConstructCall());
13311 12 : }
13312 :
13313 :
13314 23724 : THREADED_TEST(IsConstructCall) {
13315 6 : v8::Isolate* isolate = CcTest::isolate();
13316 6 : v8::HandleScope scope(isolate);
13317 :
13318 : // Function template with call handler.
13319 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13320 6 : templ->SetCallHandler(IsConstructHandler);
13321 :
13322 12 : LocalContext context;
13323 :
13324 36 : CHECK(context->Global()
13325 : ->Set(context.local(), v8_str("f"),
13326 : templ->GetFunction(context.local()).ToLocalChecked())
13327 : .FromJust());
13328 12 : Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
13329 12 : CHECK(!value->BooleanValue(context.local()).FromJust());
13330 12 : value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
13331 18 : CHECK(value->BooleanValue(context.local()).FromJust());
13332 6 : }
13333 :
13334 48 : static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
13335 24 : ApiTestFuzzer::Fuzz();
13336 : args.GetReturnValue().Set(args.NewTarget());
13337 24 : }
13338 :
13339 23724 : THREADED_TEST(NewTargetHandler) {
13340 6 : v8::Isolate* isolate = CcTest::isolate();
13341 6 : v8::HandleScope scope(isolate);
13342 :
13343 : // Function template with call handler.
13344 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13345 6 : templ->SetCallHandler(NewTargetHandler);
13346 :
13347 12 : LocalContext context;
13348 :
13349 : Local<Function> function =
13350 6 : templ->GetFunction(context.local()).ToLocalChecked();
13351 30 : CHECK(context->Global()
13352 : ->Set(context.local(), v8_str("f"), function)
13353 : .FromJust());
13354 : Local<Value> value = CompileRun("f()");
13355 6 : CHECK(value->IsUndefined());
13356 : value = CompileRun("new f()");
13357 6 : CHECK(value->IsFunction());
13358 6 : CHECK(value == function);
13359 : Local<Value> subclass = CompileRun("var g = class extends f { }; g");
13360 6 : CHECK(subclass->IsFunction());
13361 : value = CompileRun("new g()");
13362 6 : CHECK(value->IsFunction());
13363 6 : CHECK(value == subclass);
13364 : value = CompileRun("Reflect.construct(f, [], Array)");
13365 6 : CHECK(value->IsFunction());
13366 30 : CHECK(value ==
13367 : context->Global()
13368 : ->Get(context.local(), v8_str("Array"))
13369 6 : .ToLocalChecked());
13370 6 : }
13371 :
13372 23724 : THREADED_TEST(ObjectProtoToString) {
13373 6 : v8::Isolate* isolate = CcTest::isolate();
13374 6 : v8::HandleScope scope(isolate);
13375 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13376 6 : templ->SetClassName(v8_str("MyClass"));
13377 :
13378 12 : LocalContext context;
13379 :
13380 6 : Local<String> customized_tostring = v8_str("customized toString");
13381 :
13382 : // Replace Object.prototype.toString
13383 : v8_compile(
13384 : "Object.prototype.toString = function() {"
13385 : " return 'customized toString';"
13386 : "}")
13387 6 : ->Run(context.local())
13388 6 : .ToLocalChecked();
13389 :
13390 : // Normal ToString call should call replaced Object.prototype.toString
13391 6 : Local<v8::Object> instance = templ->GetFunction(context.local())
13392 6 : .ToLocalChecked()
13393 6 : ->NewInstance(context.local())
13394 : .ToLocalChecked();
13395 6 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13396 18 : CHECK(value->IsString() &&
13397 : value->Equals(context.local(), customized_tostring).FromJust());
13398 :
13399 : // ObjectProtoToString should not call replace toString function.
13400 6 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13401 18 : CHECK(value->IsString() &&
13402 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13403 :
13404 : // Check global
13405 : value =
13406 24 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13407 18 : CHECK(value->IsString() &&
13408 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13409 :
13410 : // Check ordinary object
13411 : Local<Value> object =
13412 12 : v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13413 : value = object.As<v8::Object>()
13414 6 : ->ObjectProtoToString(context.local())
13415 6 : .ToLocalChecked();
13416 18 : CHECK(value->IsString() &&
13417 6 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13418 6 : }
13419 :
13420 :
13421 23723 : TEST(ObjectProtoToStringES6) {
13422 5 : LocalContext context;
13423 5 : v8::Isolate* isolate = CcTest::isolate();
13424 10 : v8::HandleScope scope(isolate);
13425 5 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13426 5 : templ->SetClassName(v8_str("MyClass"));
13427 :
13428 5 : Local<String> customized_tostring = v8_str("customized toString");
13429 :
13430 : // Replace Object.prototype.toString
13431 : CompileRun(
13432 : "Object.prototype.toString = function() {"
13433 : " return 'customized toString';"
13434 : "}");
13435 :
13436 : // Normal ToString call should call replaced Object.prototype.toString
13437 5 : Local<v8::Object> instance = templ->GetFunction(context.local())
13438 5 : .ToLocalChecked()
13439 5 : ->NewInstance(context.local())
13440 : .ToLocalChecked();
13441 5 : Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13442 15 : CHECK(value->IsString() &&
13443 : value->Equals(context.local(), customized_tostring).FromJust());
13444 :
13445 : // ObjectProtoToString should not call replace toString function.
13446 5 : value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13447 15 : CHECK(value->IsString() &&
13448 : value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13449 :
13450 : // Check global
13451 : value =
13452 20 : context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13453 15 : CHECK(value->IsString() &&
13454 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13455 :
13456 : // Check ordinary object
13457 : Local<Value> object = CompileRun("new Object()");
13458 : value = object.As<v8::Object>()
13459 5 : ->ObjectProtoToString(context.local())
13460 5 : .ToLocalChecked();
13461 15 : CHECK(value->IsString() &&
13462 : value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13463 :
13464 : // Check that ES6 semantics using @@toStringTag work
13465 5 : Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13466 :
13467 : #define TEST_TOSTRINGTAG(type, tag, expected) \
13468 : do { \
13469 : object = CompileRun("new " #type "()"); \
13470 : CHECK(object.As<v8::Object>() \
13471 : ->Set(context.local(), toStringTag, v8_str(#tag)) \
13472 : .FromJust()); \
13473 : value = object.As<v8::Object>() \
13474 : ->ObjectProtoToString(context.local()) \
13475 : .ToLocalChecked(); \
13476 : CHECK(value->IsString() && \
13477 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13478 : .FromJust()); \
13479 : } while (0)
13480 :
13481 30 : TEST_TOSTRINGTAG(Array, Object, Object);
13482 30 : TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13483 30 : TEST_TOSTRINGTAG(Object, Array, Array);
13484 30 : TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13485 30 : TEST_TOSTRINGTAG(Object, Date, Date);
13486 30 : TEST_TOSTRINGTAG(Object, Error, Error);
13487 30 : TEST_TOSTRINGTAG(Object, Function, Function);
13488 30 : TEST_TOSTRINGTAG(Object, Number, Number);
13489 30 : TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13490 30 : TEST_TOSTRINGTAG(Object, String, String);
13491 30 : TEST_TOSTRINGTAG(Object, Foo, Foo);
13492 :
13493 : #undef TEST_TOSTRINGTAG
13494 :
13495 : Local<v8::RegExp> valueRegExp =
13496 5 : v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13497 5 : .ToLocalChecked();
13498 5 : Local<Value> valueNumber = v8_num(123);
13499 5 : Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13500 : Local<v8::Function> valueFunction =
13501 : CompileRun("(function fn() {})").As<v8::Function>();
13502 5 : Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13503 5 : Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13504 5 : Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13505 :
13506 : #define TEST_TOSTRINGTAG(type, tagValue, expected) \
13507 : do { \
13508 : object = CompileRun("new " #type "()"); \
13509 : CHECK(object.As<v8::Object>() \
13510 : ->Set(context.local(), toStringTag, tagValue) \
13511 : .FromJust()); \
13512 : value = object.As<v8::Object>() \
13513 : ->ObjectProtoToString(context.local()) \
13514 : .ToLocalChecked(); \
13515 : CHECK(value->IsString() && \
13516 : value->Equals(context.local(), v8_str("[object " #expected "]")) \
13517 : .FromJust()); \
13518 : } while (0)
13519 :
13520 : #define TEST_TOSTRINGTAG_TYPES(tagValue) \
13521 : TEST_TOSTRINGTAG(Array, tagValue, Array); \
13522 : TEST_TOSTRINGTAG(Object, tagValue, Object); \
13523 : TEST_TOSTRINGTAG(Function, tagValue, Function); \
13524 : TEST_TOSTRINGTAG(Date, tagValue, Date); \
13525 : TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13526 : TEST_TOSTRINGTAG(Error, tagValue, Error); \
13527 :
13528 : // Test non-String-valued @@toStringTag
13529 150 : TEST_TOSTRINGTAG_TYPES(valueRegExp);
13530 150 : TEST_TOSTRINGTAG_TYPES(valueNumber);
13531 150 : TEST_TOSTRINGTAG_TYPES(valueSymbol);
13532 150 : TEST_TOSTRINGTAG_TYPES(valueFunction);
13533 150 : TEST_TOSTRINGTAG_TYPES(valueObject);
13534 150 : TEST_TOSTRINGTAG_TYPES(valueNull);
13535 150 : TEST_TOSTRINGTAG_TYPES(valueUndef);
13536 :
13537 : #undef TEST_TOSTRINGTAG
13538 : #undef TEST_TOSTRINGTAG_TYPES
13539 :
13540 : // @@toStringTag getter throws
13541 5 : Local<Value> obj = v8::Object::New(isolate);
13542 : obj.As<v8::Object>()
13543 10 : ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13544 10 : .FromJust();
13545 : {
13546 5 : TryCatch try_catch(isolate);
13547 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13548 5 : CHECK(try_catch.HasCaught());
13549 : }
13550 :
13551 : // @@toStringTag getter does not throw
13552 5 : obj = v8::Object::New(isolate);
13553 : obj.As<v8::Object>()
13554 : ->SetAccessor(context.local(), toStringTag,
13555 15 : SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"))
13556 10 : .FromJust();
13557 : {
13558 5 : TryCatch try_catch(isolate);
13559 : value = obj.As<v8::Object>()
13560 5 : ->ObjectProtoToString(context.local())
13561 5 : .ToLocalChecked();
13562 15 : CHECK(value->IsString() &&
13563 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13564 5 : CHECK(!try_catch.HasCaught());
13565 : }
13566 :
13567 : // JS @@toStringTag value
13568 : obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13569 : {
13570 5 : TryCatch try_catch(isolate);
13571 : value = obj.As<v8::Object>()
13572 5 : ->ObjectProtoToString(context.local())
13573 5 : .ToLocalChecked();
13574 15 : CHECK(value->IsString() &&
13575 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13576 5 : CHECK(!try_catch.HasCaught());
13577 : }
13578 :
13579 : // JS @@toStringTag getter throws
13580 : obj = CompileRun(
13581 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13582 : " get: function() { throw 'Test'; }"
13583 : "}); obj");
13584 : {
13585 5 : TryCatch try_catch(isolate);
13586 10 : CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13587 5 : CHECK(try_catch.HasCaught());
13588 : }
13589 :
13590 : // JS @@toStringTag getter does not throw
13591 : obj = CompileRun(
13592 : "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13593 : " get: function() { return 'Test'; }"
13594 : "}); obj");
13595 : {
13596 5 : TryCatch try_catch(isolate);
13597 : value = obj.As<v8::Object>()
13598 5 : ->ObjectProtoToString(context.local())
13599 5 : .ToLocalChecked();
13600 15 : CHECK(value->IsString() &&
13601 : value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13602 5 : CHECK(!try_catch.HasCaught());
13603 5 : }
13604 5 : }
13605 :
13606 :
13607 23724 : THREADED_TEST(ObjectGetConstructorName) {
13608 6 : v8::Isolate* isolate = CcTest::isolate();
13609 6 : LocalContext context;
13610 12 : v8::HandleScope scope(isolate);
13611 : v8_compile(
13612 : "function Parent() {};"
13613 : "function Child() {};"
13614 : "Child.prototype = new Parent();"
13615 : "Child.prototype.constructor = Child;"
13616 : "var outer = { inner: (0, function() { }) };"
13617 : "var p = new Parent();"
13618 : "var c = new Child();"
13619 : "var x = new outer.inner();"
13620 : "var proto = Child.prototype;")
13621 6 : ->Run(context.local())
13622 6 : .ToLocalChecked();
13623 :
13624 : Local<v8::Value> p =
13625 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13626 30 : CHECK(p->IsObject() &&
13627 : p->ToObject(context.local())
13628 : .ToLocalChecked()
13629 : ->GetConstructorName()
13630 : ->Equals(context.local(), v8_str("Parent"))
13631 : .FromJust());
13632 :
13633 : Local<v8::Value> c =
13634 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13635 30 : CHECK(c->IsObject() &&
13636 : c->ToObject(context.local())
13637 : .ToLocalChecked()
13638 : ->GetConstructorName()
13639 : ->Equals(context.local(), v8_str("Child"))
13640 : .FromJust());
13641 :
13642 : Local<v8::Value> x =
13643 30 : context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13644 30 : CHECK(x->IsObject() &&
13645 : x->ToObject(context.local())
13646 : .ToLocalChecked()
13647 : ->GetConstructorName()
13648 : ->Equals(context.local(), v8_str("outer.inner"))
13649 : .FromJust());
13650 :
13651 : Local<v8::Value> child_prototype =
13652 30 : context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13653 30 : CHECK(child_prototype->IsObject() &&
13654 : child_prototype->ToObject(context.local())
13655 : .ToLocalChecked()
13656 : ->GetConstructorName()
13657 : ->Equals(context.local(), v8_str("Parent"))
13658 6 : .FromJust());
13659 6 : }
13660 :
13661 :
13662 23724 : THREADED_TEST(SubclassGetConstructorName) {
13663 6 : v8::Isolate* isolate = CcTest::isolate();
13664 6 : LocalContext context;
13665 12 : v8::HandleScope scope(isolate);
13666 : v8_compile(
13667 : "\"use strict\";"
13668 : "class Parent {}"
13669 : "class Child extends Parent {}"
13670 : "var p = new Parent();"
13671 : "var c = new Child();")
13672 6 : ->Run(context.local())
13673 6 : .ToLocalChecked();
13674 :
13675 : Local<v8::Value> p =
13676 30 : context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13677 30 : CHECK(p->IsObject() &&
13678 : p->ToObject(context.local())
13679 : .ToLocalChecked()
13680 : ->GetConstructorName()
13681 : ->Equals(context.local(), v8_str("Parent"))
13682 : .FromJust());
13683 :
13684 : Local<v8::Value> c =
13685 30 : context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13686 30 : CHECK(c->IsObject() &&
13687 : c->ToObject(context.local())
13688 : .ToLocalChecked()
13689 : ->GetConstructorName()
13690 : ->Equals(context.local(), v8_str("Child"))
13691 6 : .FromJust());
13692 6 : }
13693 :
13694 :
13695 : bool ApiTestFuzzer::fuzzing_ = false;
13696 23718 : v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13697 : int ApiTestFuzzer::active_tests_;
13698 : int ApiTestFuzzer::tests_being_run_;
13699 : int ApiTestFuzzer::current_;
13700 :
13701 :
13702 : // We are in a callback and want to switch to another thread (if we
13703 : // are currently running the thread fuzzing test).
13704 470793 : void ApiTestFuzzer::Fuzz() {
13705 941586 : if (!fuzzing_) return;
13706 77223 : ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13707 77223 : test->ContextSwitch();
13708 : }
13709 :
13710 :
13711 : // Let the next thread go. Since it is also waiting on the V8 lock it may
13712 : // not start immediately.
13713 77694 : bool ApiTestFuzzer::NextThread() {
13714 77694 : int test_position = GetNextTestNumber();
13715 77694 : const char* test_name = RegisterThreadedTest::nth(current_)->name();
13716 77694 : if (test_position == current_) {
13717 : if (kLogThreading)
13718 : printf("Stay with %s\n", test_name);
13719 : return false;
13720 : }
13721 : if (kLogThreading) {
13722 : printf("Switch from %s to %s\n",
13723 : test_name,
13724 : RegisterThreadedTest::nth(test_position)->name());
13725 : }
13726 23568 : current_ = test_position;
13727 23568 : RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13728 23568 : return true;
13729 : }
13730 :
13731 :
13732 471 : void ApiTestFuzzer::Run() {
13733 : // When it is our turn...
13734 471 : gate_.Wait();
13735 : {
13736 : // ... get the V8 lock and start running the test.
13737 471 : v8::Locker locker(CcTest::isolate());
13738 471 : CallTest();
13739 : }
13740 : // This test finished.
13741 471 : active_ = false;
13742 471 : active_tests_--;
13743 : // If it was the last then signal that fact.
13744 471 : if (active_tests_ == 0) {
13745 8 : all_tests_done_.Signal();
13746 : } else {
13747 : // Otherwise select a new test and start that.
13748 463 : NextThread();
13749 : }
13750 471 : }
13751 :
13752 :
13753 : static unsigned linear_congruential_generator;
13754 :
13755 :
13756 8 : void ApiTestFuzzer::SetUp(PartOfTest part) {
13757 8 : linear_congruential_generator = i::FLAG_testing_prng_seed;
13758 8 : fuzzing_ = true;
13759 : int count = RegisterThreadedTest::count();
13760 8 : int start = count * part / (LAST_PART + 1);
13761 8 : int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13762 8 : active_tests_ = tests_being_run_ = end - start + 1;
13763 479 : for (int i = 0; i < tests_being_run_; i++) {
13764 471 : RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13765 : }
13766 471 : for (int i = 0; i < active_tests_; i++) {
13767 471 : RegisterThreadedTest::nth(i)->fuzzer_->Start();
13768 : }
13769 8 : }
13770 :
13771 :
13772 : static void CallTestNumber(int test_number) {
13773 471 : (RegisterThreadedTest::nth(test_number)->callback())();
13774 : }
13775 :
13776 :
13777 0 : void ApiTestFuzzer::RunAllTests() {
13778 : // Set off the first test.
13779 8 : current_ = -1;
13780 8 : NextThread();
13781 : // Wait till they are all done.
13782 8 : all_tests_done_.Wait();
13783 0 : }
13784 :
13785 :
13786 77694 : int ApiTestFuzzer::GetNextTestNumber() {
13787 : int next_test;
13788 3188791 : do {
13789 3188791 : next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13790 3188791 : linear_congruential_generator *= 1664525u;
13791 3188791 : linear_congruential_generator += 1013904223u;
13792 3188791 : } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13793 77694 : return next_test;
13794 : }
13795 :
13796 :
13797 77223 : void ApiTestFuzzer::ContextSwitch() {
13798 : // If the new thread is the same as the current thread there is nothing to do.
13799 77223 : if (NextThread()) {
13800 : // Now it can start.
13801 23097 : v8::Unlocker unlocker(CcTest::isolate());
13802 : // Wait till someone starts us again.
13803 23097 : gate_.Wait();
13804 : // And we're off.
13805 : }
13806 77223 : }
13807 :
13808 :
13809 8 : void ApiTestFuzzer::TearDown() {
13810 8 : fuzzing_ = false;
13811 7552 : for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13812 3768 : ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13813 3768 : if (fuzzer != nullptr) fuzzer->Join();
13814 : }
13815 8 : }
13816 :
13817 471 : void ApiTestFuzzer::CallTest() {
13818 471 : v8::Isolate::Scope scope(CcTest::isolate());
13819 : if (kLogThreading)
13820 : printf("Start test %s #%d\n",
13821 : RegisterThreadedTest::nth(test_number_)->name(), test_number_);
13822 471 : CallTestNumber(test_number_);
13823 : if (kLogThreading)
13824 : printf("End test %s #%d\n", RegisterThreadedTest::nth(test_number_)->name(),
13825 : test_number_);
13826 471 : }
13827 :
13828 : #define THREADING_TEST(INDEX, NAME) \
13829 : TEST(Threading##INDEX) { \
13830 : ApiTestFuzzer::SetUp(ApiTestFuzzer::NAME); \
13831 : ApiTestFuzzer::RunAllTests(); \
13832 : ApiTestFuzzer::TearDown(); \
13833 : }
13834 :
13835 23720 : THREADING_TEST(1, FIRST_PART)
13836 23720 : THREADING_TEST(2, SECOND_PART)
13837 23720 : THREADING_TEST(3, THIRD_PART)
13838 23720 : THREADING_TEST(4, FOURTH_PART)
13839 23720 : THREADING_TEST(5, FIFTH_PART)
13840 23720 : THREADING_TEST(6, SIXTH_PART)
13841 23720 : THREADING_TEST(7, SEVENTH_PART)
13842 23720 : THREADING_TEST(8, EIGHTH_PART)
13843 :
13844 : #undef THREADING_TEST
13845 :
13846 10 : static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13847 : v8::Isolate* isolate = args.GetIsolate();
13848 5 : CHECK(v8::Locker::IsLocked(isolate));
13849 5 : ApiTestFuzzer::Fuzz();
13850 : v8::Unlocker unlocker(isolate);
13851 : const char* code = "throw 7;";
13852 : {
13853 : v8::Locker nested_locker(isolate);
13854 10 : v8::HandleScope scope(isolate);
13855 : v8::Local<Value> exception;
13856 : {
13857 5 : v8::TryCatch try_catch(isolate);
13858 : v8::Local<Value> value = CompileRun(code);
13859 5 : CHECK(value.IsEmpty());
13860 5 : CHECK(try_catch.HasCaught());
13861 : // Make sure to wrap the exception in a new handle because
13862 : // the handle returned from the TryCatch is destroyed
13863 : // when the TryCatch is destroyed.
13864 10 : exception = Local<Value>::New(isolate, try_catch.Exception());
13865 : }
13866 10 : args.GetIsolate()->ThrowException(exception);
13867 5 : }
13868 5 : }
13869 :
13870 :
13871 15 : static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13872 5 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13873 5 : ApiTestFuzzer::Fuzz();
13874 5 : v8::Unlocker unlocker(CcTest::isolate());
13875 : const char* code = "throw 7;";
13876 : {
13877 5 : v8::Locker nested_locker(CcTest::isolate());
13878 10 : v8::HandleScope scope(args.GetIsolate());
13879 : v8::Local<Value> value = CompileRun(code);
13880 5 : CHECK(value.IsEmpty());
13881 10 : args.GetReturnValue().Set(v8_str("foo"));
13882 5 : }
13883 5 : }
13884 :
13885 :
13886 : // These are locking tests that don't need to be run again
13887 : // as part of the locking aggregation tests.
13888 23723 : TEST(NestedLockers) {
13889 5 : v8::Isolate* isolate = CcTest::isolate();
13890 : v8::Locker locker(isolate);
13891 5 : CHECK(v8::Locker::IsLocked(isolate));
13892 10 : LocalContext env;
13893 10 : v8::HandleScope scope(env->GetIsolate());
13894 : Local<v8::FunctionTemplate> fun_templ =
13895 5 : v8::FunctionTemplate::New(isolate, ThrowInJS);
13896 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13897 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13898 : Local<Script> script = v8_compile("(function () {"
13899 : " try {"
13900 : " throw_in_js();"
13901 : " return 42;"
13902 : " } catch (e) {"
13903 : " return e * 13;"
13904 : " }"
13905 : "})();");
13906 15 : CHECK_EQ(91, script->Run(env.local())
13907 : .ToLocalChecked()
13908 : ->Int32Value(env.local())
13909 5 : .FromJust());
13910 5 : }
13911 :
13912 :
13913 : // These are locking tests that don't need to be run again
13914 : // as part of the locking aggregation tests.
13915 23723 : TEST(NestedLockersNoTryCatch) {
13916 5 : v8::Locker locker(CcTest::isolate());
13917 10 : LocalContext env;
13918 10 : v8::HandleScope scope(env->GetIsolate());
13919 : Local<v8::FunctionTemplate> fun_templ =
13920 5 : v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13921 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13922 25 : CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13923 : Local<Script> script = v8_compile("(function () {"
13924 : " try {"
13925 : " throw_in_js();"
13926 : " return 42;"
13927 : " } catch (e) {"
13928 : " return e * 13;"
13929 : " }"
13930 : "})();");
13931 15 : CHECK_EQ(91, script->Run(env.local())
13932 : .ToLocalChecked()
13933 : ->Int32Value(env.local())
13934 5 : .FromJust());
13935 5 : }
13936 :
13937 :
13938 23724 : THREADED_TEST(RecursiveLocking) {
13939 6 : v8::Locker locker(CcTest::isolate());
13940 : {
13941 6 : v8::Locker locker2(CcTest::isolate());
13942 6 : CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13943 6 : }
13944 6 : }
13945 :
13946 :
13947 12 : static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13948 12 : ApiTestFuzzer::Fuzz();
13949 24 : v8::Unlocker unlocker(CcTest::isolate());
13950 12 : }
13951 :
13952 :
13953 23724 : THREADED_TEST(LockUnlockLock) {
13954 : {
13955 6 : v8::Locker locker(CcTest::isolate());
13956 12 : v8::HandleScope scope(CcTest::isolate());
13957 12 : LocalContext env;
13958 : Local<v8::FunctionTemplate> fun_templ =
13959 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13960 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13961 30 : CHECK(env->Global()
13962 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13963 : .FromJust());
13964 : Local<Script> script = v8_compile("(function () {"
13965 : " unlock_for_a_moment();"
13966 : " return 42;"
13967 : "})();");
13968 18 : CHECK_EQ(42, script->Run(env.local())
13969 : .ToLocalChecked()
13970 : ->Int32Value(env.local())
13971 6 : .FromJust());
13972 : }
13973 : {
13974 6 : v8::Locker locker(CcTest::isolate());
13975 12 : v8::HandleScope scope(CcTest::isolate());
13976 12 : LocalContext env;
13977 : Local<v8::FunctionTemplate> fun_templ =
13978 6 : v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13979 12 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13980 30 : CHECK(env->Global()
13981 : ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13982 : .FromJust());
13983 : Local<Script> script = v8_compile("(function () {"
13984 : " unlock_for_a_moment();"
13985 : " return 42;"
13986 : "})();");
13987 18 : CHECK_EQ(42, script->Run(env.local())
13988 : .ToLocalChecked()
13989 : ->Int32Value(env.local())
13990 6 : .FromJust());
13991 : }
13992 6 : }
13993 :
13994 :
13995 130 : static int GetGlobalObjectsCount() {
13996 : int count = 0;
13997 130 : i::HeapIterator it(CcTest::heap());
13998 817148 : for (i::HeapObject* object = it.next(); object != nullptr; object = it.next())
13999 817018 : if (object->IsJSGlobalObject()) {
14000 : i::JSGlobalObject* g = i::JSGlobalObject::cast(object);
14001 : // Skip dummy global object.
14002 30 : if (g->global_dictionary()->NumberOfElements() != 0) {
14003 30 : count++;
14004 : }
14005 : }
14006 130 : return count;
14007 : }
14008 :
14009 :
14010 100 : static void CheckSurvivingGlobalObjectsCount(int expected) {
14011 : // We need to collect all garbage twice to be sure that everything
14012 : // has been collected. This is because inline caches are cleared in
14013 : // the first garbage collection but some of the maps have already
14014 : // been marked at that point. Therefore some of the maps are not
14015 : // collected until the second garbage collection.
14016 100 : CcTest::CollectAllGarbage();
14017 100 : CcTest::CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
14018 100 : int count = GetGlobalObjectsCount();
14019 100 : CHECK_EQ(expected, count);
14020 100 : }
14021 :
14022 :
14023 23723 : TEST(DontLeakGlobalObjects) {
14024 : // Regression test for issues 1139850 and 1174891.
14025 :
14026 5 : i::FLAG_expose_gc = true;
14027 5 : v8::V8::Initialize();
14028 :
14029 30 : for (int i = 0; i < 5; i++) {
14030 25 : { v8::HandleScope scope(CcTest::isolate());
14031 25 : LocalContext context;
14032 : }
14033 25 : CcTest::isolate()->ContextDisposedNotification();
14034 25 : CheckSurvivingGlobalObjectsCount(0);
14035 :
14036 25 : { v8::HandleScope scope(CcTest::isolate());
14037 50 : LocalContext context;
14038 75 : v8_compile("Date")->Run(context.local()).ToLocalChecked();
14039 : }
14040 25 : CcTest::isolate()->ContextDisposedNotification();
14041 25 : CheckSurvivingGlobalObjectsCount(0);
14042 :
14043 25 : { v8::HandleScope scope(CcTest::isolate());
14044 50 : LocalContext context;
14045 75 : v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
14046 : }
14047 25 : CcTest::isolate()->ContextDisposedNotification();
14048 25 : CheckSurvivingGlobalObjectsCount(0);
14049 :
14050 25 : { v8::HandleScope scope(CcTest::isolate());
14051 25 : const char* extension_list[] = { "v8/gc" };
14052 : v8::ExtensionConfiguration extensions(1, extension_list);
14053 50 : LocalContext context(&extensions);
14054 75 : v8_compile("gc();")->Run(context.local()).ToLocalChecked();
14055 : }
14056 25 : CcTest::isolate()->ContextDisposedNotification();
14057 25 : CheckSurvivingGlobalObjectsCount(0);
14058 : }
14059 5 : }
14060 :
14061 :
14062 23723 : TEST(CopyablePersistent) {
14063 5 : LocalContext context;
14064 5 : v8::Isolate* isolate = context->GetIsolate();
14065 25 : i::GlobalHandles* globals =
14066 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14067 : int initial_handles = globals->global_handles_count();
14068 : typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14069 : CopyableObject;
14070 : {
14071 : CopyableObject handle1;
14072 : {
14073 5 : v8::HandleScope scope(isolate);
14074 10 : handle1.Reset(isolate, v8::Object::New(isolate));
14075 : }
14076 5 : CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14077 : CopyableObject handle2;
14078 : handle2 = handle1;
14079 5 : CHECK(handle1 == handle2);
14080 5 : CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14081 : CopyableObject handle3(handle2);
14082 5 : CHECK(handle1 == handle3);
14083 5 : CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14084 : }
14085 : // Verify autodispose
14086 5 : CHECK_EQ(initial_handles, globals->global_handles_count());
14087 5 : }
14088 :
14089 :
14090 5 : static void WeakApiCallback(
14091 10 : const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
14092 : data.GetParameter()->Reset();
14093 5 : delete data.GetParameter();
14094 5 : }
14095 :
14096 :
14097 23723 : TEST(WeakCallbackApi) {
14098 5 : LocalContext context;
14099 5 : v8::Isolate* isolate = context->GetIsolate();
14100 10 : i::GlobalHandles* globals =
14101 : reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14102 : int initial_handles = globals->global_handles_count();
14103 : {
14104 5 : v8::HandleScope scope(isolate);
14105 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
14106 25 : CHECK(
14107 : obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
14108 : .FromJust());
14109 : v8::Persistent<v8::Object>* handle =
14110 5 : new v8::Persistent<v8::Object>(isolate, obj);
14111 : handle->SetWeak<v8::Persistent<v8::Object>>(
14112 5 : handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
14113 : }
14114 : reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
14115 : i::Heap::kAbortIncrementalMarkingMask,
14116 5 : i::GarbageCollectionReason::kTesting);
14117 : // Verify disposed.
14118 5 : CHECK_EQ(initial_handles, globals->global_handles_count());
14119 5 : }
14120 :
14121 :
14122 23718 : v8::Persistent<v8::Object> some_object;
14123 23718 : v8::Persistent<v8::Object> bad_handle;
14124 :
14125 :
14126 6 : void NewPersistentHandleCallback2(
14127 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14128 6 : v8::HandleScope scope(data.GetIsolate());
14129 6 : bad_handle.Reset(data.GetIsolate(), some_object);
14130 6 : }
14131 :
14132 :
14133 6 : void NewPersistentHandleCallback1(
14134 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14135 : data.GetParameter()->Reset();
14136 : data.SetSecondPassCallback(NewPersistentHandleCallback2);
14137 6 : }
14138 :
14139 :
14140 23724 : THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14141 6 : LocalContext context;
14142 6 : v8::Isolate* isolate = context->GetIsolate();
14143 :
14144 : v8::Persistent<v8::Object> handle1, handle2;
14145 : {
14146 6 : v8::HandleScope scope(isolate);
14147 12 : some_object.Reset(isolate, v8::Object::New(isolate));
14148 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14149 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14150 : }
14151 : // Note: order is implementation dependent alas: currently
14152 : // global handle nodes are processed by PostGarbageCollectionProcessing
14153 : // in reverse allocation order, so if second allocated handle is deleted,
14154 : // weak callback of the first handle would be able to 'reallocate' it.
14155 : handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
14156 : v8::WeakCallbackType::kParameter);
14157 : handle2.Reset();
14158 6 : CcTest::CollectAllGarbage();
14159 6 : }
14160 :
14161 :
14162 23718 : v8::Persistent<v8::Object> to_be_disposed;
14163 :
14164 :
14165 6 : void DisposeAndForceGcCallback2(
14166 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14167 : to_be_disposed.Reset();
14168 6 : CcTest::CollectAllGarbage();
14169 6 : }
14170 :
14171 :
14172 6 : void DisposeAndForceGcCallback1(
14173 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14174 : data.GetParameter()->Reset();
14175 : data.SetSecondPassCallback(DisposeAndForceGcCallback2);
14176 6 : }
14177 :
14178 :
14179 23724 : THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14180 6 : LocalContext context;
14181 6 : v8::Isolate* isolate = context->GetIsolate();
14182 :
14183 : v8::Persistent<v8::Object> handle1, handle2;
14184 : {
14185 6 : v8::HandleScope scope(isolate);
14186 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14187 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14188 : }
14189 : handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
14190 : v8::WeakCallbackType::kParameter);
14191 : to_be_disposed.Reset(isolate, handle2);
14192 6 : CcTest::CollectAllGarbage();
14193 6 : }
14194 :
14195 6 : void DisposingCallback(
14196 6 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14197 : data.GetParameter()->Reset();
14198 6 : }
14199 :
14200 6 : void HandleCreatingCallback2(
14201 18 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14202 6 : v8::HandleScope scope(data.GetIsolate());
14203 12 : v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
14204 6 : }
14205 :
14206 :
14207 6 : void HandleCreatingCallback1(
14208 12 : const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14209 : data.GetParameter()->Reset();
14210 : data.SetSecondPassCallback(HandleCreatingCallback2);
14211 6 : }
14212 :
14213 :
14214 23724 : THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14215 6 : v8::Locker locker(CcTest::isolate());
14216 12 : LocalContext context;
14217 6 : v8::Isolate* isolate = context->GetIsolate();
14218 :
14219 : v8::Persistent<v8::Object> handle1, handle2, handle3;
14220 : {
14221 6 : v8::HandleScope scope(isolate);
14222 12 : handle3.Reset(isolate, v8::Object::New(isolate));
14223 12 : handle2.Reset(isolate, v8::Object::New(isolate));
14224 12 : handle1.Reset(isolate, v8::Object::New(isolate));
14225 : }
14226 : handle2.SetWeak(&handle2, DisposingCallback,
14227 : v8::WeakCallbackType::kParameter);
14228 : handle3.SetWeak(&handle3, HandleCreatingCallback1,
14229 : v8::WeakCallbackType::kParameter);
14230 6 : CcTest::CollectAllGarbage();
14231 12 : EmptyMessageQueues(isolate);
14232 6 : }
14233 :
14234 :
14235 23724 : THREADED_TEST(CheckForCrossContextObjectLiterals) {
14236 6 : v8::V8::Initialize();
14237 :
14238 : const int nof = 2;
14239 : const char* sources[nof] = {
14240 : "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14241 : "Object()"
14242 6 : };
14243 :
14244 18 : for (int i = 0; i < nof; i++) {
14245 12 : const char* source = sources[i];
14246 12 : { v8::HandleScope scope(CcTest::isolate());
14247 24 : LocalContext context;
14248 12 : CompileRun(source);
14249 : }
14250 12 : { v8::HandleScope scope(CcTest::isolate());
14251 24 : LocalContext context;
14252 12 : CompileRun(source);
14253 : }
14254 : }
14255 6 : }
14256 :
14257 :
14258 6 : static v8::Local<Value> NestedScope(v8::Local<Context> env) {
14259 6 : v8::EscapableHandleScope inner(env->GetIsolate());
14260 6 : env->Enter();
14261 6 : v8::Local<Value> three = v8_num(3);
14262 : v8::Local<Value> value = inner.Escape(three);
14263 6 : env->Exit();
14264 12 : return value;
14265 : }
14266 :
14267 :
14268 23724 : THREADED_TEST(NestedHandleScopeAndContexts) {
14269 6 : v8::Isolate* isolate = CcTest::isolate();
14270 6 : v8::HandleScope outer(isolate);
14271 6 : v8::Local<Context> env = Context::New(isolate);
14272 6 : env->Enter();
14273 6 : v8::Local<Value> value = NestedScope(env);
14274 6 : v8::Local<String> str(value->ToString(env).ToLocalChecked());
14275 6 : CHECK(!str.IsEmpty());
14276 6 : env->Exit();
14277 6 : }
14278 :
14279 :
14280 : struct SymbolInfo {
14281 : size_t id;
14282 : size_t size;
14283 : std::string name;
14284 : };
14285 :
14286 :
14287 : class SetFunctionEntryHookTest {
14288 : public:
14289 0 : SetFunctionEntryHookTest() {
14290 0 : CHECK_NULL(instance_);
14291 0 : instance_ = this;
14292 0 : }
14293 0 : ~SetFunctionEntryHookTest() {
14294 0 : CHECK(instance_ == this);
14295 0 : instance_ = nullptr;
14296 0 : }
14297 0 : void Reset() {
14298 : symbols_.clear();
14299 : symbol_locations_.clear();
14300 : invocations_.clear();
14301 0 : }
14302 : void RunTest();
14303 : void OnJitEvent(const v8::JitCodeEvent* event);
14304 0 : static void JitEvent(const v8::JitCodeEvent* event) {
14305 0 : CHECK_NOT_NULL(instance_);
14306 0 : instance_->OnJitEvent(event);
14307 0 : }
14308 :
14309 : void OnEntryHook(uintptr_t function,
14310 : uintptr_t return_addr_location);
14311 0 : static void EntryHook(uintptr_t function,
14312 : uintptr_t return_addr_location) {
14313 0 : CHECK_NOT_NULL(instance_);
14314 0 : instance_->OnEntryHook(function, return_addr_location);
14315 0 : }
14316 :
14317 0 : static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14318 0 : CHECK_NOT_NULL(instance_);
14319 0 : args.GetReturnValue().Set(v8_num(42));
14320 0 : }
14321 : void RunLoopInNewEnv(v8::Isolate* isolate);
14322 :
14323 : // Records addr as location of symbol.
14324 : void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14325 :
14326 : // Finds the symbol containing addr
14327 : SymbolInfo* FindSymbolForAddr(i::Address addr);
14328 : // Returns the number of invocations where the caller name contains
14329 : // \p caller_name and the function name contains \p function_name.
14330 : int CountInvocations(const char* caller_name,
14331 : const char* function_name);
14332 :
14333 : i::Handle<i::JSFunction> foo_func_;
14334 : i::Handle<i::JSFunction> bar_func_;
14335 :
14336 : typedef std::map<size_t, SymbolInfo> SymbolMap;
14337 : typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14338 : typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14339 : SymbolMap symbols_;
14340 : SymbolLocationMap symbol_locations_;
14341 : InvocationMap invocations_;
14342 :
14343 : static SetFunctionEntryHookTest* instance_;
14344 : };
14345 : SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = nullptr;
14346 :
14347 : // Returns true if addr is in the range [start, start+len).
14348 : static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14349 0 : if (start <= addr && start + len > addr)
14350 : return true;
14351 :
14352 : return false;
14353 : }
14354 :
14355 0 : void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14356 : SymbolInfo* symbol) {
14357 : // Insert the symbol at the new location.
14358 : SymbolLocationMap::iterator it =
14359 0 : symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14360 : // Now erase symbols to the left and right that overlap this one.
14361 0 : while (it != symbol_locations_.begin()) {
14362 : SymbolLocationMap::iterator left = it;
14363 : --left;
14364 0 : if (!Overlaps(left->first, left->second->size, addr))
14365 : break;
14366 : symbol_locations_.erase(left);
14367 : }
14368 :
14369 : // Now erase symbols to the left and right that overlap this one.
14370 : while (true) {
14371 : SymbolLocationMap::iterator right = it;
14372 : ++right;
14373 0 : if (right == symbol_locations_.end())
14374 : break;
14375 0 : if (!Overlaps(addr, symbol->size, right->first))
14376 : break;
14377 : symbol_locations_.erase(right);
14378 0 : }
14379 0 : }
14380 :
14381 :
14382 0 : void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14383 0 : switch (event->type) {
14384 : case v8::JitCodeEvent::CODE_ADDED: {
14385 0 : CHECK_NOT_NULL(event->code_start);
14386 0 : CHECK_NE(0, static_cast<int>(event->code_len));
14387 0 : CHECK_NOT_NULL(event->name.str);
14388 0 : size_t symbol_id = symbols_.size();
14389 :
14390 : // Record the new symbol.
14391 0 : SymbolInfo& info = symbols_[symbol_id];
14392 0 : info.id = symbol_id;
14393 0 : info.size = event->code_len;
14394 0 : info.name.assign(event->name.str, event->name.str + event->name.len);
14395 :
14396 : // And record it's location.
14397 0 : InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14398 : }
14399 0 : break;
14400 :
14401 : case v8::JitCodeEvent::CODE_MOVED: {
14402 : // We would like to never see code move that we haven't seen before,
14403 : // but the code creation event does not happen until the line endings
14404 : // have been calculated (this is so that we can report the line in the
14405 : // script at which the function source is found, see
14406 : // Compiler::RecordFunctionCompilation) and the line endings
14407 : // calculations can cause a GC, which can move the newly created code
14408 : // before its existence can be logged.
14409 : SymbolLocationMap::iterator it(
14410 : symbol_locations_.find(
14411 0 : reinterpret_cast<i::Address>(event->code_start)));
14412 0 : if (it != symbol_locations_.end()) {
14413 : // Found a symbol at this location, move it.
14414 0 : SymbolInfo* info = it->second;
14415 : symbol_locations_.erase(it);
14416 : InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14417 0 : info);
14418 : }
14419 : }
14420 : default:
14421 : break;
14422 : }
14423 0 : }
14424 :
14425 0 : void SetFunctionEntryHookTest::OnEntryHook(
14426 : uintptr_t function, uintptr_t return_addr_location) {
14427 : // Get the function's code object.
14428 : i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14429 0 : reinterpret_cast<i::Address>(function));
14430 0 : CHECK_NOT_NULL(function_code);
14431 :
14432 : // Then try and look up the caller's code object.
14433 0 : i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14434 :
14435 : // Count the invocation.
14436 0 : SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14437 : SymbolInfo* function_symbol =
14438 0 : FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14439 0 : ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14440 :
14441 0 : if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14442 : // Check that we have a symbol for the "bar" function at the right location.
14443 : SymbolLocationMap::iterator it(
14444 0 : symbol_locations_.find(function_code->instruction_start()));
14445 0 : CHECK(it != symbol_locations_.end());
14446 : }
14447 :
14448 0 : if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14449 : // Check that we have a symbol for "foo" at the right location.
14450 : SymbolLocationMap::iterator it(
14451 0 : symbol_locations_.find(function_code->instruction_start()));
14452 0 : CHECK(it != symbol_locations_.end());
14453 : }
14454 0 : }
14455 :
14456 :
14457 0 : SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14458 : SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14459 : // Do we have a direct hit on a symbol?
14460 0 : if (it != symbol_locations_.end()) {
14461 0 : if (it->first == addr)
14462 0 : return it->second;
14463 : }
14464 :
14465 : // If not a direct hit, it'll have to be the previous symbol.
14466 0 : if (it == symbol_locations_.begin()) return nullptr;
14467 :
14468 : --it;
14469 0 : size_t offs = addr - it->first;
14470 0 : if (offs < it->second->size)
14471 0 : return it->second;
14472 :
14473 : return nullptr;
14474 : }
14475 :
14476 :
14477 0 : int SetFunctionEntryHookTest::CountInvocations(
14478 : const char* caller_name, const char* function_name) {
14479 : InvocationMap::iterator it(invocations_.begin());
14480 : int invocations = 0;
14481 0 : for (; it != invocations_.end(); ++it) {
14482 0 : SymbolInfo* caller = it->first.first;
14483 0 : SymbolInfo* function = it->first.second;
14484 :
14485 : // Filter out non-matching functions.
14486 0 : if (function_name != nullptr) {
14487 0 : if (function->name.find(function_name) == std::string::npos)
14488 : continue;
14489 : }
14490 :
14491 : // Filter out non-matching callers.
14492 0 : if (caller_name != nullptr) {
14493 0 : if (caller == nullptr) continue;
14494 0 : if (caller->name.find(caller_name) == std::string::npos)
14495 : continue;
14496 : }
14497 :
14498 : // It matches add the invocation count to the tally.
14499 0 : invocations += it->second;
14500 : }
14501 :
14502 0 : return invocations;
14503 : }
14504 :
14505 0 : void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14506 0 : v8::HandleScope outer(isolate);
14507 0 : v8::Local<Context> env = Context::New(isolate);
14508 0 : env->Enter();
14509 :
14510 0 : Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14511 0 : t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14512 0 : CHECK(env->Global()
14513 : ->Set(env, v8_str("obj"), t->NewInstance(env).ToLocalChecked())
14514 : .FromJust());
14515 :
14516 : const char* script =
14517 : "function bar() {\n"
14518 : " var sum = 0;\n"
14519 : " for (i = 0; i < 100; ++i)\n"
14520 : " sum = foo(i);\n"
14521 : " return sum;\n"
14522 : "}\n"
14523 : "function foo(i) { return i * i; }\n"
14524 : "// Invoke on the runtime function.\n"
14525 : "obj.asdf()";
14526 : CompileRun(script);
14527 : bar_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(
14528 0 : *env->Global()->Get(env, v8_str("bar")).ToLocalChecked()));
14529 0 : CHECK(!bar_func_.is_null());
14530 :
14531 : foo_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(
14532 0 : *env->Global()->Get(env, v8_str("foo")).ToLocalChecked()));
14533 0 : CHECK(!foo_func_.is_null());
14534 :
14535 : v8::Local<v8::Value> value = CompileRun("bar();");
14536 0 : CHECK(value->IsNumber());
14537 0 : CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14538 :
14539 : // Test the optimized codegen path.
14540 : value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14541 : "bar();");
14542 0 : CHECK(value->IsNumber());
14543 0 : CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14544 :
14545 0 : env->Exit();
14546 0 : }
14547 :
14548 :
14549 0 : void SetFunctionEntryHookTest::RunTest() {
14550 : // Work in a new isolate throughout.
14551 : v8::Isolate::CreateParams create_params;
14552 0 : create_params.entry_hook = EntryHook;
14553 0 : create_params.code_event_handler = JitEvent;
14554 0 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14555 0 : v8::Isolate* isolate = v8::Isolate::New(create_params);
14556 :
14557 : {
14558 : v8::Isolate::Scope scope(isolate);
14559 :
14560 0 : RunLoopInNewEnv(isolate);
14561 :
14562 : // Check the expected invocation counts.
14563 0 : if (i::FLAG_always_opt) {
14564 0 : CHECK_EQ(2, CountInvocations(nullptr, "bar"));
14565 0 : CHECK_EQ(200, CountInvocations("bar", "foo"));
14566 0 : CHECK_EQ(200, CountInvocations(nullptr, "foo"));
14567 0 : } else if (i::FLAG_opt) {
14568 : // For ignition we don't see the actual functions being called, instead
14569 : // we see the InterpreterEntryTrampoline at least 102 times
14570 : // (100 unoptimized calls to foo, and 2 calls to bar).
14571 0 : CHECK_LE(102, CountInvocations(nullptr, "InterpreterEntryTrampoline"));
14572 : // We should also see the calls to the optimized function foo.
14573 0 : CHECK_EQ(100, CountInvocations(nullptr, "foo"));
14574 : } else {
14575 : // For ignition without an optimizing compiler, we should only see the
14576 : // InterpreterEntryTrampoline.
14577 : // (200 unoptimized calls to foo, and 2 calls to bar).
14578 0 : CHECK_LE(202, CountInvocations(nullptr, "InterpreterEntryTrampoline"));
14579 : }
14580 :
14581 : // Verify that we have an entry hook on some specific stubs.
14582 0 : CHECK_NE(0, CountInvocations(nullptr, "CEntryStub"));
14583 0 : CHECK_NE(0, CountInvocations(nullptr, "JSEntryStub"));
14584 0 : CHECK_NE(0, CountInvocations(nullptr, "JSEntryTrampoline"));
14585 : }
14586 0 : isolate->Dispose();
14587 :
14588 0 : Reset();
14589 :
14590 : // Make sure a second isolate is unaffected by the previous entry hook.
14591 0 : create_params = v8::Isolate::CreateParams();
14592 0 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14593 0 : isolate = v8::Isolate::New(create_params);
14594 : {
14595 : v8::Isolate::Scope scope(isolate);
14596 :
14597 : // Reset the entry count to zero and set the entry hook.
14598 0 : RunLoopInNewEnv(isolate);
14599 :
14600 : // We should record no invocations in this isolate.
14601 0 : CHECK_EQ(0, static_cast<int>(invocations_.size()));
14602 : }
14603 :
14604 0 : isolate->Dispose();
14605 0 : }
14606 :
14607 :
14608 23718 : TEST(SetFunctionEntryHook) {
14609 : // FunctionEntryHook does not work well with experimental natives.
14610 : // Experimental natives are compiled during snapshot deserialization.
14611 : // This test breaks because InstallGetter (function from snapshot that
14612 : // only gets called from experimental natives) is compiled with entry hooks.
14613 0 : i::FLAG_allow_natives_syntax = true;
14614 0 : i::FLAG_turbo_inlining = false;
14615 :
14616 0 : SetFunctionEntryHookTest test;
14617 0 : test.RunTest();
14618 0 : }
14619 :
14620 : static v8::base::HashMap* code_map = nullptr;
14621 : static v8::base::HashMap* jitcode_line_info = nullptr;
14622 : static int saw_bar = 0;
14623 : static int move_events = 0;
14624 :
14625 :
14626 5355 : static bool FunctionNameIs(const char* expected,
14627 : const v8::JitCodeEvent* event) {
14628 : // Log lines for functions are of the general form:
14629 : // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
14630 : // where the type is one of "*", "~" or "".
14631 : static const char* kPreamble;
14632 5355 : if (!i::FLAG_lazy) {
14633 0 : kPreamble = "Function:";
14634 : } else {
14635 5355 : kPreamble = "LazyCompile:";
14636 : }
14637 5355 : static size_t kPreambleLen = strlen(kPreamble);
14638 :
14639 10655 : if (event->name.len < kPreambleLen ||
14640 5300 : strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14641 : return false;
14642 : }
14643 :
14644 2753 : const char* tail = event->name.str + kPreambleLen;
14645 2753 : size_t tail_len = event->name.len - kPreambleLen;
14646 2753 : size_t expected_len = strlen(expected);
14647 2753 : if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14648 148 : --tail_len;
14649 148 : ++tail;
14650 : }
14651 :
14652 : // Check for tails like 'bar :1'.
14653 2885 : if (tail_len > expected_len + 2 &&
14654 264 : tail[expected_len] == ' ' &&
14655 264 : tail[expected_len + 1] == ':' &&
14656 264 : tail[expected_len + 2] &&
14657 132 : !strncmp(tail, expected, expected_len)) {
14658 : return true;
14659 : }
14660 :
14661 2687 : if (tail_len != expected_len)
14662 : return false;
14663 :
14664 21 : return strncmp(tail, expected, expected_len) == 0;
14665 : }
14666 :
14667 :
14668 7617 : static void event_handler(const v8::JitCodeEvent* event) {
14669 7617 : CHECK_NOT_NULL(event);
14670 7617 : CHECK_NOT_NULL(code_map);
14671 7617 : CHECK_NOT_NULL(jitcode_line_info);
14672 :
14673 : class DummyJitCodeLineInfo {
14674 : };
14675 :
14676 7617 : switch (event->type) {
14677 : case v8::JitCodeEvent::CODE_ADDED: {
14678 5355 : CHECK_NOT_NULL(event->code_start);
14679 5355 : CHECK_NE(0, static_cast<int>(event->code_len));
14680 5355 : CHECK_NOT_NULL(event->name.str);
14681 : v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
14682 5355 : event->code_start, i::ComputePointerHash(event->code_start));
14683 5355 : entry->value = reinterpret_cast<void*>(event->code_len);
14684 :
14685 5355 : if (FunctionNameIs("bar", event)) {
14686 66 : ++saw_bar;
14687 : }
14688 : }
14689 : break;
14690 :
14691 : case v8::JitCodeEvent::CODE_MOVED: {
14692 192 : uint32_t hash = i::ComputePointerHash(event->code_start);
14693 : // We would like to never see code move that we haven't seen before,
14694 : // but the code creation event does not happen until the line endings
14695 : // have been calculated (this is so that we can report the line in the
14696 : // script at which the function source is found, see
14697 : // Compiler::RecordFunctionCompilation) and the line endings
14698 : // calculations can cause a GC, which can move the newly created code
14699 : // before its existence can be logged.
14700 : v8::base::HashMap::Entry* entry =
14701 192 : code_map->Lookup(event->code_start, hash);
14702 192 : if (entry != nullptr) {
14703 192 : ++move_events;
14704 :
14705 192 : CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14706 192 : code_map->Remove(event->code_start, hash);
14707 :
14708 : entry = code_map->LookupOrInsert(
14709 : event->new_code_start,
14710 384 : i::ComputePointerHash(event->new_code_start));
14711 192 : entry->value = reinterpret_cast<void*>(event->code_len);
14712 : }
14713 : }
14714 : break;
14715 :
14716 : case v8::JitCodeEvent::CODE_REMOVED:
14717 : // Object/code removal events are currently not dispatched from the GC.
14718 0 : CHECK(false);
14719 : break;
14720 :
14721 : // For CODE_START_LINE_INFO_RECORDING event, we will create one
14722 : // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14723 : // record it in jitcode_line_info.
14724 : case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14725 180 : DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14726 : v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14727 180 : temp_event->user_data = line_info;
14728 : v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14729 360 : line_info, i::ComputePointerHash(line_info));
14730 180 : entry->value = reinterpret_cast<void*>(line_info);
14731 : }
14732 180 : break;
14733 : // For these two events, we will check whether the event->user_data
14734 : // data structure is created before during CODE_START_LINE_INFO_RECORDING
14735 : // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14736 : case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14737 180 : CHECK_NOT_NULL(event->user_data);
14738 : uint32_t hash = i::ComputePointerHash(event->user_data);
14739 : v8::base::HashMap::Entry* entry =
14740 180 : jitcode_line_info->Lookup(event->user_data, hash);
14741 180 : CHECK_NOT_NULL(entry);
14742 180 : delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14743 : }
14744 180 : break;
14745 :
14746 : case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14747 1710 : CHECK_NOT_NULL(event->user_data);
14748 : uint32_t hash = i::ComputePointerHash(event->user_data);
14749 : v8::base::HashMap::Entry* entry =
14750 1710 : jitcode_line_info->Lookup(event->user_data, hash);
14751 1710 : CHECK_NOT_NULL(entry);
14752 : }
14753 : break;
14754 :
14755 : default:
14756 : // Impossible event.
14757 0 : CHECK(false);
14758 : break;
14759 : }
14760 7617 : }
14761 :
14762 :
14763 23723 : UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14764 5 : i::FLAG_stress_compaction = true;
14765 5 : i::FLAG_incremental_marking = false;
14766 5 : if (i::FLAG_never_compact) return;
14767 : const char* script =
14768 : "function bar() {"
14769 : " var sum = 0;"
14770 : " for (i = 0; i < 10; ++i)"
14771 : " sum = foo(i);"
14772 : " return sum;"
14773 : "}"
14774 : "function foo(i) { return i; };"
14775 : "bar();";
14776 :
14777 : // Run this test in a new isolate to make sure we don't
14778 : // have remnants of state from other code.
14779 : v8::Isolate::CreateParams create_params;
14780 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14781 55 : v8::Isolate* isolate = v8::Isolate::New(create_params);
14782 5 : isolate->Enter();
14783 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14784 5 : i::Heap* heap = i_isolate->heap();
14785 :
14786 : // Start with a clean slate.
14787 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14788 :
14789 : {
14790 5 : v8::HandleScope scope(isolate);
14791 : v8::base::HashMap code;
14792 5 : code_map = &code;
14793 :
14794 : v8::base::HashMap lineinfo;
14795 5 : jitcode_line_info = &lineinfo;
14796 :
14797 5 : saw_bar = 0;
14798 5 : move_events = 0;
14799 :
14800 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14801 :
14802 : // Generate new code objects sparsely distributed across several
14803 : // different fragmented code-space pages.
14804 : const int kIterations = 10;
14805 55 : for (int i = 0; i < kIterations; ++i) {
14806 : LocalContext env(isolate);
14807 : i::AlwaysAllocateScope always_allocate(i_isolate);
14808 : CompileRun(script);
14809 :
14810 : // Keep a strong reference to the code object in the handle scope.
14811 : i::Handle<i::JSFunction> bar(i::Handle<i::JSFunction>::cast(
14812 : v8::Utils::OpenHandle(*env->Global()
14813 200 : ->Get(env.local(), v8_str("bar"))
14814 50 : .ToLocalChecked())));
14815 : i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
14816 : v8::Utils::OpenHandle(*env->Global()
14817 200 : ->Get(env.local(), v8_str("foo"))
14818 50 : .ToLocalChecked())));
14819 :
14820 : i::PagedSpace* foo_owning_space = reinterpret_cast<i::PagedSpace*>(
14821 50 : i::Page::FromAddress(foo->abstract_code()->address())->owner());
14822 : i::PagedSpace* bar_owning_space = reinterpret_cast<i::PagedSpace*>(
14823 50 : i::Page::FromAddress(bar->abstract_code()->address())->owner());
14824 50 : CHECK_EQ(foo_owning_space, bar_owning_space);
14825 50 : i::heap::SimulateFullSpace(foo_owning_space);
14826 :
14827 : // Clear the compilation cache to get more wastage.
14828 50 : reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14829 50 : }
14830 :
14831 : // Force code movement.
14832 5 : heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14833 :
14834 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14835 :
14836 5 : CHECK_LE(kIterations, saw_bar);
14837 5 : CHECK_LT(0, move_events);
14838 :
14839 5 : code_map = nullptr;
14840 10 : jitcode_line_info = nullptr;
14841 : }
14842 :
14843 5 : isolate->Exit();
14844 5 : isolate->Dispose();
14845 :
14846 : // Do this in a new isolate.
14847 5 : isolate = v8::Isolate::New(create_params);
14848 5 : isolate->Enter();
14849 :
14850 : // Verify that we get callbacks for existing code objects when we
14851 : // request enumeration of existing code.
14852 : {
14853 5 : v8::HandleScope scope(isolate);
14854 5 : LocalContext env(isolate);
14855 : CompileRun(script);
14856 :
14857 : // Now get code through initial iteration.
14858 : v8::base::HashMap code;
14859 5 : code_map = &code;
14860 :
14861 : v8::base::HashMap lineinfo;
14862 5 : jitcode_line_info = &lineinfo;
14863 :
14864 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14865 5 : event_handler);
14866 5 : isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14867 :
14868 5 : jitcode_line_info = nullptr;
14869 : // We expect that we got some events. Note that if we could get code removal
14870 : // notifications, we could compare two collections, one created by listening
14871 : // from the time of creation of an isolate, and the other by subscribing
14872 : // with EnumExisting.
14873 5 : CHECK_LT(0u, code.occupancy());
14874 :
14875 10 : code_map = nullptr;
14876 : }
14877 :
14878 5 : isolate->Exit();
14879 5 : isolate->Dispose();
14880 : }
14881 :
14882 23723 : TEST(ExternalAllocatedMemory) {
14883 5 : v8::Isolate* isolate = CcTest::isolate();
14884 5 : v8::HandleScope outer(isolate);
14885 5 : v8::Local<Context> env(Context::New(isolate));
14886 5 : CHECK(!env.IsEmpty());
14887 : const int64_t kSize = 1024*1024;
14888 : int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14889 5 : CHECK_EQ(baseline + kSize,
14890 : isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14891 5 : CHECK_EQ(baseline,
14892 : isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14893 : const int64_t kTriggerGCSize =
14894 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14895 5 : CHECK_EQ(baseline + kTriggerGCSize,
14896 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14897 10 : CHECK_EQ(baseline,
14898 5 : isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14899 5 : }
14900 :
14901 :
14902 23723 : TEST(Regress51719) {
14903 5 : i::FLAG_incremental_marking = false;
14904 5 : CcTest::InitializeVM();
14905 :
14906 : const int64_t kTriggerGCSize =
14907 5 : CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14908 5 : v8::Isolate* isolate = CcTest::isolate();
14909 : isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14910 5 : }
14911 :
14912 : // Regression test for issue 54, object templates with embedder fields
14913 : // but no accessors or interceptors did not get their embedder field
14914 : // count set on instances.
14915 23724 : THREADED_TEST(Regress54) {
14916 6 : LocalContext context;
14917 6 : v8::Isolate* isolate = context->GetIsolate();
14918 12 : v8::HandleScope outer(isolate);
14919 12 : static v8::Persistent<v8::ObjectTemplate> templ;
14920 6 : if (templ.IsEmpty()) {
14921 6 : v8::EscapableHandleScope inner(isolate);
14922 6 : v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14923 6 : local->SetInternalFieldCount(1);
14924 : templ.Reset(isolate, inner.Escape(local));
14925 : }
14926 : v8::Local<v8::Object> result =
14927 : v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14928 6 : ->NewInstance(context.local())
14929 6 : .ToLocalChecked();
14930 12 : CHECK_EQ(1, result->InternalFieldCount());
14931 6 : }
14932 :
14933 :
14934 : // If part of the threaded tests, this test makes ThreadingTest fail
14935 : // on mac.
14936 23723 : TEST(CatchStackOverflow) {
14937 5 : LocalContext context;
14938 10 : v8::HandleScope scope(context->GetIsolate());
14939 10 : v8::TryCatch try_catch(context->GetIsolate());
14940 : v8::Local<v8::Value> result = CompileRun(
14941 : "function f() {"
14942 : " return f();"
14943 : "}"
14944 : ""
14945 : "f();");
14946 10 : CHECK(result.IsEmpty());
14947 5 : }
14948 :
14949 :
14950 18 : static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14951 : const char* resource_name,
14952 : int line_offset) {
14953 18 : v8::HandleScope scope(CcTest::isolate());
14954 36 : v8::TryCatch try_catch(CcTest::isolate());
14955 18 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14956 36 : CHECK(script->Run(context).IsEmpty());
14957 18 : CHECK(try_catch.HasCaught());
14958 18 : v8::Local<v8::Message> message = try_catch.Message();
14959 18 : CHECK(!message.IsEmpty());
14960 36 : CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14961 18 : CHECK_EQ(91, message->GetStartPosition());
14962 18 : CHECK_EQ(92, message->GetEndPosition());
14963 36 : CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14964 36 : CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14965 : v8::String::Utf8Value line(CcTest::isolate(),
14966 54 : message->GetSourceLine(context).ToLocalChecked());
14967 18 : CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14968 : v8::String::Utf8Value name(CcTest::isolate(),
14969 36 : message->GetScriptOrigin().ResourceName());
14970 36 : CHECK_EQ(0, strcmp(resource_name, *name));
14971 18 : }
14972 :
14973 :
14974 23724 : THREADED_TEST(TryCatchSourceInfo) {
14975 6 : LocalContext context;
14976 12 : v8::HandleScope scope(context->GetIsolate());
14977 : v8::Local<v8::String> source = v8_str(
14978 : "function Foo() {\n"
14979 : " return Bar();\n"
14980 : "}\n"
14981 : "\n"
14982 : "function Bar() {\n"
14983 : " return Baz();\n"
14984 : "}\n"
14985 : "\n"
14986 : "function Baz() {\n"
14987 : " throw 'nirk';\n"
14988 : "}\n"
14989 : "\n"
14990 6 : "Foo();\n");
14991 :
14992 : const char* resource_name;
14993 : v8::Local<v8::Script> script;
14994 : resource_name = "test.js";
14995 6 : script = CompileWithOrigin(source, resource_name);
14996 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
14997 :
14998 : resource_name = "test1.js";
14999 6 : v8::ScriptOrigin origin1(v8_str(resource_name));
15000 : script =
15001 12 : v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
15002 6 : CheckTryCatchSourceInfo(script, resource_name, 0);
15003 :
15004 : resource_name = "test2.js";
15005 : v8::ScriptOrigin origin2(v8_str(resource_name),
15006 6 : v8::Integer::New(context->GetIsolate(), 7));
15007 : script =
15008 12 : v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
15009 12 : CheckTryCatchSourceInfo(script, resource_name, 7);
15010 6 : }
15011 :
15012 :
15013 23724 : THREADED_TEST(TryCatchSourceInfoForEOSError) {
15014 6 : LocalContext context;
15015 12 : v8::HandleScope scope(context->GetIsolate());
15016 12 : v8::TryCatch try_catch(context->GetIsolate());
15017 12 : CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
15018 6 : CHECK(try_catch.HasCaught());
15019 6 : v8::Local<v8::Message> message = try_catch.Message();
15020 12 : CHECK_EQ(1, message->GetLineNumber(context.local()).FromJust());
15021 18 : CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
15022 6 : }
15023 :
15024 :
15025 23724 : THREADED_TEST(CompilationCache) {
15026 6 : LocalContext context;
15027 12 : v8::HandleScope scope(context->GetIsolate());
15028 6 : v8::Local<v8::String> source0 = v8_str("1234");
15029 6 : v8::Local<v8::String> source1 = v8_str("1234");
15030 : v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15031 : v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
15032 6 : v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
15033 6 : .ToLocalChecked(); // different origin
15034 18 : CHECK_EQ(1234, script0->Run(context.local())
15035 : .ToLocalChecked()
15036 : ->Int32Value(context.local())
15037 : .FromJust());
15038 18 : CHECK_EQ(1234, script1->Run(context.local())
15039 : .ToLocalChecked()
15040 : ->Int32Value(context.local())
15041 : .FromJust());
15042 18 : CHECK_EQ(1234, script2->Run(context.local())
15043 : .ToLocalChecked()
15044 : ->Int32Value(context.local())
15045 6 : .FromJust());
15046 6 : }
15047 :
15048 :
15049 0 : static void FunctionNameCallback(
15050 0 : const v8::FunctionCallbackInfo<v8::Value>& args) {
15051 0 : ApiTestFuzzer::Fuzz();
15052 0 : args.GetReturnValue().Set(v8_num(42));
15053 0 : }
15054 :
15055 :
15056 23724 : THREADED_TEST(CallbackFunctionName) {
15057 6 : LocalContext context;
15058 6 : v8::Isolate* isolate = context->GetIsolate();
15059 12 : v8::HandleScope scope(isolate);
15060 6 : Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15061 : t->Set(v8_str("asdf"),
15062 18 : v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15063 36 : CHECK(context->Global()
15064 : ->Set(context.local(), v8_str("obj"),
15065 : t->NewInstance(context.local()).ToLocalChecked())
15066 : .FromJust());
15067 : v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
15068 6 : CHECK(value->IsString());
15069 12 : v8::String::Utf8Value name(isolate, value);
15070 12 : CHECK_EQ(0, strcmp("asdf", *name));
15071 6 : }
15072 :
15073 :
15074 23724 : THREADED_TEST(DateAccess) {
15075 6 : LocalContext context;
15076 12 : v8::HandleScope scope(context->GetIsolate());
15077 : v8::Local<v8::Value> date =
15078 6 : v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
15079 6 : CHECK(date->IsDate());
15080 12 : CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15081 6 : }
15082 :
15083 24 : void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
15084 : unsigned index, const char* name) {
15085 24 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15086 : v8::Local<v8::Value> value =
15087 48 : properties->Get(context, v8::Integer::New(isolate, index))
15088 24 : .ToLocalChecked();
15089 24 : CHECK(value->IsSymbol());
15090 : v8::String::Utf8Value symbol_name(isolate,
15091 24 : Local<Symbol>::Cast(value)->Name());
15092 24 : CHECK_EQ(0, strcmp(name, *symbol_name));
15093 24 : }
15094 :
15095 84 : void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
15096 : unsigned length, const char* names[]) {
15097 84 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15098 84 : CHECK_EQ(length, properties->Length());
15099 342 : for (unsigned i = 0; i < length; i++) {
15100 : v8::Local<v8::Value> value =
15101 1026 : properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
15102 342 : if (names[i] == nullptr) {
15103 : DCHECK(value->IsSymbol());
15104 : } else {
15105 318 : v8::String::Utf8Value elm(isolate, value);
15106 318 : CHECK_EQ(0, strcmp(names[i], *elm));
15107 : }
15108 : }
15109 84 : }
15110 :
15111 30 : void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15112 : unsigned length, const char* names[]) {
15113 30 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15114 : v8::Local<v8::Object> obj = val.As<v8::Object>();
15115 60 : v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
15116 30 : CheckStringArray(isolate, props, length, names);
15117 30 : }
15118 :
15119 :
15120 24 : void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15121 : unsigned elmc, const char* elmv[]) {
15122 24 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
15123 : v8::Local<v8::Object> obj = val.As<v8::Object>();
15124 : v8::Local<v8::Array> props =
15125 24 : obj->GetOwnPropertyNames(context).ToLocalChecked();
15126 24 : CHECK_EQ(elmc, props->Length());
15127 42 : for (unsigned i = 0; i < elmc; i++) {
15128 : v8::String::Utf8Value elm(
15129 : isolate,
15130 126 : props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
15131 42 : CHECK_EQ(0, strcmp(elmv[i], *elm));
15132 42 : }
15133 24 : }
15134 :
15135 :
15136 23724 : THREADED_TEST(PropertyEnumeration) {
15137 6 : LocalContext context;
15138 6 : v8::Isolate* isolate = context->GetIsolate();
15139 12 : v8::HandleScope scope(isolate);
15140 : v8::Local<v8::Value> obj = CompileRun(
15141 : "var result = [];"
15142 : "result[0] = {};"
15143 : "result[1] = {a: 1, b: 2};"
15144 : "result[2] = [1, 2, 3];"
15145 : "var proto = {x: 1, y: 2, z: 3};"
15146 : "var x = { __proto__: proto, w: 0, z: 1 };"
15147 : "result[3] = x;"
15148 : "result;");
15149 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
15150 6 : CHECK_EQ(4u, elms->Length());
15151 : int elmc0 = 0;
15152 : const char** elmv0 = nullptr;
15153 : CheckProperties(
15154 : isolate,
15155 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15156 12 : elmc0, elmv0);
15157 : CheckOwnProperties(
15158 : isolate,
15159 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15160 12 : elmc0, elmv0);
15161 : int elmc1 = 2;
15162 6 : const char* elmv1[] = {"a", "b"};
15163 : CheckProperties(
15164 : isolate,
15165 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15166 12 : elmc1, elmv1);
15167 : CheckOwnProperties(
15168 : isolate,
15169 18 : elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15170 12 : elmc1, elmv1);
15171 : int elmc2 = 3;
15172 6 : const char* elmv2[] = {"0", "1", "2"};
15173 : CheckProperties(
15174 : isolate,
15175 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15176 12 : elmc2, elmv2);
15177 : CheckOwnProperties(
15178 : isolate,
15179 18 : elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15180 12 : elmc2, elmv2);
15181 : int elmc3 = 4;
15182 6 : const char* elmv3[] = {"w", "z", "x", "y"};
15183 : CheckProperties(
15184 : isolate,
15185 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15186 12 : elmc3, elmv3);
15187 : int elmc4 = 2;
15188 6 : const char* elmv4[] = {"w", "z"};
15189 : CheckOwnProperties(
15190 : isolate,
15191 18 : elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15192 18 : elmc4, elmv4);
15193 6 : }
15194 :
15195 :
15196 23724 : THREADED_TEST(PropertyEnumeration2) {
15197 6 : LocalContext context;
15198 6 : v8::Isolate* isolate = context->GetIsolate();
15199 12 : v8::HandleScope scope(isolate);
15200 : v8::Local<v8::Value> obj = CompileRun(
15201 : "var result = [];"
15202 : "result[0] = {};"
15203 : "result[1] = {a: 1, b: 2};"
15204 : "result[2] = [1, 2, 3];"
15205 : "var proto = {x: 1, y: 2, z: 3};"
15206 : "var x = { __proto__: proto, w: 0, z: 1 };"
15207 : "result[3] = x;"
15208 : "result;");
15209 : v8::Local<v8::Array> elms = obj.As<v8::Array>();
15210 6 : CHECK_EQ(4u, elms->Length());
15211 : int elmc0 = 0;
15212 : const char** elmv0 = nullptr;
15213 : CheckProperties(
15214 : isolate,
15215 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15216 12 : elmc0, elmv0);
15217 :
15218 : v8::Local<v8::Value> val =
15219 18 : elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
15220 : v8::Local<v8::Array> props =
15221 6 : val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
15222 6 : CHECK_EQ(0u, props->Length());
15223 0 : for (uint32_t i = 0; i < props->Length(); i++) {
15224 : printf("p[%u]\n", i);
15225 6 : }
15226 6 : }
15227 :
15228 23724 : THREADED_TEST(PropertyNames) {
15229 6 : LocalContext context;
15230 6 : v8::Isolate* isolate = context->GetIsolate();
15231 12 : v8::HandleScope scope(isolate);
15232 : v8::Local<v8::Value> result = CompileRun(
15233 : "var result = {0: 0, 1: 1, a: 2, b: 3};"
15234 : "result[Symbol('symbol')] = true;"
15235 : "result.__proto__ = {2: 4, 3: 5, c: 6, d: 7};"
15236 : "result;");
15237 : v8::Local<v8::Object> object = result.As<v8::Object>();
15238 : v8::PropertyFilter default_filter =
15239 : static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
15240 : v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
15241 :
15242 : v8::Local<v8::Array> properties =
15243 12 : object->GetPropertyNames(context.local()).ToLocalChecked();
15244 6 : const char* expected_properties1[] = {"0", "1", "a", "b", "2", "3", "c", "d"};
15245 6 : CheckStringArray(isolate, properties, 8, expected_properties1);
15246 :
15247 : properties =
15248 : object
15249 : ->GetPropertyNames(context.local(),
15250 : v8::KeyCollectionMode::kIncludePrototypes,
15251 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15252 12 : .ToLocalChecked();
15253 6 : CheckStringArray(isolate, properties, 8, expected_properties1);
15254 :
15255 : properties = object
15256 : ->GetPropertyNames(context.local(),
15257 : v8::KeyCollectionMode::kIncludePrototypes,
15258 : include_symbols_filter,
15259 6 : v8::IndexFilter::kIncludeIndices)
15260 12 : .ToLocalChecked();
15261 : const char* expected_properties1_1[] = {"0", "1", "a", "b", nullptr,
15262 6 : "2", "3", "c", "d"};
15263 6 : CheckStringArray(isolate, properties, 9, expected_properties1_1);
15264 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15265 :
15266 : properties =
15267 : object
15268 : ->GetPropertyNames(context.local(),
15269 : v8::KeyCollectionMode::kIncludePrototypes,
15270 6 : default_filter, v8::IndexFilter::kSkipIndices)
15271 12 : .ToLocalChecked();
15272 6 : const char* expected_properties2[] = {"a", "b", "c", "d"};
15273 6 : CheckStringArray(isolate, properties, 4, expected_properties2);
15274 :
15275 : properties = object
15276 : ->GetPropertyNames(context.local(),
15277 : v8::KeyCollectionMode::kIncludePrototypes,
15278 : include_symbols_filter,
15279 6 : v8::IndexFilter::kSkipIndices)
15280 12 : .ToLocalChecked();
15281 6 : const char* expected_properties2_1[] = {"a", "b", nullptr, "c", "d"};
15282 6 : CheckStringArray(isolate, properties, 5, expected_properties2_1);
15283 6 : CheckIsSymbolAt(isolate, properties, 2, "symbol");
15284 :
15285 : properties =
15286 : object
15287 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15288 6 : default_filter, v8::IndexFilter::kIncludeIndices)
15289 12 : .ToLocalChecked();
15290 6 : const char* expected_properties3[] = {"0", "1", "a", "b"};
15291 6 : CheckStringArray(isolate, properties, 4, expected_properties3);
15292 :
15293 : properties = object
15294 : ->GetPropertyNames(
15295 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15296 6 : include_symbols_filter, v8::IndexFilter::kIncludeIndices)
15297 12 : .ToLocalChecked();
15298 6 : const char* expected_properties3_1[] = {"0", "1", "a", "b", nullptr};
15299 6 : CheckStringArray(isolate, properties, 5, expected_properties3_1);
15300 6 : CheckIsSymbolAt(isolate, properties, 4, "symbol");
15301 :
15302 : properties =
15303 : object
15304 : ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15305 6 : default_filter, v8::IndexFilter::kSkipIndices)
15306 12 : .ToLocalChecked();
15307 6 : const char* expected_properties4[] = {"a", "b"};
15308 6 : CheckStringArray(isolate, properties, 2, expected_properties4);
15309 :
15310 : properties = object
15311 : ->GetPropertyNames(
15312 : context.local(), v8::KeyCollectionMode::kOwnOnly,
15313 6 : include_symbols_filter, v8::IndexFilter::kSkipIndices)
15314 12 : .ToLocalChecked();
15315 6 : const char* expected_properties4_1[] = {"a", "b", nullptr};
15316 6 : CheckStringArray(isolate, properties, 3, expected_properties4_1);
15317 12 : CheckIsSymbolAt(isolate, properties, 2, "symbol");
15318 6 : }
15319 :
15320 23724 : THREADED_TEST(AccessChecksReenabledCorrectly) {
15321 6 : LocalContext context;
15322 6 : v8::Isolate* isolate = context->GetIsolate();
15323 12 : v8::HandleScope scope(isolate);
15324 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15325 6 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15326 18 : templ->Set(v8_str("a"), v8_str("a"));
15327 : // Add more than 8 (see kMaxFastProperties) properties
15328 : // so that the constructor will force copying map.
15329 : // Cannot sprintf, gcc complains unsafety.
15330 : char buf[4];
15331 66 : for (char i = '0'; i <= '9' ; i++) {
15332 60 : buf[0] = i;
15333 660 : for (char j = '0'; j <= '9'; j++) {
15334 600 : buf[1] = j;
15335 6600 : for (char k = '0'; k <= '9'; k++) {
15336 6000 : buf[2] = k;
15337 6000 : buf[3] = 0;
15338 18000 : templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15339 : }
15340 : }
15341 : }
15342 :
15343 : Local<v8::Object> instance_1 =
15344 6 : templ->NewInstance(context.local()).ToLocalChecked();
15345 30 : CHECK(context->Global()
15346 : ->Set(context.local(), v8_str("obj_1"), instance_1)
15347 : .FromJust());
15348 :
15349 : Local<Value> value_1 = CompileRun("obj_1.a");
15350 6 : CHECK(value_1.IsEmpty());
15351 :
15352 : Local<v8::Object> instance_2 =
15353 6 : templ->NewInstance(context.local()).ToLocalChecked();
15354 30 : CHECK(context->Global()
15355 : ->Set(context.local(), v8_str("obj_2"), instance_2)
15356 : .FromJust());
15357 :
15358 : Local<Value> value_2 = CompileRun("obj_2.a");
15359 12 : CHECK(value_2.IsEmpty());
15360 6 : }
15361 :
15362 :
15363 : // Tests that ScriptData can be serialized and deserialized.
15364 23723 : TEST(PreCompileSerialization) {
15365 : // Producing cached parser data while parsing eagerly is not supported.
15366 5 : if (!i::FLAG_lazy) return;
15367 :
15368 5 : v8::V8::Initialize();
15369 5 : LocalContext env;
15370 5 : v8::Isolate* isolate = env->GetIsolate();
15371 10 : HandleScope handle_scope(isolate);
15372 :
15373 : const char* script = "function foo(a) { return a+1; }";
15374 5 : v8::ScriptCompiler::Source source(v8_str(script));
15375 : v8::ScriptCompiler::Compile(env.local(), &source,
15376 5 : v8::ScriptCompiler::kProduceParserCache)
15377 5 : .ToLocalChecked();
15378 : // Serialize.
15379 5 : const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15380 5 : i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15381 5 : i::MemCopy(serialized_data, cd->data, cd->length);
15382 :
15383 : // Deserialize.
15384 10 : i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15385 :
15386 : // Verify that the original is the same as the deserialized.
15387 5 : CHECK_EQ(cd->length, deserialized->length());
15388 10 : CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15389 :
15390 10 : delete deserialized;
15391 5 : i::DeleteArray(serialized_data);
15392 : }
15393 :
15394 :
15395 : // This tests that we do not allow dictionary load/call inline caches
15396 : // to use functions that have not yet been compiled. The potential
15397 : // problem of loading a function that has not yet been compiled can
15398 : // arise because we share code between contexts via the compilation
15399 : // cache.
15400 23724 : THREADED_TEST(DictionaryICLoadedFunction) {
15401 6 : v8::HandleScope scope(CcTest::isolate());
15402 : // Test LoadIC.
15403 18 : for (int i = 0; i < 2; i++) {
15404 12 : LocalContext context;
15405 72 : CHECK(context->Global()
15406 : ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
15407 : .FromJust());
15408 60 : context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
15409 : CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15410 12 : }
15411 : // Test CallIC.
15412 12 : 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++) RegExp('')");
15419 18 : }
15420 6 : }
15421 :
15422 :
15423 : // Test that cross-context new calls use the context of the callee to
15424 : // create the new JavaScript object.
15425 23724 : THREADED_TEST(CrossContextNew) {
15426 6 : v8::Isolate* isolate = CcTest::isolate();
15427 6 : v8::HandleScope scope(isolate);
15428 6 : v8::Local<Context> context0 = Context::New(isolate);
15429 6 : v8::Local<Context> context1 = Context::New(isolate);
15430 :
15431 : // Allow cross-domain access.
15432 6 : Local<String> token = v8_str("<security token>");
15433 6 : context0->SetSecurityToken(token);
15434 6 : context1->SetSecurityToken(token);
15435 :
15436 : // Set an 'x' property on the Object prototype and define a
15437 : // constructor function in context0.
15438 6 : context0->Enter();
15439 : CompileRun("Object.prototype.x = 42; function C() {};");
15440 6 : context0->Exit();
15441 :
15442 : // Call the constructor function from context0 and check that the
15443 : // result has the 'x' property.
15444 6 : context1->Enter();
15445 30 : CHECK(context1->Global()
15446 : ->Set(context1, v8_str("other"), context0->Global())
15447 : .FromJust());
15448 : Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15449 6 : CHECK(value->IsInt32());
15450 12 : CHECK_EQ(42, value->Int32Value(context1).FromJust());
15451 6 : context1->Exit();
15452 6 : }
15453 :
15454 :
15455 : // Verify that we can clone an object
15456 23723 : TEST(ObjectClone) {
15457 5 : LocalContext env;
15458 5 : v8::Isolate* isolate = env->GetIsolate();
15459 10 : v8::HandleScope scope(isolate);
15460 :
15461 : const char* sample =
15462 : "var rv = {};" \
15463 : "rv.alpha = 'hello';" \
15464 : "rv.beta = 123;" \
15465 : "rv;";
15466 :
15467 : // Create an object, verify basics.
15468 : Local<Value> val = CompileRun(sample);
15469 5 : CHECK(val->IsObject());
15470 : Local<v8::Object> obj = val.As<v8::Object>();
15471 20 : obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
15472 :
15473 25 : CHECK(v8_str("hello")
15474 : ->Equals(env.local(),
15475 : obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15476 : .FromJust());
15477 25 : CHECK(v8::Integer::New(isolate, 123)
15478 : ->Equals(env.local(),
15479 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15480 : .FromJust());
15481 25 : CHECK(v8_str("cloneme")
15482 : ->Equals(env.local(),
15483 : obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15484 : .FromJust());
15485 :
15486 : // Clone it.
15487 5 : Local<v8::Object> clone = obj->Clone();
15488 25 : CHECK(v8_str("hello")
15489 : ->Equals(env.local(),
15490 : clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15491 : .FromJust());
15492 25 : CHECK(v8::Integer::New(isolate, 123)
15493 : ->Equals(env.local(),
15494 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15495 : .FromJust());
15496 25 : CHECK(v8_str("cloneme")
15497 : ->Equals(env.local(),
15498 : clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15499 : .FromJust());
15500 :
15501 : // Set a property on the clone, verify each object.
15502 20 : CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
15503 : .FromJust());
15504 25 : CHECK(v8::Integer::New(isolate, 123)
15505 : ->Equals(env.local(),
15506 : obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15507 : .FromJust());
15508 25 : CHECK(v8::Integer::New(isolate, 456)
15509 : ->Equals(env.local(),
15510 : clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15511 5 : .FromJust());
15512 5 : }
15513 :
15514 :
15515 : class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15516 : public:
15517 : explicit OneByteVectorResource(i::Vector<const char> vector)
15518 6 : : data_(vector) {}
15519 6 : virtual ~OneByteVectorResource() {}
15520 24 : virtual size_t length() const { return data_.length(); }
15521 24 : virtual const char* data() const { return data_.start(); }
15522 : private:
15523 : i::Vector<const char> data_;
15524 : };
15525 :
15526 :
15527 : class UC16VectorResource : public v8::String::ExternalStringResource {
15528 : public:
15529 : explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15530 11 : : data_(vector) {}
15531 6 : virtual ~UC16VectorResource() {}
15532 0 : virtual size_t length() const { return data_.length(); }
15533 438 : virtual const i::uc16* data() const { return data_.start(); }
15534 : private:
15535 : i::Vector<const i::uc16> data_;
15536 : };
15537 :
15538 :
15539 12 : static void MorphAString(i::String* string,
15540 : OneByteVectorResource* one_byte_resource,
15541 : UC16VectorResource* uc16_resource) {
15542 12 : CHECK(i::StringShape(string).IsExternal());
15543 12 : if (string->IsOneByteRepresentation()) {
15544 : // Check old map is not internalized or long.
15545 12 : CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15546 : // Morph external string to be TwoByte string.
15547 12 : string->set_map(CcTest::heap()->external_string_map());
15548 : i::ExternalTwoByteString* morphed =
15549 : i::ExternalTwoByteString::cast(string);
15550 : morphed->set_resource(uc16_resource);
15551 : } else {
15552 : // Check old map is not internalized or long.
15553 0 : CHECK(string->map() == CcTest::heap()->external_string_map());
15554 : // Morph external string to be one-byte string.
15555 0 : string->set_map(CcTest::heap()->external_one_byte_string_map());
15556 : i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15557 : morphed->set_resource(one_byte_resource);
15558 : }
15559 12 : }
15560 :
15561 :
15562 : // Test that we can still flatten a string if the components it is built up
15563 : // from have been turned into 16 bit strings in the mean time.
15564 23724 : THREADED_TEST(MorphCompositeStringTest) {
15565 : char utf_buffer[129];
15566 : const char* c_string = "Now is the time for all good men"
15567 : " to come to the aid of the party";
15568 6 : uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15569 : {
15570 6 : LocalContext env;
15571 : i::Factory* factory = CcTest::i_isolate()->factory();
15572 12 : v8::HandleScope scope(env->GetIsolate());
15573 : OneByteVectorResource one_byte_resource(
15574 : i::Vector<const char>(c_string, i::StrLength(c_string)));
15575 : UC16VectorResource uc16_resource(
15576 : i::Vector<const uint16_t>(two_byte_string,
15577 : i::StrLength(c_string)));
15578 :
15579 : Local<String> lhs(
15580 : v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15581 12 : &one_byte_resource).ToHandleChecked()));
15582 : Local<String> rhs(
15583 : v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15584 12 : &one_byte_resource).ToHandleChecked()));
15585 :
15586 30 : CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
15587 30 : CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
15588 :
15589 : CompileRun(
15590 : "var cons = lhs + rhs;"
15591 : "var slice = lhs.substring(1, lhs.length - 1);"
15592 : "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15593 :
15594 6 : CHECK(lhs->IsOneByte());
15595 6 : CHECK(rhs->IsOneByte());
15596 :
15597 : MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15598 6 : &uc16_resource);
15599 : MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15600 6 : &uc16_resource);
15601 :
15602 : // This should UTF-8 without flattening, since everything is ASCII.
15603 : Local<String> cons =
15604 12 : v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15605 6 : CHECK_EQ(128, cons->Utf8Length());
15606 6 : int nchars = -1;
15607 6 : CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15608 6 : CHECK_EQ(128, nchars);
15609 6 : CHECK_EQ(0, strcmp(
15610 : utf_buffer,
15611 : "Now is the time for all good men to come to the aid of the party"
15612 : "Now is the time for all good men to come to the aid of the party"));
15613 :
15614 : // Now do some stuff to make sure the strings are flattened, etc.
15615 : CompileRun(
15616 : "/[^a-z]/.test(cons);"
15617 : "/[^a-z]/.test(slice);"
15618 : "/[^a-z]/.test(slice_on_cons);");
15619 : const char* expected_cons =
15620 : "Now is the time for all good men to come to the aid of the party"
15621 : "Now is the time for all good men to come to the aid of the party";
15622 : const char* expected_slice =
15623 : "ow is the time for all good men to come to the aid of the part";
15624 : const char* expected_slice_on_cons =
15625 : "ow is the time for all good men to come to the aid of the party"
15626 : "Now is the time for all good men to come to the aid of the part";
15627 42 : CHECK(v8_str(expected_cons)
15628 : ->Equals(env.local(), env->Global()
15629 : ->Get(env.local(), v8_str("cons"))
15630 : .ToLocalChecked())
15631 : .FromJust());
15632 42 : CHECK(v8_str(expected_slice)
15633 : ->Equals(env.local(), env->Global()
15634 : ->Get(env.local(), v8_str("slice"))
15635 : .ToLocalChecked())
15636 : .FromJust());
15637 42 : CHECK(v8_str(expected_slice_on_cons)
15638 : ->Equals(env.local(),
15639 : env->Global()
15640 : ->Get(env.local(), v8_str("slice_on_cons"))
15641 : .ToLocalChecked())
15642 6 : .FromJust());
15643 : }
15644 : i::DeleteArray(two_byte_string);
15645 6 : }
15646 :
15647 :
15648 23723 : TEST(CompileExternalTwoByteSource) {
15649 5 : LocalContext context;
15650 10 : v8::HandleScope scope(context->GetIsolate());
15651 :
15652 : // This is a very short list of sources, which currently is to check for a
15653 : // regression caused by r2703.
15654 : const char* one_byte_sources[] = {
15655 : "0.5",
15656 : "-0.5", // This mainly testes PushBack in the Scanner.
15657 : "--0.5", // This mainly testes PushBack in the Scanner.
15658 5 : nullptr};
15659 :
15660 : // Compile the sources as external two byte strings.
15661 20 : for (int i = 0; one_byte_sources[i] != nullptr; i++) {
15662 15 : uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15663 15 : TestResource* uc16_resource = new TestResource(two_byte_string);
15664 : v8::Local<v8::String> source =
15665 15 : v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15666 30 : .ToLocalChecked();
15667 15 : v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15668 5 : }
15669 5 : }
15670 :
15671 :
15672 : #ifndef V8_INTERPRETED_REGEXP
15673 :
15674 23718 : struct RegExpInterruptionData {
15675 : v8::base::Atomic32 loop_count;
15676 : UC16VectorResource* string_resource;
15677 : v8::Persistent<v8::String> string;
15678 23718 : } regexp_interruption_data;
15679 :
15680 :
15681 5 : class RegExpInterruptionThread : public v8::base::Thread {
15682 : public:
15683 : explicit RegExpInterruptionThread(v8::Isolate* isolate)
15684 5 : : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15685 :
15686 5 : virtual void Run() {
15687 40 : for (v8::base::Relaxed_Store(®exp_interruption_data.loop_count, 0);
15688 : v8::base::Relaxed_Load(®exp_interruption_data.loop_count) < 7;
15689 : v8::base::Relaxed_AtomicIncrement(®exp_interruption_data.loop_count,
15690 : 1)) {
15691 : // Wait a bit before requesting GC.
15692 35 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15693 35 : reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15694 : }
15695 : // Wait a bit before terminating.
15696 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15697 5 : isolate_->TerminateExecution();
15698 5 : }
15699 :
15700 : private:
15701 : v8::Isolate* isolate_;
15702 : };
15703 :
15704 :
15705 2 : void RunBeforeGC(v8::Isolate* isolate, v8::GCType type,
15706 : v8::GCCallbackFlags flags) {
15707 2 : if (v8::base::Relaxed_Load(®exp_interruption_data.loop_count) != 2) {
15708 2 : return;
15709 : }
15710 0 : v8::HandleScope scope(isolate);
15711 : v8::Local<v8::String> string = v8::Local<v8::String>::New(
15712 0 : CcTest::isolate(), regexp_interruption_data.string);
15713 0 : string->MakeExternal(regexp_interruption_data.string_resource);
15714 : }
15715 :
15716 :
15717 : // Test that RegExp execution can be interrupted. Specifically, we test
15718 : // * interrupting with GC
15719 : // * turn the subject string from one-byte internal to two-byte external string
15720 : // * force termination
15721 23723 : TEST(RegExpInterruption) {
15722 5 : LocalContext env;
15723 10 : v8::HandleScope scope(env->GetIsolate());
15724 :
15725 5 : RegExpInterruptionThread timeout_thread(env->GetIsolate());
15726 :
15727 5 : env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC);
15728 : static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15729 5 : i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15730 5 : v8::Local<v8::String> string = v8_str(one_byte_content);
15731 :
15732 25 : env->Global()->Set(env.local(), v8_str("a"), string).FromJust();
15733 5 : regexp_interruption_data.string.Reset(env->GetIsolate(), string);
15734 : regexp_interruption_data.string_resource = new UC16VectorResource(
15735 15 : i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15736 :
15737 10 : v8::TryCatch try_catch(env->GetIsolate());
15738 5 : timeout_thread.Start();
15739 :
15740 : CompileRun("/((a*)*)*b/.exec(a)");
15741 5 : CHECK(try_catch.HasTerminated());
15742 :
15743 5 : timeout_thread.Join();
15744 :
15745 : regexp_interruption_data.string.Reset();
15746 5 : i::DeleteArray(uc16_content);
15747 5 : }
15748 :
15749 : #endif // V8_INTERPRETED_REGEXP
15750 :
15751 :
15752 : // Test that we cannot set a property on the global object if there
15753 : // is a read-only property in the prototype chain.
15754 23723 : TEST(ReadOnlyPropertyInGlobalProto) {
15755 5 : v8::Isolate* isolate = CcTest::isolate();
15756 5 : v8::HandleScope scope(isolate);
15757 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15758 10 : LocalContext context(0, templ);
15759 5 : v8::Local<v8::Object> global = context->Global();
15760 : v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15761 20 : global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15762 : global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15763 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15764 10 : .FromJust();
15765 : global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15766 20 : v8::Integer::New(isolate, 0), v8::ReadOnly)
15767 10 : .FromJust();
15768 : // Check without 'eval' or 'with'.
15769 : v8::Local<v8::Value> res =
15770 5 : CompileRun("function f() { x = 42; return x; }; f()");
15771 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15772 : // Check with 'eval'.
15773 5 : res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15774 15 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15775 : // Check with 'with'.
15776 5 : res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15777 20 : CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15778 5 : }
15779 :
15780 :
15781 23723 : TEST(CreateDataProperty) {
15782 5 : LocalContext env;
15783 5 : v8::Isolate* isolate = env->GetIsolate();
15784 10 : v8::HandleScope handle_scope(isolate);
15785 :
15786 : CompileRun(
15787 : "var a = {};"
15788 : "var b = [];"
15789 : "Object.defineProperty(a, 'foo', {value: 23});"
15790 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15791 :
15792 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15793 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15794 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15795 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15796 : {
15797 : // Can't change a non-configurable properties.
15798 5 : v8::TryCatch try_catch(isolate);
15799 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15800 : v8::Integer::New(isolate, 42)).FromJust());
15801 5 : CHECK(!try_catch.HasCaught());
15802 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15803 : v8::Integer::New(isolate, 42)).FromJust());
15804 5 : CHECK(!try_catch.HasCaught());
15805 : v8::Local<v8::Value> val =
15806 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15807 5 : CHECK(val->IsNumber());
15808 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15809 : }
15810 :
15811 : {
15812 : // Set a regular property.
15813 5 : v8::TryCatch try_catch(isolate);
15814 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15815 : v8::Integer::New(isolate, 42)).FromJust());
15816 5 : CHECK(!try_catch.HasCaught());
15817 : v8::Local<v8::Value> val =
15818 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15819 5 : CHECK(val->IsNumber());
15820 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15821 : }
15822 :
15823 : {
15824 : // Set an indexed property.
15825 5 : v8::TryCatch try_catch(isolate);
15826 20 : CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15827 : v8::Integer::New(isolate, 42)).FromJust());
15828 5 : CHECK(!try_catch.HasCaught());
15829 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15830 5 : CHECK(val->IsNumber());
15831 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15832 : }
15833 :
15834 : {
15835 : // Special cases for arrays.
15836 5 : v8::TryCatch try_catch(isolate);
15837 20 : CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15838 : v8::Integer::New(isolate, 1)).FromJust());
15839 5 : CHECK(!try_catch.HasCaught());
15840 : }
15841 : {
15842 : // Special cases for arrays: index exceeds the array's length
15843 5 : v8::TryCatch try_catch(isolate);
15844 15 : CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15845 : .FromJust());
15846 5 : CHECK(!try_catch.HasCaught());
15847 5 : CHECK_EQ(2U, arr->Length());
15848 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15849 5 : CHECK(val->IsNumber());
15850 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15851 :
15852 : // Set an existing entry.
15853 15 : CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15854 : .FromJust());
15855 5 : CHECK(!try_catch.HasCaught());
15856 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15857 5 : CHECK(val->IsNumber());
15858 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15859 : }
15860 :
15861 : CompileRun("Object.freeze(a);");
15862 : {
15863 : // Can't change non-extensible objects.
15864 5 : v8::TryCatch try_catch(isolate);
15865 20 : CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15866 : v8::Integer::New(isolate, 42)).FromJust());
15867 5 : CHECK(!try_catch.HasCaught());
15868 : }
15869 :
15870 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15871 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15872 : v8::Local<v8::Object> access_checked =
15873 5 : templ->NewInstance(env.local()).ToLocalChecked();
15874 : {
15875 5 : v8::TryCatch try_catch(isolate);
15876 20 : CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15877 : v8::Integer::New(isolate, 42))
15878 : .IsNothing());
15879 5 : CHECK(try_catch.HasCaught());
15880 5 : }
15881 5 : }
15882 :
15883 :
15884 23723 : TEST(DefineOwnProperty) {
15885 5 : LocalContext env;
15886 5 : v8::Isolate* isolate = env->GetIsolate();
15887 10 : v8::HandleScope handle_scope(isolate);
15888 :
15889 : CompileRun(
15890 : "var a = {};"
15891 : "var b = [];"
15892 : "Object.defineProperty(a, 'foo', {value: 23});"
15893 : "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15894 :
15895 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15896 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15897 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15898 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15899 : {
15900 : // Can't change a non-configurable properties.
15901 5 : v8::TryCatch try_catch(isolate);
15902 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15903 : v8::Integer::New(isolate, 42)).FromJust());
15904 5 : CHECK(!try_catch.HasCaught());
15905 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15906 : v8::Integer::New(isolate, 42)).FromJust());
15907 5 : CHECK(!try_catch.HasCaught());
15908 : v8::Local<v8::Value> val =
15909 15 : obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15910 5 : CHECK(val->IsNumber());
15911 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15912 : }
15913 :
15914 : {
15915 : // Set a regular property.
15916 5 : v8::TryCatch try_catch(isolate);
15917 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15918 : v8::Integer::New(isolate, 42)).FromJust());
15919 5 : CHECK(!try_catch.HasCaught());
15920 : v8::Local<v8::Value> val =
15921 15 : obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15922 5 : CHECK(val->IsNumber());
15923 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15924 : }
15925 :
15926 : {
15927 : // Set an indexed property.
15928 5 : v8::TryCatch try_catch(isolate);
15929 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15930 : v8::Integer::New(isolate, 42)).FromJust());
15931 5 : CHECK(!try_catch.HasCaught());
15932 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15933 5 : CHECK(val->IsNumber());
15934 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15935 : }
15936 :
15937 : {
15938 : // Special cases for arrays.
15939 5 : v8::TryCatch try_catch(isolate);
15940 20 : CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15941 : v8::Integer::New(isolate, 1)).FromJust());
15942 5 : CHECK(!try_catch.HasCaught());
15943 : }
15944 : {
15945 : // Special cases for arrays: index exceeds the array's length
15946 5 : v8::TryCatch try_catch(isolate);
15947 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15948 : v8::Integer::New(isolate, 23)).FromJust());
15949 5 : CHECK(!try_catch.HasCaught());
15950 5 : CHECK_EQ(2U, arr->Length());
15951 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15952 5 : CHECK(val->IsNumber());
15953 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15954 :
15955 : // Set an existing entry.
15956 20 : CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15957 : v8::Integer::New(isolate, 42)).FromJust());
15958 5 : CHECK(!try_catch.HasCaught());
15959 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
15960 5 : CHECK(val->IsNumber());
15961 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15962 : }
15963 :
15964 : {
15965 : // Set a non-writable property.
15966 5 : v8::TryCatch try_catch(isolate);
15967 20 : CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15968 : v8::Integer::New(isolate, 42),
15969 : v8::ReadOnly).FromJust());
15970 5 : CHECK(!try_catch.HasCaught());
15971 : v8::Local<v8::Value> val =
15972 15 : obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15973 5 : CHECK(val->IsNumber());
15974 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15975 15 : CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
15976 : env.local(), v8_str("lala")).FromJust());
15977 5 : CHECK(!try_catch.HasCaught());
15978 : }
15979 :
15980 : CompileRun("Object.freeze(a);");
15981 : {
15982 : // Can't change non-extensible objects.
15983 5 : v8::TryCatch try_catch(isolate);
15984 20 : CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
15985 : v8::Integer::New(isolate, 42)).FromJust());
15986 5 : CHECK(!try_catch.HasCaught());
15987 : }
15988 :
15989 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15990 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15991 : v8::Local<v8::Object> access_checked =
15992 5 : templ->NewInstance(env.local()).ToLocalChecked();
15993 : {
15994 5 : v8::TryCatch try_catch(isolate);
15995 20 : CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
15996 : v8::Integer::New(isolate, 42))
15997 : .IsNothing());
15998 5 : CHECK(try_catch.HasCaught());
15999 5 : }
16000 5 : }
16001 :
16002 23723 : TEST(DefineProperty) {
16003 5 : LocalContext env;
16004 5 : v8::Isolate* isolate = env->GetIsolate();
16005 10 : v8::HandleScope handle_scope(isolate);
16006 :
16007 : v8::Local<v8::Name> p;
16008 :
16009 : CompileRun(
16010 : "var a = {};"
16011 : "var b = [];"
16012 : "Object.defineProperty(a, 'v1', {value: 23});"
16013 : "Object.defineProperty(a, 'v2', {value: 23, configurable: true});");
16014 :
16015 : v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
16016 25 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
16017 : v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
16018 25 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
16019 :
16020 10 : v8::PropertyDescriptor desc(v8_num(42));
16021 : {
16022 : // Use a data descriptor.
16023 :
16024 : // Cannot change a non-configurable property.
16025 5 : p = v8_str("v1");
16026 5 : v8::TryCatch try_catch(isolate);
16027 10 : CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
16028 5 : CHECK(!try_catch.HasCaught());
16029 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16030 5 : CHECK(val->IsNumber());
16031 10 : CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
16032 :
16033 : // Change a configurable property.
16034 5 : p = v8_str("v2");
16035 10 : obj->DefineProperty(env.local(), p, desc).FromJust();
16036 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16037 5 : CHECK(!try_catch.HasCaught());
16038 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16039 5 : CHECK(val->IsNumber());
16040 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16041 :
16042 : // Check that missing writable has default value false.
16043 5 : p = v8_str("v12");
16044 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16045 5 : CHECK(!try_catch.HasCaught());
16046 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16047 5 : CHECK(val->IsNumber());
16048 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16049 10 : v8::PropertyDescriptor desc2(v8_num(43));
16050 10 : CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust());
16051 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16052 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16053 10 : CHECK(!try_catch.HasCaught());
16054 : }
16055 :
16056 : {
16057 : // Set a regular property.
16058 5 : p = v8_str("v3");
16059 5 : v8::TryCatch try_catch(isolate);
16060 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16061 5 : CHECK(!try_catch.HasCaught());
16062 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16063 5 : CHECK(val->IsNumber());
16064 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16065 : }
16066 :
16067 : {
16068 : // Set an indexed property.
16069 5 : v8::TryCatch try_catch(isolate);
16070 15 : CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust());
16071 5 : CHECK(!try_catch.HasCaught());
16072 5 : v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
16073 5 : CHECK(val->IsNumber());
16074 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16075 : }
16076 :
16077 : {
16078 : // No special case when changing array length.
16079 5 : v8::TryCatch try_catch(isolate);
16080 : // Use a writable descriptor, otherwise the next test, that changes
16081 : // the array length will fail.
16082 10 : v8::PropertyDescriptor desc(v8_num(42), true);
16083 15 : CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust());
16084 10 : CHECK(!try_catch.HasCaught());
16085 : }
16086 :
16087 : {
16088 : // Special cases for arrays: index exceeds the array's length.
16089 5 : v8::TryCatch try_catch(isolate);
16090 15 : CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust());
16091 5 : CHECK(!try_catch.HasCaught());
16092 5 : CHECK_EQ(101U, arr->Length());
16093 5 : v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
16094 5 : CHECK(val->IsNumber());
16095 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16096 :
16097 : // Set an existing entry.
16098 15 : CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust());
16099 5 : CHECK(!try_catch.HasCaught());
16100 5 : val = arr->Get(env.local(), 0).ToLocalChecked();
16101 5 : CHECK(val->IsNumber());
16102 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16103 : }
16104 :
16105 : {
16106 : // Use a generic descriptor.
16107 5 : v8::PropertyDescriptor desc_generic;
16108 :
16109 5 : p = v8_str("v4");
16110 10 : v8::TryCatch try_catch(isolate);
16111 10 : CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust());
16112 5 : CHECK(!try_catch.HasCaught());
16113 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16114 5 : CHECK(val->IsUndefined());
16115 :
16116 15 : obj->Set(env.local(), p, v8_num(1)).FromJust();
16117 5 : CHECK(!try_catch.HasCaught());
16118 :
16119 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16120 5 : CHECK(val->IsUndefined());
16121 10 : CHECK(!try_catch.HasCaught());
16122 : }
16123 :
16124 : {
16125 : // Use a data descriptor with undefined value.
16126 5 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate));
16127 :
16128 10 : v8::TryCatch try_catch(isolate);
16129 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16130 5 : CHECK(!try_catch.HasCaught());
16131 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16132 5 : CHECK(val->IsUndefined());
16133 10 : CHECK(!try_catch.HasCaught());
16134 : }
16135 :
16136 : {
16137 : // Use a descriptor with attribute == v8::ReadOnly.
16138 5 : v8::PropertyDescriptor desc_read_only(v8_num(42), false);
16139 5 : desc_read_only.set_enumerable(true);
16140 5 : desc_read_only.set_configurable(true);
16141 :
16142 5 : p = v8_str("v5");
16143 10 : v8::TryCatch try_catch(isolate);
16144 10 : CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust());
16145 5 : CHECK(!try_catch.HasCaught());
16146 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16147 5 : CHECK(val->IsNumber());
16148 10 : CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
16149 10 : CHECK_EQ(v8::ReadOnly,
16150 : obj->GetPropertyAttributes(env.local(), p).FromJust());
16151 10 : CHECK(!try_catch.HasCaught());
16152 : }
16153 :
16154 : {
16155 : // Use an accessor descriptor with empty handles.
16156 : v8::PropertyDescriptor desc_empty(v8::Undefined(isolate),
16157 5 : v8::Undefined(isolate));
16158 :
16159 5 : p = v8_str("v6");
16160 10 : v8::TryCatch try_catch(isolate);
16161 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16162 5 : CHECK(!try_catch.HasCaught());
16163 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16164 5 : CHECK(val->IsUndefined());
16165 10 : CHECK(!try_catch.HasCaught());
16166 : }
16167 :
16168 : {
16169 : // Use an accessor descriptor.
16170 : CompileRun(
16171 : "var set = function(x) {this.val = 2*x;};"
16172 : "var get = function() {return this.val || 0;};");
16173 :
16174 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
16175 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
16176 : v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
16177 25 : env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
16178 5 : v8::PropertyDescriptor desc(get, set);
16179 :
16180 5 : p = v8_str("v7");
16181 10 : v8::TryCatch try_catch(isolate);
16182 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16183 5 : CHECK(!try_catch.HasCaught());
16184 :
16185 10 : v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
16186 5 : CHECK(val->IsNumber());
16187 10 : CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
16188 5 : CHECK(!try_catch.HasCaught());
16189 :
16190 15 : obj->Set(env.local(), p, v8_num(7)).FromJust();
16191 5 : CHECK(!try_catch.HasCaught());
16192 :
16193 10 : val = obj->Get(env.local(), p).ToLocalChecked();
16194 5 : CHECK(val->IsNumber());
16195 10 : CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
16196 10 : CHECK(!try_catch.HasCaught());
16197 : }
16198 :
16199 : {
16200 : // Redefine an existing property.
16201 :
16202 : // desc = {value: 42, enumerable: true}
16203 5 : v8::PropertyDescriptor desc(v8_num(42));
16204 5 : desc.set_enumerable(true);
16205 :
16206 5 : p = v8_str("v8");
16207 10 : v8::TryCatch try_catch(isolate);
16208 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16209 5 : CHECK(!try_catch.HasCaught());
16210 :
16211 : // desc = {enumerable: true}
16212 10 : v8::PropertyDescriptor desc_true((v8::Local<v8::Value>()));
16213 5 : desc_true.set_enumerable(true);
16214 :
16215 : // Successful redefinition because all present attributes have the same
16216 : // value as the current descriptor.
16217 10 : CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust());
16218 5 : CHECK(!try_catch.HasCaught());
16219 :
16220 : // desc = {}
16221 10 : v8::PropertyDescriptor desc_empty;
16222 : // Successful redefinition because no attributes are overwritten in the
16223 : // current descriptor.
16224 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16225 5 : CHECK(!try_catch.HasCaught());
16226 :
16227 : // desc = {enumerable: false}
16228 10 : v8::PropertyDescriptor desc_false((v8::Local<v8::Value>()));
16229 5 : desc_false.set_enumerable(false);
16230 : // Not successful because we cannot define a different value for enumerable.
16231 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
16232 10 : CHECK(!try_catch.HasCaught());
16233 : }
16234 :
16235 : {
16236 : // Redefine a property that has a getter.
16237 : CompileRun("var get = function() {};");
16238 : v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
16239 25 : env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
16240 :
16241 : // desc = {get: function() {}}
16242 5 : v8::PropertyDescriptor desc(get, v8::Local<v8::Function>());
16243 10 : v8::TryCatch try_catch(isolate);
16244 :
16245 5 : p = v8_str("v9");
16246 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16247 5 : CHECK(!try_catch.HasCaught());
16248 :
16249 : // desc_empty = {}
16250 : // Successful because we are not redefining the current getter.
16251 10 : v8::PropertyDescriptor desc_empty;
16252 10 : CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
16253 5 : CHECK(!try_catch.HasCaught());
16254 :
16255 : // desc = {get: function() {}}
16256 : // Successful because we redefine the getter with its current value.
16257 10 : CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
16258 5 : CHECK(!try_catch.HasCaught());
16259 :
16260 : // desc = {get: undefined}
16261 : v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate),
16262 10 : v8::Local<v8::Function>());
16263 : // Not successful because we cannot redefine with the current value of get
16264 : // with undefined.
16265 10 : CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust());
16266 10 : CHECK(!try_catch.HasCaught());
16267 : }
16268 :
16269 : CompileRun("Object.freeze(a);");
16270 : {
16271 : // We cannot change non-extensible objects.
16272 5 : v8::TryCatch try_catch(isolate);
16273 15 : CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust());
16274 5 : CHECK(!try_catch.HasCaught());
16275 : }
16276 :
16277 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16278 5 : templ->SetAccessCheckCallback(AccessAlwaysBlocked);
16279 : v8::Local<v8::Object> access_checked =
16280 5 : templ->NewInstance(env.local()).ToLocalChecked();
16281 : {
16282 5 : v8::TryCatch try_catch(isolate);
16283 15 : CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc)
16284 : .IsNothing());
16285 5 : CHECK(try_catch.HasCaught());
16286 5 : }
16287 5 : }
16288 :
16289 23724 : THREADED_TEST(GetCurrentContextWhenNotInContext) {
16290 6 : i::Isolate* isolate = CcTest::i_isolate();
16291 6 : CHECK_NOT_NULL(isolate);
16292 6 : CHECK_NULL(isolate->context());
16293 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16294 6 : v8::HandleScope scope(v8_isolate);
16295 : // The following should not crash, but return an empty handle.
16296 6 : v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16297 6 : CHECK(current.IsEmpty());
16298 6 : }
16299 :
16300 :
16301 : // Check that a variable declaration with no explicit initialization
16302 : // value does shadow an existing property in the prototype chain.
16303 23724 : THREADED_TEST(InitGlobalVarInProtoChain) {
16304 6 : LocalContext context;
16305 12 : v8::HandleScope scope(context->GetIsolate());
16306 : // Introduce a variable in the prototype chain.
16307 : CompileRun("__proto__.x = 42");
16308 : v8::Local<v8::Value> result = CompileRun("var x = 43; x");
16309 6 : CHECK(!result->IsUndefined());
16310 18 : CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
16311 6 : }
16312 :
16313 :
16314 : // Regression test for issue 398.
16315 : // If a function is added to an object, creating a constant function
16316 : // field, and the result is cloned, replacing the constant function on the
16317 : // original should not affect the clone.
16318 : // See http://code.google.com/p/v8/issues/detail?id=398
16319 23724 : THREADED_TEST(ReplaceConstantFunction) {
16320 6 : LocalContext context;
16321 6 : v8::Isolate* isolate = context->GetIsolate();
16322 12 : v8::HandleScope scope(isolate);
16323 6 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
16324 : v8::Local<v8::FunctionTemplate> func_templ =
16325 6 : v8::FunctionTemplate::New(isolate);
16326 6 : v8::Local<v8::String> foo_string = v8_str("foo");
16327 : obj->Set(context.local(), foo_string,
16328 24 : func_templ->GetFunction(context.local()).ToLocalChecked())
16329 12 : .FromJust();
16330 6 : v8::Local<v8::Object> obj_clone = obj->Clone();
16331 24 : obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
16332 18 : CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
16333 6 : }
16334 :
16335 :
16336 504 : static void CheckElementValue(i::Isolate* isolate,
16337 : int expected,
16338 : i::Handle<i::Object> obj,
16339 : int offset) {
16340 : i::Object* element =
16341 1008 : *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16342 504 : CHECK_EQ(expected, i::Smi::ToInt(element));
16343 504 : }
16344 :
16345 :
16346 : template <class ExternalArrayClass, class ElementType>
16347 162 : static void ObjectWithExternalArrayTestHelper(Local<Context> context,
16348 : v8::Local<Object> obj,
16349 : int element_count,
16350 : i::ExternalArrayType array_type,
16351 : int64_t low, int64_t high) {
16352 : i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
16353 : i::Isolate* isolate = jsobj->GetIsolate();
16354 : obj->Set(context, v8_str("field"),
16355 486 : v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503))
16356 324 : .FromJust();
16357 648 : CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
16358 : v8::Local<v8::Value> result = CompileRun("ext_array.field");
16359 324 : CHECK_EQ(1503, result->Int32Value(context).FromJust());
16360 : result = CompileRun("ext_array[1]");
16361 324 : CHECK_EQ(1, result->Int32Value(context).FromJust());
16362 :
16363 : // Check assigned smis
16364 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16365 : " ext_array[i] = i;"
16366 : "}"
16367 : "var sum = 0;"
16368 : "for (var i = 0; i < 8; i++) {"
16369 : " sum += ext_array[i];"
16370 : "}"
16371 : "sum;");
16372 :
16373 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16374 : // Check pass through of assigned smis
16375 : result = CompileRun("var sum = 0;"
16376 : "for (var i = 0; i < 8; i++) {"
16377 : " sum += ext_array[i] = ext_array[i] = -i;"
16378 : "}"
16379 : "sum;");
16380 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
16381 :
16382 :
16383 : // Check assigned smis in reverse order
16384 : result = CompileRun("for (var i = 8; --i >= 0; ) {"
16385 : " ext_array[i] = i;"
16386 : "}"
16387 : "var sum = 0;"
16388 : "for (var i = 0; i < 8; i++) {"
16389 : " sum += ext_array[i];"
16390 : "}"
16391 : "sum;");
16392 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16393 :
16394 : // Check pass through of assigned HeapNumbers
16395 : result = CompileRun("var sum = 0;"
16396 : "for (var i = 0; i < 16; i+=2) {"
16397 : " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16398 : "}"
16399 : "sum;");
16400 324 : CHECK_EQ(-28, result->Int32Value(context).FromJust());
16401 :
16402 : // Check assigned HeapNumbers
16403 : result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16404 : " ext_array[i] = (i * 0.5);"
16405 : "}"
16406 : "var sum = 0;"
16407 : "for (var i = 0; i < 16; i+=2) {"
16408 : " sum += ext_array[i];"
16409 : "}"
16410 : "sum;");
16411 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16412 :
16413 : // Check assigned HeapNumbers in reverse order
16414 : result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16415 : " ext_array[i] = (i * 0.5);"
16416 : "}"
16417 : "var sum = 0;"
16418 : "for (var i = 0; i < 16; i+=2) {"
16419 : " sum += ext_array[i];"
16420 : "}"
16421 : "sum;");
16422 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16423 :
16424 : i::ScopedVector<char> test_buf(1024);
16425 :
16426 : // Check legal boundary conditions.
16427 : // The repeated loads and stores ensure the ICs are exercised.
16428 : const char* boundary_program =
16429 : "var res = 0;"
16430 : "for (var i = 0; i < 16; i++) {"
16431 : " ext_array[i] = %lld;"
16432 : " if (i > 8) {"
16433 : " res = ext_array[i];"
16434 : " }"
16435 : "}"
16436 : "res;";
16437 162 : i::SNPrintF(test_buf,
16438 : boundary_program,
16439 : low);
16440 : result = CompileRun(test_buf.start());
16441 324 : CHECK_EQ(low, result->IntegerValue(context).FromJust());
16442 :
16443 162 : i::SNPrintF(test_buf,
16444 : boundary_program,
16445 : high);
16446 : result = CompileRun(test_buf.start());
16447 324 : CHECK_EQ(high, result->IntegerValue(context).FromJust());
16448 :
16449 : // Check misprediction of type in IC.
16450 : result = CompileRun("var tmp_array = ext_array;"
16451 : "var sum = 0;"
16452 : "for (var i = 0; i < 8; i++) {"
16453 : " tmp_array[i] = i;"
16454 : " sum += tmp_array[i];"
16455 : " if (i == 4) {"
16456 : " tmp_array = {};"
16457 : " }"
16458 : "}"
16459 : "sum;");
16460 : // Force GC to trigger verification.
16461 162 : CcTest::CollectAllGarbage();
16462 324 : CHECK_EQ(28, result->Int32Value(context).FromJust());
16463 :
16464 : // Make sure out-of-range loads do not throw.
16465 162 : i::SNPrintF(test_buf,
16466 : "var caught_exception = false;"
16467 : "try {"
16468 : " ext_array[%d];"
16469 : "} catch (e) {"
16470 : " caught_exception = true;"
16471 : "}"
16472 : "caught_exception;",
16473 : element_count);
16474 : result = CompileRun(test_buf.start());
16475 324 : CHECK(!result->BooleanValue(context).FromJust());
16476 :
16477 : // Make sure out-of-range stores do not throw.
16478 162 : i::SNPrintF(test_buf,
16479 : "var caught_exception = false;"
16480 : "try {"
16481 : " ext_array[%d] = 1;"
16482 : "} catch (e) {"
16483 : " caught_exception = true;"
16484 : "}"
16485 : "caught_exception;",
16486 : element_count);
16487 : result = CompileRun(test_buf.start());
16488 324 : CHECK(!result->BooleanValue(context).FromJust());
16489 :
16490 : // Check other boundary conditions, values and operations.
16491 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16492 : " ext_array[7] = undefined;"
16493 : "}"
16494 : "ext_array[7];");
16495 324 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16496 162 : if (array_type == i::kExternalFloat64Array ||
16497 : array_type == i::kExternalFloat32Array) {
16498 72 : CHECK(std::isnan(
16499 : i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
16500 : } else {
16501 126 : CheckElementValue(isolate, 0, jsobj, 7);
16502 : }
16503 :
16504 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16505 : " ext_array[6] = '2.3';"
16506 : "}"
16507 : "ext_array[6];");
16508 324 : CHECK_EQ(2, result->Int32Value(context).FromJust());
16509 324 : CHECK_EQ(2,
16510 : static_cast<int>(
16511 : i::Object::GetElement(
16512 : isolate, jsobj, 6).ToHandleChecked()->Number()));
16513 :
16514 162 : if (array_type != i::kExternalFloat32Array &&
16515 : array_type != i::kExternalFloat64Array) {
16516 : // Though the specification doesn't state it, be explicit about
16517 : // converting NaNs and +/-Infinity to zero.
16518 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16519 : " ext_array[i] = 5;"
16520 : "}"
16521 : "for (var i = 0; i < 8; i++) {"
16522 : " ext_array[i] = NaN;"
16523 : "}"
16524 : "ext_array[5];");
16525 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16526 126 : CheckElementValue(isolate, 0, jsobj, 5);
16527 :
16528 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16529 : " ext_array[i] = 5;"
16530 : "}"
16531 : "for (var i = 0; i < 8; i++) {"
16532 : " ext_array[i] = Infinity;"
16533 : "}"
16534 : "ext_array[5];");
16535 : int expected_value =
16536 126 : (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
16537 252 : CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
16538 126 : CheckElementValue(isolate, expected_value, jsobj, 5);
16539 :
16540 : result = CompileRun("for (var i = 0; i < 8; i++) {"
16541 : " ext_array[i] = 5;"
16542 : "}"
16543 : "for (var i = 0; i < 8; i++) {"
16544 : " ext_array[i] = -Infinity;"
16545 : "}"
16546 : "ext_array[5];");
16547 252 : CHECK_EQ(0, result->Int32Value(context).FromJust());
16548 126 : CheckElementValue(isolate, 0, jsobj, 5);
16549 :
16550 : // Check truncation behavior of integral arrays.
16551 : const char* unsigned_data =
16552 : "var source_data = [0.6, 10.6];"
16553 : "var expected_results = [0, 10];";
16554 : const char* signed_data =
16555 : "var source_data = [0.6, 10.6, -0.6, -10.6];"
16556 : "var expected_results = [0, 10, 0, -10];";
16557 : const char* pixel_data =
16558 : "var source_data = [0.6, 10.6];"
16559 : "var expected_results = [1, 11];";
16560 : bool is_unsigned = (array_type == i::kExternalUint8Array ||
16561 : array_type == i::kExternalUint16Array ||
16562 126 : array_type == i::kExternalUint32Array);
16563 : bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
16564 :
16565 126 : i::SNPrintF(test_buf,
16566 : "%s"
16567 : "var all_passed = true;"
16568 : "for (var i = 0; i < source_data.length; i++) {"
16569 : " for (var j = 0; j < 8; j++) {"
16570 : " ext_array[j] = source_data[i];"
16571 : " }"
16572 : " all_passed = all_passed &&"
16573 : " (ext_array[5] == expected_results[i]);"
16574 : "}"
16575 : "all_passed;",
16576 : (is_unsigned ?
16577 : unsigned_data :
16578 126 : (is_pixel_data ? pixel_data : signed_data)));
16579 : result = CompileRun(test_buf.start());
16580 252 : CHECK(result->BooleanValue(context).FromJust());
16581 : }
16582 :
16583 : i::Handle<ExternalArrayClass> array(ExternalArrayClass::cast(
16584 : i::Handle<i::JSObject>::cast(jsobj)->elements()));
16585 19602 : for (int i = 0; i < element_count; i++) {
16586 36720 : array->set(i, static_cast<ElementType>(i));
16587 : }
16588 :
16589 : // Test complex assignments
16590 : result = CompileRun("function ee_op_test_complex_func(sum) {"
16591 : " for (var i = 0; i < 40; ++i) {"
16592 : " sum += (ext_array[i] += 1);"
16593 : " sum += (ext_array[i] -= 1);"
16594 : " } "
16595 : " return sum;"
16596 : "}"
16597 : "sum=0;"
16598 : "for (var i=0;i<10000;++i) {"
16599 : " sum=ee_op_test_complex_func(sum);"
16600 : "}"
16601 : "sum;");
16602 324 : CHECK_EQ(16000000, result->Int32Value(context).FromJust());
16603 :
16604 : // Test count operations
16605 : result = CompileRun("function ee_op_test_count_func(sum) {"
16606 : " for (var i = 0; i < 40; ++i) {"
16607 : " sum += (++ext_array[i]);"
16608 : " sum += (--ext_array[i]);"
16609 : " } "
16610 : " return sum;"
16611 : "}"
16612 : "sum=0;"
16613 : "for (var i=0;i<10000;++i) {"
16614 : " sum=ee_op_test_count_func(sum);"
16615 : "}"
16616 : "sum;");
16617 324 : CHECK_EQ(16000000, result->Int32Value(context).FromJust());
16618 :
16619 : result = CompileRun("ext_array[3] = 33;"
16620 : "delete ext_array[3];"
16621 : "ext_array[3];");
16622 324 : CHECK_EQ(33, result->Int32Value(context).FromJust());
16623 :
16624 : result = CompileRun(
16625 : "ext_array[0] = 10; ext_array[1] = 11;"
16626 : "ext_array[2] = 12; ext_array[3] = 13;"
16627 : "try { ext_array.__defineGetter__('2', function() { return 120; }); }"
16628 : "catch (e) { }"
16629 : "ext_array[2];");
16630 324 : CHECK_EQ(12, result->Int32Value(context).FromJust());
16631 :
16632 : result = CompileRun("var js_array = new Array(40);"
16633 : "js_array[0] = 77;"
16634 : "js_array;");
16635 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16636 : ->Get(context, v8_str("0"))
16637 : .ToLocalChecked()
16638 : ->Int32Value(context)
16639 : .FromJust());
16640 :
16641 : result = CompileRun("ext_array[1] = 23;"
16642 : "ext_array.__proto__ = [];"
16643 : "js_array.__proto__ = ext_array;"
16644 : "js_array.concat(ext_array);");
16645 648 : CHECK_EQ(77, v8::Object::Cast(*result)
16646 : ->Get(context, v8_str("0"))
16647 : .ToLocalChecked()
16648 : ->Int32Value(context)
16649 : .FromJust());
16650 648 : CHECK_EQ(23, v8::Object::Cast(*result)
16651 : ->Get(context, v8_str("1"))
16652 : .ToLocalChecked()
16653 : ->Int32Value(context)
16654 : .FromJust());
16655 :
16656 : result = CompileRun("ext_array[1] = 23;");
16657 324 : CHECK_EQ(23, result->Int32Value(context).FromJust());
16658 162 : }
16659 :
16660 :
16661 : template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16662 : class ElementType>
16663 54 : static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16664 : ElementType low, ElementType high) {
16665 54 : i::FLAG_allow_natives_syntax = true;
16666 54 : LocalContext context;
16667 : i::Isolate* isolate = CcTest::i_isolate();
16668 : i::Factory* factory = isolate->factory();
16669 108 : v8::HandleScope scope(context->GetIsolate());
16670 : const int kElementCount = 260;
16671 : i::Handle<i::JSTypedArray> jsobj =
16672 54 : factory->NewJSTypedArray(elements_kind, kElementCount);
16673 : i::Handle<FixedTypedArrayClass> fixed_array(
16674 : FixedTypedArrayClass::cast(jsobj->elements()));
16675 54 : CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16676 : fixed_array->map()->instance_type());
16677 54 : CHECK_EQ(kElementCount, fixed_array->length());
16678 54 : CcTest::CollectAllGarbage();
16679 14094 : for (int i = 0; i < kElementCount; i++) {
16680 26520 : fixed_array->set(i, static_cast<ElementType>(i));
16681 : }
16682 : // Force GC to trigger verification.
16683 54 : CcTest::CollectAllGarbage();
16684 14094 : for (int i = 0; i < kElementCount; i++) {
16685 14040 : CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16686 : static_cast<int64_t>(fixed_array->get_scalar(i)));
16687 : }
16688 : v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16689 :
16690 54 : ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16691 : context.local(), obj, kElementCount, array_type,
16692 : static_cast<int64_t>(low),
16693 108 : static_cast<int64_t>(high));
16694 54 : }
16695 :
16696 :
16697 23724 : THREADED_TEST(FixedUint8Array) {
16698 : FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16699 6 : i::kExternalUint8Array, 0x0, 0xFF);
16700 6 : }
16701 :
16702 :
16703 23724 : THREADED_TEST(FixedUint8ClampedArray) {
16704 : FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16705 : i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16706 6 : i::kExternalUint8ClampedArray, 0x0, 0xFF);
16707 6 : }
16708 :
16709 :
16710 23724 : THREADED_TEST(FixedInt8Array) {
16711 : FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16712 6 : i::kExternalInt8Array, -0x80, 0x7F);
16713 6 : }
16714 :
16715 :
16716 23724 : THREADED_TEST(FixedUint16Array) {
16717 : FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16718 6 : i::kExternalUint16Array, 0x0, 0xFFFF);
16719 6 : }
16720 :
16721 :
16722 23724 : THREADED_TEST(FixedInt16Array) {
16723 : FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16724 6 : i::kExternalInt16Array, -0x8000, 0x7FFF);
16725 6 : }
16726 :
16727 :
16728 23724 : THREADED_TEST(FixedUint32Array) {
16729 : FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16730 6 : i::kExternalUint32Array, 0x0, UINT_MAX);
16731 6 : }
16732 :
16733 :
16734 23724 : THREADED_TEST(FixedInt32Array) {
16735 : FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16736 6 : i::kExternalInt32Array, INT_MIN, INT_MAX);
16737 6 : }
16738 :
16739 :
16740 23724 : THREADED_TEST(FixedFloat32Array) {
16741 : FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16742 6 : i::kExternalFloat32Array, -500, 500);
16743 6 : }
16744 :
16745 :
16746 23724 : THREADED_TEST(FixedFloat64Array) {
16747 : FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16748 6 : i::kExternalFloat64Array, -500, 500);
16749 6 : }
16750 :
16751 :
16752 : template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16753 : class ArrayBufferType>
16754 108 : void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16755 : int64_t high) {
16756 : const int kElementCount = 50;
16757 :
16758 : i::ScopedVector<ElementType> backing_store(kElementCount+2);
16759 :
16760 216 : LocalContext env;
16761 108 : v8::Isolate* isolate = env->GetIsolate();
16762 216 : v8::HandleScope handle_scope(isolate);
16763 :
16764 : Local<ArrayBufferType> ab =
16765 : ArrayBufferType::New(isolate, backing_store.start(),
16766 108 : (kElementCount + 2) * sizeof(ElementType));
16767 : Local<TypedArray> ta =
16768 108 : TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16769 108 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16770 108 : CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16771 108 : CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16772 108 : CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16773 432 : CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16774 :
16775 108 : ElementType* data = backing_store.start() + 2;
16776 5508 : for (int i = 0; i < kElementCount; i++) {
16777 5400 : data[i] = static_cast<ElementType>(i);
16778 : }
16779 :
16780 108 : ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16781 216 : env.local(), ta, kElementCount, array_type, low, high);
16782 108 : }
16783 :
16784 :
16785 23724 : THREADED_TEST(Uint8Array) {
16786 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16787 6 : v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16788 6 : }
16789 :
16790 :
16791 23724 : THREADED_TEST(Int8Array) {
16792 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16793 6 : v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16794 6 : }
16795 :
16796 :
16797 23724 : THREADED_TEST(Uint16Array) {
16798 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16799 6 : v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16800 6 : }
16801 :
16802 :
16803 23724 : THREADED_TEST(Int16Array) {
16804 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16805 : v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16806 6 : 0x7FFF);
16807 6 : }
16808 :
16809 :
16810 23724 : THREADED_TEST(Uint32Array) {
16811 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16812 6 : v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16813 6 : }
16814 :
16815 :
16816 23724 : THREADED_TEST(Int32Array) {
16817 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16818 : v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16819 6 : INT_MAX);
16820 6 : }
16821 :
16822 :
16823 23724 : THREADED_TEST(Float32Array) {
16824 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16825 6 : v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16826 6 : }
16827 :
16828 :
16829 23724 : THREADED_TEST(Float64Array) {
16830 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16831 6 : v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16832 6 : }
16833 :
16834 :
16835 23724 : THREADED_TEST(Uint8ClampedArray) {
16836 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16837 : i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16838 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16839 6 : }
16840 :
16841 :
16842 23724 : THREADED_TEST(DataView) {
16843 : const int kSize = 50;
16844 :
16845 : i::ScopedVector<uint8_t> backing_store(kSize+2);
16846 :
16847 12 : LocalContext env;
16848 6 : v8::Isolate* isolate = env->GetIsolate();
16849 12 : v8::HandleScope handle_scope(isolate);
16850 :
16851 : Local<v8::ArrayBuffer> ab =
16852 6 : v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16853 6 : Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16854 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16855 6 : CHECK_EQ(2u, dv->ByteOffset());
16856 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16857 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16858 6 : }
16859 :
16860 :
16861 23724 : THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16862 6 : LocalContext env;
16863 6 : v8::Isolate* isolate = env->GetIsolate();
16864 12 : v8::HandleScope handle_scope(isolate);
16865 :
16866 : // Make sure the pointer looks like a heap object
16867 : uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16868 :
16869 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16870 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16871 :
16872 : // Should not crash
16873 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16874 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16875 6 : CcTest::CollectAllGarbage();
16876 6 : CcTest::CollectAllGarbage();
16877 :
16878 : // Should not move the pointer
16879 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16880 6 : }
16881 :
16882 :
16883 23724 : THREADED_TEST(SkipArrayBufferDuringScavenge) {
16884 6 : LocalContext env;
16885 6 : v8::Isolate* isolate = env->GetIsolate();
16886 12 : v8::HandleScope handle_scope(isolate);
16887 :
16888 : // Make sure the pointer looks like a heap object
16889 6 : Local<v8::Object> tmp = v8::Object::New(isolate);
16890 : uint8_t* store_ptr =
16891 6 : reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16892 :
16893 : // Make `store_ptr` point to from space
16894 6 : CcTest::CollectGarbage(i::NEW_SPACE);
16895 :
16896 : // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16897 6 : Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16898 :
16899 : // Should not crash,
16900 : // i.e. backing store pointer should not be treated as a heap object pointer
16901 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16902 6 : CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16903 :
16904 : // Use `ab` to silence compiler warning
16905 12 : CHECK_EQ(ab->GetContents().Data(), store_ptr);
16906 6 : }
16907 :
16908 :
16909 23724 : THREADED_TEST(SharedUint8Array) {
16910 6 : i::FLAG_harmony_sharedarraybuffer = true;
16911 : TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16912 6 : v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16913 6 : }
16914 :
16915 :
16916 23724 : THREADED_TEST(SharedInt8Array) {
16917 6 : i::FLAG_harmony_sharedarraybuffer = true;
16918 : TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16919 : v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16920 6 : 0x7F);
16921 6 : }
16922 :
16923 :
16924 23724 : THREADED_TEST(SharedUint16Array) {
16925 6 : i::FLAG_harmony_sharedarraybuffer = true;
16926 : TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16927 : v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16928 6 : 0xFFFF);
16929 6 : }
16930 :
16931 :
16932 23724 : THREADED_TEST(SharedInt16Array) {
16933 6 : i::FLAG_harmony_sharedarraybuffer = true;
16934 : TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16935 : v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16936 6 : 0x7FFF);
16937 6 : }
16938 :
16939 :
16940 23724 : THREADED_TEST(SharedUint32Array) {
16941 6 : i::FLAG_harmony_sharedarraybuffer = true;
16942 : TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16943 : v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16944 6 : UINT_MAX);
16945 6 : }
16946 :
16947 :
16948 23724 : THREADED_TEST(SharedInt32Array) {
16949 6 : i::FLAG_harmony_sharedarraybuffer = true;
16950 : TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16951 : v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16952 6 : INT_MAX);
16953 6 : }
16954 :
16955 :
16956 23724 : THREADED_TEST(SharedFloat32Array) {
16957 6 : i::FLAG_harmony_sharedarraybuffer = true;
16958 : TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16959 : v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16960 6 : 500);
16961 6 : }
16962 :
16963 :
16964 23724 : THREADED_TEST(SharedFloat64Array) {
16965 6 : i::FLAG_harmony_sharedarraybuffer = true;
16966 : TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16967 : v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
16968 6 : 500);
16969 6 : }
16970 :
16971 :
16972 23724 : THREADED_TEST(SharedUint8ClampedArray) {
16973 6 : i::FLAG_harmony_sharedarraybuffer = true;
16974 : TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16975 : i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
16976 6 : i::kExternalUint8ClampedArray, 0, 0xFF);
16977 6 : }
16978 :
16979 :
16980 23724 : THREADED_TEST(SharedDataView) {
16981 6 : i::FLAG_harmony_sharedarraybuffer = true;
16982 : const int kSize = 50;
16983 :
16984 : i::ScopedVector<uint8_t> backing_store(kSize + 2);
16985 :
16986 12 : LocalContext env;
16987 6 : v8::Isolate* isolate = env->GetIsolate();
16988 12 : v8::HandleScope handle_scope(isolate);
16989 :
16990 : Local<v8::SharedArrayBuffer> ab =
16991 6 : v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16992 : Local<v8::DataView> dv =
16993 6 : v8::DataView::New(ab, 2, kSize);
16994 6 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16995 6 : CHECK_EQ(2u, dv->ByteOffset());
16996 6 : CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16997 24 : CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16998 6 : }
16999 :
17000 : #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17001 : THREADED_TEST(Is##View) { \
17002 : LocalContext env; \
17003 : v8::Isolate* isolate = env->GetIsolate(); \
17004 : v8::HandleScope handle_scope(isolate); \
17005 : \
17006 : Local<Value> result = CompileRun( \
17007 : "var ab = new ArrayBuffer(128);" \
17008 : "new " #View "(ab)"); \
17009 : CHECK(result->IsArrayBufferView()); \
17010 : CHECK(result->Is##View()); \
17011 : CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17012 : }
17013 :
17014 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17015 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17016 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17017 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17018 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17019 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17020 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17021 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17022 23748 : IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17023 23748 : IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17024 :
17025 : #undef IS_ARRAY_BUFFER_VIEW_TEST
17026 :
17027 :
17028 :
17029 23724 : THREADED_TEST(ScriptContextDependence) {
17030 6 : LocalContext c1;
17031 12 : v8::HandleScope scope(c1->GetIsolate());
17032 : const char *source = "foo";
17033 : v8::Local<v8::Script> dep = v8_compile(source);
17034 : v8::ScriptCompiler::Source script_source(
17035 : v8::String::NewFromUtf8(c1->GetIsolate(), source,
17036 6 : v8::NewStringType::kNormal)
17037 6 : .ToLocalChecked());
17038 : v8::Local<v8::UnboundScript> indep =
17039 6 : v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
17040 6 : .ToLocalChecked();
17041 : c1->Global()
17042 : ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
17043 6 : v8::NewStringType::kNormal)
17044 : .ToLocalChecked(),
17045 30 : v8::Integer::New(c1->GetIsolate(), 100))
17046 12 : .FromJust();
17047 18 : CHECK_EQ(
17048 : dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
17049 : 100);
17050 24 : CHECK_EQ(indep->BindToCurrentContext()
17051 : ->Run(c1.local())
17052 : .ToLocalChecked()
17053 : ->Int32Value(c1.local())
17054 : .FromJust(),
17055 : 100);
17056 12 : LocalContext c2;
17057 : c2->Global()
17058 : ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
17059 6 : v8::NewStringType::kNormal)
17060 : .ToLocalChecked(),
17061 30 : v8::Integer::New(c2->GetIsolate(), 101))
17062 12 : .FromJust();
17063 18 : CHECK_EQ(
17064 : dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
17065 : 100);
17066 24 : CHECK_EQ(indep->BindToCurrentContext()
17067 : ->Run(c2.local())
17068 : .ToLocalChecked()
17069 : ->Int32Value(c2.local())
17070 : .FromJust(),
17071 6 : 101);
17072 6 : }
17073 :
17074 :
17075 23724 : THREADED_TEST(StackTrace) {
17076 6 : LocalContext context;
17077 12 : v8::HandleScope scope(context->GetIsolate());
17078 12 : v8::TryCatch try_catch(context->GetIsolate());
17079 : const char *source = "function foo() { FAIL.FAIL; }; foo();";
17080 6 : v8::Local<v8::String> src = v8_str(source);
17081 6 : v8::Local<v8::String> origin = v8_str("stack-trace-test");
17082 : v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17083 30 : CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
17084 : &script_source)
17085 : .ToLocalChecked()
17086 : ->BindToCurrentContext()
17087 : ->Run(context.local())
17088 : .IsEmpty());
17089 6 : CHECK(try_catch.HasCaught());
17090 : v8::String::Utf8Value stack(
17091 : context->GetIsolate(),
17092 18 : try_catch.StackTrace(context.local()).ToLocalChecked());
17093 18 : CHECK_NOT_NULL(strstr(*stack, "at foo (stack-trace-test"));
17094 6 : }
17095 :
17096 :
17097 : // Checks that a StackFrame has certain expected values.
17098 100 : void checkStackFrame(const char* expected_script_name,
17099 : const char* expected_func_name, int expected_line_number,
17100 : int expected_column, bool is_eval, bool is_constructor,
17101 : v8::Local<v8::StackFrame> frame) {
17102 100 : v8::HandleScope scope(CcTest::isolate());
17103 300 : v8::String::Utf8Value func_name(CcTest::isolate(), frame->GetFunctionName());
17104 300 : v8::String::Utf8Value script_name(CcTest::isolate(), frame->GetScriptName());
17105 100 : if (*script_name == nullptr) {
17106 : // The situation where there is no associated script, like for evals.
17107 10 : CHECK_NULL(expected_script_name);
17108 : } else {
17109 90 : CHECK_NOT_NULL(strstr(*script_name, expected_script_name));
17110 : }
17111 200 : CHECK_NOT_NULL(strstr(*func_name, expected_func_name));
17112 100 : CHECK_EQ(expected_line_number, frame->GetLineNumber());
17113 100 : CHECK_EQ(expected_column, frame->GetColumn());
17114 100 : CHECK_EQ(is_eval, frame->IsEval());
17115 200 : CHECK_EQ(is_constructor, frame->IsConstructor());
17116 100 : }
17117 :
17118 :
17119 140 : void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17120 35 : v8::HandleScope scope(args.GetIsolate());
17121 : const char* origin = "capture-stack-trace-test";
17122 : const int kOverviewTest = 1;
17123 : const int kDetailedTest = 2;
17124 : const int kFunctionName = 3;
17125 : const int kDisplayName = 4;
17126 : const int kFunctionNameAndDisplayName = 5;
17127 : const int kDisplayNameIsNotString = 6;
17128 : const int kFunctionNameIsNotString = 7;
17129 :
17130 35 : CHECK_EQ(args.Length(), 1);
17131 :
17132 35 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
17133 70 : int testGroup = args[0]->Int32Value(context).FromJust();
17134 35 : if (testGroup == kOverviewTest) {
17135 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17136 5 : args.GetIsolate(), 10, v8::StackTrace::kOverview);
17137 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
17138 : checkStackFrame(origin, "bar", 2, 10, false, false,
17139 5 : stackTrace->GetFrame(0));
17140 5 : checkStackFrame(origin, "foo", 6, 3, false, true, stackTrace->GetFrame(1));
17141 : // This is the source string inside the eval which has the call to foo.
17142 5 : checkStackFrame(nullptr, "", 1, 1, true, false, stackTrace->GetFrame(2));
17143 : // The last frame is an anonymous function which has the initial eval call.
17144 5 : checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
17145 30 : } else if (testGroup == kDetailedTest) {
17146 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17147 5 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17148 5 : CHECK_EQ(4, stackTrace->GetFrameCount());
17149 : checkStackFrame(origin, "bat", 4, 22, false, false,
17150 5 : stackTrace->GetFrame(0));
17151 : checkStackFrame(origin, "baz", 8, 3, false, true,
17152 5 : stackTrace->GetFrame(1));
17153 : bool is_eval = true;
17154 : // This is the source string inside the eval which has the call to baz.
17155 5 : checkStackFrame(nullptr, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
17156 : // The last frame is an anonymous function which has the initial eval call.
17157 5 : checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
17158 25 : } else if (testGroup == kFunctionName) {
17159 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17160 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17161 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17162 : checkStackFrame(origin, "function.name", 2, 24, false, false,
17163 5 : stackTrace->GetFrame(0));
17164 20 : } else if (testGroup == kDisplayName) {
17165 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17166 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17167 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17168 : checkStackFrame(origin, "function.displayName", 2, 24, false, false,
17169 5 : stackTrace->GetFrame(0));
17170 15 : } else if (testGroup == kFunctionNameAndDisplayName) {
17171 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17172 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17173 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17174 : checkStackFrame(origin, "function.displayName", 2, 24, false, false,
17175 5 : stackTrace->GetFrame(0));
17176 10 : } else if (testGroup == kDisplayNameIsNotString) {
17177 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17178 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17179 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17180 : checkStackFrame(origin, "function.name", 2, 24, false, false,
17181 5 : stackTrace->GetFrame(0));
17182 5 : } else if (testGroup == kFunctionNameIsNotString) {
17183 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17184 5 : args.GetIsolate(), 5, v8::StackTrace::kOverview);
17185 5 : CHECK_EQ(3, stackTrace->GetFrameCount());
17186 5 : checkStackFrame(origin, "f", 2, 24, false, false, stackTrace->GetFrame(0));
17187 35 : }
17188 35 : }
17189 :
17190 :
17191 : // Tests the C++ StackTrace API.
17192 : // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17193 : // THREADED_TEST(CaptureStackTrace) {
17194 23723 : TEST(CaptureStackTrace) {
17195 5 : v8::Isolate* isolate = CcTest::isolate();
17196 5 : v8::HandleScope scope(isolate);
17197 5 : v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
17198 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17199 : templ->Set(v8_str("AnalyzeStackInNativeCode"),
17200 15 : v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17201 10 : LocalContext context(0, templ);
17202 :
17203 : // Test getting OVERVIEW information. Should ignore information that is not
17204 : // script name, function name, line number, and column offset.
17205 : const char *overview_source =
17206 : "function bar() {\n"
17207 : " var y; AnalyzeStackInNativeCode(1);\n"
17208 : "}\n"
17209 : "function foo() {\n"
17210 : "\n"
17211 : " bar();\n"
17212 : "}\n"
17213 : "var x;eval('new foo();');";
17214 5 : v8::Local<v8::String> overview_src = v8_str(overview_source);
17215 : v8::ScriptCompiler::Source script_source(overview_src,
17216 : v8::ScriptOrigin(origin));
17217 : v8::Local<Value> overview_result(
17218 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
17219 5 : .ToLocalChecked()
17220 : ->BindToCurrentContext()
17221 15 : ->Run(context.local())
17222 5 : .ToLocalChecked());
17223 5 : CHECK(!overview_result.IsEmpty());
17224 5 : CHECK(overview_result->IsObject());
17225 :
17226 : // Test getting DETAILED information.
17227 : const char *detailed_source =
17228 : "function bat() {AnalyzeStackInNativeCode(2);\n"
17229 : "}\n"
17230 : "\n"
17231 : "function baz() {\n"
17232 : " bat();\n"
17233 : "}\n"
17234 : "eval('new baz();');";
17235 5 : v8::Local<v8::String> detailed_src = v8_str(detailed_source);
17236 : // Make the script using a non-zero line and column offset.
17237 5 : v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17238 5 : v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17239 : v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17240 : v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17241 : v8::Local<v8::UnboundScript> detailed_script(
17242 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
17243 5 : .ToLocalChecked());
17244 : v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
17245 10 : ->Run(context.local())
17246 5 : .ToLocalChecked());
17247 5 : CHECK(!detailed_result.IsEmpty());
17248 5 : CHECK(detailed_result->IsObject());
17249 :
17250 : // Test using function.name and function.displayName in stack trace
17251 : const char* function_name_source =
17252 : "function bar(function_name, display_name, testGroup) {\n"
17253 : " var f = function() { AnalyzeStackInNativeCode(testGroup); };\n"
17254 : " if (function_name) {\n"
17255 : " Object.defineProperty(f, 'name', { value: function_name });\n"
17256 : " }\n"
17257 : " if (display_name) {\n"
17258 : " f.displayName = display_name;"
17259 : " }\n"
17260 : " f()\n"
17261 : "}\n"
17262 : "bar('function.name', undefined, 3);\n"
17263 : "bar(undefined, 'function.displayName', 4);\n"
17264 : "bar('function.name', 'function.displayName', 5);\n"
17265 : "bar('function.name', 239, 6);\n"
17266 : "bar(239, undefined, 7);\n";
17267 : v8::Local<v8::String> function_name_src =
17268 : v8::String::NewFromUtf8(isolate, function_name_source,
17269 : v8::NewStringType::kNormal)
17270 5 : .ToLocalChecked();
17271 : v8::ScriptCompiler::Source script_source3(function_name_src,
17272 : v8::ScriptOrigin(origin));
17273 : v8::Local<Value> function_name_result(
17274 : v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
17275 5 : .ToLocalChecked()
17276 : ->BindToCurrentContext()
17277 15 : ->Run(context.local())
17278 5 : .ToLocalChecked());
17279 10 : CHECK(!function_name_result.IsEmpty());
17280 5 : }
17281 :
17282 :
17283 5 : static void StackTraceForUncaughtExceptionListener(
17284 : v8::Local<v8::Message> message, v8::Local<Value>) {
17285 5 : report_count++;
17286 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17287 5 : CHECK_EQ(2, stack_trace->GetFrameCount());
17288 : checkStackFrame("origin", "foo", 2, 3, false, false,
17289 5 : stack_trace->GetFrame(0));
17290 : checkStackFrame("origin", "bar", 5, 3, false, false,
17291 5 : stack_trace->GetFrame(1));
17292 5 : }
17293 :
17294 :
17295 23723 : TEST(CaptureStackTraceForUncaughtException) {
17296 5 : report_count = 0;
17297 5 : LocalContext env;
17298 5 : v8::Isolate* isolate = env->GetIsolate();
17299 10 : v8::HandleScope scope(isolate);
17300 5 : isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
17301 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17302 :
17303 : CompileRunWithOrigin(
17304 : "function foo() {\n"
17305 : " throw 1;\n"
17306 : "};\n"
17307 : "function bar() {\n"
17308 : " foo();\n"
17309 : "};",
17310 : "origin");
17311 5 : v8::Local<v8::Object> global = env->Global();
17312 : Local<Value> trouble =
17313 20 : global->Get(env.local(), v8_str("bar")).ToLocalChecked();
17314 5 : CHECK(trouble->IsFunction());
17315 10 : CHECK(Function::Cast(*trouble)
17316 : ->Call(env.local(), global, 0, nullptr)
17317 : .IsEmpty());
17318 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17319 5 : isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17320 10 : CHECK_EQ(1, report_count);
17321 5 : }
17322 :
17323 23723 : TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17324 5 : LocalContext env;
17325 5 : v8::Isolate* isolate = env->GetIsolate();
17326 10 : v8::HandleScope scope(isolate);
17327 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
17328 5 : v8::StackTrace::kDetailed);
17329 :
17330 : CompileRun(
17331 : "var setters = ['column', 'lineNumber', 'scriptName',\n"
17332 : " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17333 : " 'isConstructor'];\n"
17334 : "for (var i = 0; i < setters.length; i++) {\n"
17335 : " var prop = setters[i];\n"
17336 : " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17337 : "}\n");
17338 : CompileRun("throw 'exception';");
17339 10 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17340 5 : }
17341 :
17342 : static int asm_warning_triggered = 0;
17343 :
17344 4 : static void AsmJsWarningListener(v8::Local<v8::Message> message,
17345 : v8::Local<Value>) {
17346 : DCHECK_EQ(v8::Isolate::kMessageWarning, message->ErrorLevel());
17347 4 : asm_warning_triggered = 1;
17348 4 : }
17349 :
17350 23723 : TEST(AsmJsWarning) {
17351 5 : i::FLAG_validate_asm = true;
17352 6 : if (i::FLAG_suppress_asm_messages) return;
17353 :
17354 4 : LocalContext env;
17355 4 : v8::Isolate* isolate = env->GetIsolate();
17356 8 : v8::HandleScope scope(isolate);
17357 :
17358 4 : asm_warning_triggered = 0;
17359 : isolate->AddMessageListenerWithErrorLevel(AsmJsWarningListener,
17360 4 : v8::Isolate::kMessageAll);
17361 : CompileRun(
17362 : "function module() {\n"
17363 : " 'use asm';\n"
17364 : " var x = 'hi';\n"
17365 : " return {};\n"
17366 : "}\n"
17367 : "module();");
17368 : DCHECK_EQ(1, asm_warning_triggered);
17369 8 : isolate->RemoveMessageListeners(AsmJsWarningListener);
17370 : }
17371 :
17372 : static int error_level_message_count = 0;
17373 : static int expected_error_level = 0;
17374 :
17375 20 : static void ErrorLevelListener(v8::Local<v8::Message> message,
17376 : v8::Local<Value>) {
17377 : DCHECK_EQ(expected_error_level, message->ErrorLevel());
17378 20 : ++error_level_message_count;
17379 20 : }
17380 :
17381 23723 : TEST(ErrorLevelWarning) {
17382 5 : LocalContext env;
17383 5 : v8::Isolate* isolate = env->GetIsolate();
17384 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
17385 10 : v8::HandleScope scope(isolate);
17386 :
17387 : const char* source = "fake = 1;";
17388 5 : v8::Local<v8::Script> lscript = CompileWithOrigin(source, "test");
17389 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
17390 10 : v8::Utils::OpenHandle(*lscript->GetUnboundScript()));
17391 5 : CHECK(obj->script()->IsScript());
17392 : i::Handle<i::Script> script(i::Script::cast(obj->script()));
17393 :
17394 : int levels[] = {
17395 : v8::Isolate::kMessageLog, v8::Isolate::kMessageInfo,
17396 : v8::Isolate::kMessageDebug, v8::Isolate::kMessageWarning,
17397 5 : };
17398 5 : error_level_message_count = 0;
17399 : isolate->AddMessageListenerWithErrorLevel(ErrorLevelListener,
17400 5 : v8::Isolate::kMessageAll);
17401 25 : for (size_t i = 0; i < arraysize(levels); i++) {
17402 20 : i::MessageLocation location(script, 0, 0);
17403 : i::Handle<i::String> msg(i_isolate->factory()->InternalizeOneByteString(
17404 20 : STATIC_CHAR_VECTOR("test")));
17405 : i::Handle<i::JSMessageObject> message =
17406 : i::MessageHandler::MakeMessageObject(
17407 : i_isolate, i::MessageTemplate::kAsmJsInvalid, &location, msg,
17408 20 : i::Handle<i::FixedArray>::null());
17409 20 : message->set_error_level(levels[i]);
17410 20 : expected_error_level = levels[i];
17411 20 : i::MessageHandler::ReportMessage(i_isolate, &location, message);
17412 : }
17413 5 : isolate->RemoveMessageListeners(ErrorLevelListener);
17414 5 : DCHECK_EQ(arraysize(levels), error_level_message_count);
17415 5 : }
17416 :
17417 5 : static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
17418 : v8::Local<Value>) {
17419 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17420 5 : CHECK_EQ(5, stack_trace->GetFrameCount());
17421 : checkStackFrame("origin", "foo:0", 4, 7, false, false,
17422 5 : stack_trace->GetFrame(0));
17423 : checkStackFrame("origin", "foo:1", 5, 27, false, false,
17424 5 : stack_trace->GetFrame(1));
17425 : checkStackFrame("origin", "foo", 5, 27, false, false,
17426 5 : stack_trace->GetFrame(2));
17427 : checkStackFrame("origin", "foo", 5, 27, false, false,
17428 5 : stack_trace->GetFrame(3));
17429 5 : checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
17430 5 : }
17431 :
17432 :
17433 23723 : TEST(GetStackTraceContainsFunctionsWithFunctionName) {
17434 5 : LocalContext env;
17435 5 : v8::Isolate* isolate = env->GetIsolate();
17436 10 : v8::HandleScope scope(isolate);
17437 :
17438 : CompileRunWithOrigin(
17439 : "function gen(name, counter) {\n"
17440 : " var f = function foo() {\n"
17441 : " if (counter === 0)\n"
17442 : " throw 1;\n"
17443 : " gen(name, counter - 1)();\n"
17444 : " };\n"
17445 : " if (counter == 3) {\n"
17446 : " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
17447 : " } else {\n"
17448 : " Object.defineProperty(f, 'name', {writable:true});\n"
17449 : " if (counter == 2)\n"
17450 : " f.name = 42;\n"
17451 : " else\n"
17452 : " f.name = name + ':' + counter;\n"
17453 : " }\n"
17454 : " return f;\n"
17455 : "};",
17456 : "origin");
17457 :
17458 5 : isolate->AddMessageListener(StackTraceFunctionNameListener);
17459 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17460 : CompileRunWithOrigin("gen('foo', 3)();", "origin");
17461 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17462 10 : isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
17463 5 : }
17464 :
17465 :
17466 5 : static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
17467 : v8::Local<v8::Value> data) {
17468 : // Use the frame where JavaScript is called from.
17469 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17470 5 : CHECK(!stack_trace.IsEmpty());
17471 5 : int frame_count = stack_trace->GetFrameCount();
17472 5 : CHECK_EQ(3, frame_count);
17473 5 : int line_number[] = {1, 2, 5};
17474 20 : for (int i = 0; i < frame_count; i++) {
17475 30 : CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17476 : }
17477 5 : }
17478 :
17479 :
17480 : // Test that we only return the stack trace at the site where the exception
17481 : // is first thrown (not where it is rethrown).
17482 23723 : TEST(RethrowStackTrace) {
17483 5 : LocalContext env;
17484 5 : v8::Isolate* isolate = env->GetIsolate();
17485 10 : v8::HandleScope scope(isolate);
17486 : // We make sure that
17487 : // - the stack trace of the ReferenceError in g() is reported.
17488 : // - the stack trace is not overwritten when e1 is rethrown by t().
17489 : // - the stack trace of e2 does not overwrite that of e1.
17490 : const char* source =
17491 : "function g() { error; } \n"
17492 : "function f() { g(); } \n"
17493 : "function t(e) { throw e; } \n"
17494 : "try { \n"
17495 : " f(); \n"
17496 : "} catch (e1) { \n"
17497 : " try { \n"
17498 : " error; \n"
17499 : " } catch (e2) { \n"
17500 : " t(e1); \n"
17501 : " } \n"
17502 : "} \n";
17503 5 : isolate->AddMessageListener(RethrowStackTraceHandler);
17504 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17505 : CompileRun(source);
17506 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17507 10 : isolate->RemoveMessageListeners(RethrowStackTraceHandler);
17508 5 : }
17509 :
17510 :
17511 5 : static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
17512 : v8::Local<v8::Value> data) {
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(2, frame_count);
17517 5 : int line_number[] = {3, 7};
17518 15 : for (int i = 0; i < frame_count; i++) {
17519 20 : CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17520 : }
17521 5 : }
17522 :
17523 :
17524 : // Test that we do not recognize identity for primitive exceptions.
17525 23723 : TEST(RethrowPrimitiveStackTrace) {
17526 5 : LocalContext env;
17527 5 : v8::Isolate* isolate = env->GetIsolate();
17528 10 : v8::HandleScope scope(isolate);
17529 : // We do not capture stack trace for non Error objects on creation time.
17530 : // Instead, we capture the stack trace on last throw.
17531 : const char* source =
17532 : "function g() { throw 404; } \n"
17533 : "function f() { g(); } \n"
17534 : "function t(e) { throw e; } \n"
17535 : "try { \n"
17536 : " f(); \n"
17537 : "} catch (e1) { \n"
17538 : " t(e1) \n"
17539 : "} \n";
17540 5 : isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
17541 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17542 : CompileRun(source);
17543 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17544 10 : isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17545 5 : }
17546 :
17547 :
17548 5 : static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
17549 : v8::Local<v8::Value> data) {
17550 : // Use the frame where JavaScript is called from.
17551 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17552 5 : CHECK(!stack_trace.IsEmpty());
17553 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
17554 10 : CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17555 5 : }
17556 :
17557 :
17558 : // Test that the stack trace is captured when the error object is created and
17559 : // not where it is thrown.
17560 23723 : TEST(RethrowExistingStackTrace) {
17561 5 : LocalContext env;
17562 5 : v8::Isolate* isolate = env->GetIsolate();
17563 10 : v8::HandleScope scope(isolate);
17564 : const char* source =
17565 : "var e = new Error(); \n"
17566 : "throw e; \n";
17567 5 : isolate->AddMessageListener(RethrowExistingStackTraceHandler);
17568 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17569 : CompileRun(source);
17570 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17571 10 : isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
17572 5 : }
17573 :
17574 :
17575 5 : static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
17576 : v8::Local<v8::Value> data) {
17577 : // Use the frame where JavaScript is called from.
17578 5 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17579 5 : CHECK(!stack_trace.IsEmpty());
17580 5 : CHECK_EQ(1, stack_trace->GetFrameCount());
17581 10 : CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17582 5 : }
17583 :
17584 :
17585 : // Test that the stack trace is captured where the bogus Error object is thrown.
17586 23723 : TEST(RethrowBogusErrorStackTrace) {
17587 5 : LocalContext env;
17588 5 : v8::Isolate* isolate = env->GetIsolate();
17589 10 : v8::HandleScope scope(isolate);
17590 : const char* source =
17591 : "var e = {__proto__: new Error()} \n"
17592 : "throw e; \n";
17593 5 : isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
17594 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17595 : CompileRun(source);
17596 5 : isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17597 10 : isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17598 5 : }
17599 :
17600 :
17601 : v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17602 : int promise_reject_counter = 0;
17603 : int promise_revoke_counter = 0;
17604 : int promise_reject_msg_line_number = -1;
17605 : int promise_reject_msg_column_number = -1;
17606 : int promise_reject_line_number = -1;
17607 : int promise_reject_column_number = -1;
17608 : int promise_reject_frame_count = -1;
17609 :
17610 110 : void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
17611 110 : v8::Local<v8::Object> global = CcTest::global();
17612 110 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17613 110 : CHECK_EQ(v8::Promise::PromiseState::kRejected,
17614 : reject_message.GetPromise()->State());
17615 110 : if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
17616 80 : promise_reject_counter++;
17617 160 : global->Set(context, v8_str("rejected"), reject_message.GetPromise())
17618 160 : .FromJust();
17619 240 : global->Set(context, v8_str("value"), reject_message.GetValue()).FromJust();
17620 : v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17621 80 : CcTest::isolate(), reject_message.GetValue());
17622 80 : v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17623 :
17624 160 : promise_reject_msg_line_number = message->GetLineNumber(context).FromJust();
17625 : promise_reject_msg_column_number =
17626 160 : message->GetStartColumn(context).FromJust() + 1;
17627 :
17628 80 : if (!stack_trace.IsEmpty()) {
17629 35 : promise_reject_frame_count = stack_trace->GetFrameCount();
17630 35 : if (promise_reject_frame_count > 0) {
17631 150 : CHECK(stack_trace->GetFrame(0)
17632 : ->GetScriptName()
17633 : ->Equals(context, v8_str("pro"))
17634 : .FromJust());
17635 60 : promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
17636 60 : promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
17637 : } else {
17638 5 : promise_reject_line_number = -1;
17639 5 : promise_reject_column_number = -1;
17640 : }
17641 : }
17642 : } else {
17643 30 : promise_revoke_counter++;
17644 60 : global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17645 60 : .FromJust();
17646 30 : CHECK(reject_message.GetValue().IsEmpty());
17647 : }
17648 110 : }
17649 :
17650 :
17651 550 : v8::Local<v8::Promise> GetPromise(const char* name) {
17652 : return v8::Local<v8::Promise>::Cast(
17653 : CcTest::global()
17654 1650 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17655 1100 : .ToLocalChecked());
17656 : }
17657 :
17658 :
17659 35 : v8::Local<v8::Value> RejectValue() {
17660 : return CcTest::global()
17661 105 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17662 70 : .ToLocalChecked();
17663 : }
17664 :
17665 :
17666 40 : void ResetPromiseStates() {
17667 40 : promise_reject_counter = 0;
17668 40 : promise_revoke_counter = 0;
17669 40 : promise_reject_msg_line_number = -1;
17670 40 : promise_reject_msg_column_number = -1;
17671 40 : promise_reject_line_number = -1;
17672 40 : promise_reject_column_number = -1;
17673 40 : promise_reject_frame_count = -1;
17674 :
17675 40 : v8::Local<v8::Object> global = CcTest::global();
17676 40 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17677 160 : global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17678 160 : global->Set(context, v8_str("value"), v8_str("")).FromJust();
17679 160 : global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17680 40 : }
17681 :
17682 :
17683 23723 : TEST(PromiseRejectCallback) {
17684 5 : LocalContext env;
17685 5 : v8::Isolate* isolate = env->GetIsolate();
17686 10 : v8::HandleScope scope(isolate);
17687 :
17688 5 : isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17689 :
17690 5 : ResetPromiseStates();
17691 :
17692 : // Create promise p0.
17693 : CompileRun(
17694 : "var reject; \n"
17695 : "var p0 = new Promise( \n"
17696 : " function(res, rej) { \n"
17697 : " reject = rej; \n"
17698 : " } \n"
17699 : "); \n");
17700 10 : CHECK(!GetPromise("p0")->HasHandler());
17701 5 : CHECK_EQ(0, promise_reject_counter);
17702 5 : CHECK_EQ(0, promise_revoke_counter);
17703 :
17704 : // Add resolve handler (and default reject handler) to p0.
17705 : CompileRun("var p1 = p0.then(function(){});");
17706 10 : CHECK(GetPromise("p0")->HasHandler());
17707 10 : CHECK(!GetPromise("p1")->HasHandler());
17708 5 : CHECK_EQ(0, promise_reject_counter);
17709 5 : CHECK_EQ(0, promise_revoke_counter);
17710 :
17711 : // Reject p0.
17712 : CompileRun("reject('ppp');");
17713 10 : CHECK(GetPromise("p0")->HasHandler());
17714 10 : CHECK(!GetPromise("p1")->HasHandler());
17715 5 : CHECK_EQ(1, promise_reject_counter);
17716 5 : CHECK_EQ(0, promise_revoke_counter);
17717 5 : CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17718 20 : CHECK(
17719 : GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17720 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17721 :
17722 : // Reject p0 again. Callback is not triggered again.
17723 : CompileRun("reject();");
17724 10 : CHECK(GetPromise("p0")->HasHandler());
17725 10 : CHECK(!GetPromise("p1")->HasHandler());
17726 5 : CHECK_EQ(1, promise_reject_counter);
17727 5 : CHECK_EQ(0, promise_revoke_counter);
17728 :
17729 : // Add resolve handler to p1.
17730 : CompileRun("var p2 = p1.then(function(){});");
17731 10 : CHECK(GetPromise("p0")->HasHandler());
17732 10 : CHECK(GetPromise("p1")->HasHandler());
17733 10 : CHECK(!GetPromise("p2")->HasHandler());
17734 5 : CHECK_EQ(2, promise_reject_counter);
17735 5 : CHECK_EQ(1, promise_revoke_counter);
17736 20 : CHECK(
17737 : GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17738 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17739 20 : CHECK(
17740 : GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17741 :
17742 5 : ResetPromiseStates();
17743 :
17744 : // Create promise q0.
17745 : CompileRun(
17746 : "var q0 = new Promise( \n"
17747 : " function(res, rej) { \n"
17748 : " reject = rej; \n"
17749 : " } \n"
17750 : "); \n");
17751 10 : CHECK(!GetPromise("q0")->HasHandler());
17752 5 : CHECK_EQ(0, promise_reject_counter);
17753 5 : CHECK_EQ(0, promise_revoke_counter);
17754 :
17755 : // Add reject handler to q0.
17756 : CompileRun("var q1 = q0.catch(function() {});");
17757 10 : CHECK(GetPromise("q0")->HasHandler());
17758 10 : CHECK(!GetPromise("q1")->HasHandler());
17759 5 : CHECK_EQ(0, promise_reject_counter);
17760 5 : CHECK_EQ(0, promise_revoke_counter);
17761 :
17762 : // Reject q0.
17763 : CompileRun("reject('qq')");
17764 10 : CHECK(GetPromise("q0")->HasHandler());
17765 10 : CHECK(!GetPromise("q1")->HasHandler());
17766 5 : CHECK_EQ(0, promise_reject_counter);
17767 5 : CHECK_EQ(0, promise_revoke_counter);
17768 :
17769 : // Add a new reject handler, which rejects by returning Promise.reject().
17770 : // The returned promise q_ triggers a reject callback at first, only to
17771 : // revoke it when returning it causes q2 to be rejected.
17772 : CompileRun(
17773 : "var q_;"
17774 : "var q2 = q0.catch( \n"
17775 : " function() { \n"
17776 : " q_ = Promise.reject('qqq'); \n"
17777 : " return q_; \n"
17778 : " } \n"
17779 : "); \n");
17780 10 : CHECK(GetPromise("q0")->HasHandler());
17781 10 : CHECK(!GetPromise("q1")->HasHandler());
17782 10 : CHECK(!GetPromise("q2")->HasHandler());
17783 10 : CHECK(GetPromise("q_")->HasHandler());
17784 5 : CHECK_EQ(2, promise_reject_counter);
17785 5 : CHECK_EQ(1, promise_revoke_counter);
17786 20 : CHECK(
17787 : GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17788 20 : CHECK(
17789 : GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17790 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17791 :
17792 : // Add a reject handler to the resolved q1, which rejects by throwing.
17793 : CompileRun(
17794 : "var q3 = q1.then( \n"
17795 : " function() { \n"
17796 : " throw 'qqqq'; \n"
17797 : " } \n"
17798 : "); \n");
17799 10 : CHECK(GetPromise("q0")->HasHandler());
17800 10 : CHECK(GetPromise("q1")->HasHandler());
17801 10 : CHECK(!GetPromise("q2")->HasHandler());
17802 10 : CHECK(!GetPromise("q3")->HasHandler());
17803 5 : CHECK_EQ(3, promise_reject_counter);
17804 5 : CHECK_EQ(1, promise_revoke_counter);
17805 20 : CHECK(
17806 : GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17807 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17808 :
17809 5 : ResetPromiseStates();
17810 :
17811 : // Create promise r0, which has three handlers, two of which handle rejects.
17812 : CompileRun(
17813 : "var r0 = new Promise( \n"
17814 : " function(res, rej) { \n"
17815 : " reject = rej; \n"
17816 : " } \n"
17817 : "); \n"
17818 : "var r1 = r0.catch(function() {}); \n"
17819 : "var r2 = r0.then(function() {}); \n"
17820 : "var r3 = r0.then(function() {}, \n"
17821 : " function() {}); \n");
17822 10 : CHECK(GetPromise("r0")->HasHandler());
17823 10 : CHECK(!GetPromise("r1")->HasHandler());
17824 10 : CHECK(!GetPromise("r2")->HasHandler());
17825 10 : CHECK(!GetPromise("r3")->HasHandler());
17826 5 : CHECK_EQ(0, promise_reject_counter);
17827 5 : CHECK_EQ(0, promise_revoke_counter);
17828 :
17829 : // Reject r0.
17830 : CompileRun("reject('rrr')");
17831 10 : CHECK(GetPromise("r0")->HasHandler());
17832 10 : CHECK(!GetPromise("r1")->HasHandler());
17833 10 : CHECK(!GetPromise("r2")->HasHandler());
17834 10 : CHECK(!GetPromise("r3")->HasHandler());
17835 5 : CHECK_EQ(1, promise_reject_counter);
17836 5 : CHECK_EQ(0, promise_revoke_counter);
17837 20 : CHECK(
17838 : GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17839 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17840 :
17841 : // Add reject handler to r2.
17842 : CompileRun("var r4 = r2.catch(function() {});");
17843 10 : CHECK(GetPromise("r0")->HasHandler());
17844 10 : CHECK(!GetPromise("r1")->HasHandler());
17845 10 : CHECK(GetPromise("r2")->HasHandler());
17846 10 : CHECK(!GetPromise("r3")->HasHandler());
17847 10 : CHECK(!GetPromise("r4")->HasHandler());
17848 5 : CHECK_EQ(1, promise_reject_counter);
17849 5 : CHECK_EQ(1, promise_revoke_counter);
17850 20 : CHECK(
17851 : GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17852 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17853 :
17854 : // Add reject handlers to r4.
17855 : CompileRun("var r5 = r4.then(function() {}, function() {});");
17856 10 : CHECK(GetPromise("r0")->HasHandler());
17857 10 : CHECK(!GetPromise("r1")->HasHandler());
17858 10 : CHECK(GetPromise("r2")->HasHandler());
17859 10 : CHECK(!GetPromise("r3")->HasHandler());
17860 10 : CHECK(GetPromise("r4")->HasHandler());
17861 10 : CHECK(!GetPromise("r5")->HasHandler());
17862 5 : CHECK_EQ(1, promise_reject_counter);
17863 5 : CHECK_EQ(1, promise_revoke_counter);
17864 :
17865 5 : ResetPromiseStates();
17866 :
17867 : // Create promise s0, which has three handlers, none of which handle rejects.
17868 : CompileRun(
17869 : "var s0 = new Promise( \n"
17870 : " function(res, rej) { \n"
17871 : " reject = rej; \n"
17872 : " } \n"
17873 : "); \n"
17874 : "var s1 = s0.then(function() {}); \n"
17875 : "var s2 = s0.then(function() {}); \n"
17876 : "var s3 = s0.then(function() {}); \n");
17877 10 : CHECK(GetPromise("s0")->HasHandler());
17878 10 : CHECK(!GetPromise("s1")->HasHandler());
17879 10 : CHECK(!GetPromise("s2")->HasHandler());
17880 10 : CHECK(!GetPromise("s3")->HasHandler());
17881 5 : CHECK_EQ(0, promise_reject_counter);
17882 5 : CHECK_EQ(0, promise_revoke_counter);
17883 :
17884 : // Reject s0.
17885 : CompileRun("reject('sss')");
17886 10 : CHECK(GetPromise("s0")->HasHandler());
17887 10 : CHECK(!GetPromise("s1")->HasHandler());
17888 10 : CHECK(!GetPromise("s2")->HasHandler());
17889 10 : CHECK(!GetPromise("s3")->HasHandler());
17890 5 : CHECK_EQ(3, promise_reject_counter);
17891 5 : CHECK_EQ(0, promise_revoke_counter);
17892 20 : CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17893 :
17894 : // Test stack frames.
17895 5 : env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
17896 :
17897 5 : ResetPromiseStates();
17898 :
17899 : // Create promise t0, which is rejected in the constructor with an error.
17900 : CompileRunWithOrigin(
17901 : "var t0 = new Promise( \n"
17902 : " function(res, rej) { \n"
17903 : " reference_error; \n"
17904 : " } \n"
17905 : "); \n",
17906 5 : "pro", 0, 0);
17907 10 : CHECK(!GetPromise("t0")->HasHandler());
17908 5 : CHECK_EQ(1, promise_reject_counter);
17909 5 : CHECK_EQ(0, promise_revoke_counter);
17910 5 : CHECK_EQ(2, promise_reject_frame_count);
17911 5 : CHECK_EQ(3, promise_reject_line_number);
17912 5 : CHECK_EQ(5, promise_reject_column_number);
17913 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17914 5 : CHECK_EQ(5, promise_reject_msg_column_number);
17915 :
17916 5 : ResetPromiseStates();
17917 :
17918 : // Create promise u0 and chain u1 to it, which is rejected via throw.
17919 : CompileRunWithOrigin(
17920 : "var u0 = Promise.resolve(); \n"
17921 : "var u1 = u0.then( \n"
17922 : " function() { \n"
17923 : " (function() { \n"
17924 : " throw new Error(); \n"
17925 : " })(); \n"
17926 : " } \n"
17927 : " ); \n",
17928 5 : "pro", 0, 0);
17929 10 : CHECK(GetPromise("u0")->HasHandler());
17930 10 : CHECK(!GetPromise("u1")->HasHandler());
17931 5 : CHECK_EQ(1, promise_reject_counter);
17932 5 : CHECK_EQ(0, promise_revoke_counter);
17933 5 : CHECK_EQ(2, promise_reject_frame_count);
17934 5 : CHECK_EQ(5, promise_reject_line_number);
17935 5 : CHECK_EQ(23, promise_reject_column_number);
17936 5 : CHECK_EQ(5, promise_reject_msg_line_number);
17937 5 : CHECK_EQ(23, promise_reject_msg_column_number);
17938 :
17939 : // Throw in u3, which handles u1's rejection.
17940 : CompileRunWithOrigin(
17941 : "function f() { \n"
17942 : " return (function() { \n"
17943 : " return new Error(); \n"
17944 : " })(); \n"
17945 : "} \n"
17946 : "var u2 = Promise.reject(f()); \n"
17947 : "var u3 = u1.catch( \n"
17948 : " function() { \n"
17949 : " return u2; \n"
17950 : " } \n"
17951 : " ); \n",
17952 5 : "pro", 0, 0);
17953 10 : CHECK(GetPromise("u0")->HasHandler());
17954 10 : CHECK(GetPromise("u1")->HasHandler());
17955 10 : CHECK(GetPromise("u2")->HasHandler());
17956 10 : CHECK(!GetPromise("u3")->HasHandler());
17957 5 : CHECK_EQ(3, promise_reject_counter);
17958 5 : CHECK_EQ(2, promise_revoke_counter);
17959 5 : CHECK_EQ(3, promise_reject_frame_count);
17960 5 : CHECK_EQ(3, promise_reject_line_number);
17961 5 : CHECK_EQ(12, promise_reject_column_number);
17962 5 : CHECK_EQ(3, promise_reject_msg_line_number);
17963 5 : CHECK_EQ(12, promise_reject_msg_column_number);
17964 :
17965 5 : ResetPromiseStates();
17966 :
17967 : // Create promise rejected promise v0, which is incorrectly handled by v1
17968 : // via chaining cycle.
17969 : CompileRunWithOrigin(
17970 : "var v0 = Promise.reject(); \n"
17971 : "var v1 = v0.catch( \n"
17972 : " function() { \n"
17973 : " return v1; \n"
17974 : " } \n"
17975 : " ); \n",
17976 5 : "pro", 0, 0);
17977 10 : CHECK(GetPromise("v0")->HasHandler());
17978 10 : CHECK(!GetPromise("v1")->HasHandler());
17979 5 : CHECK_EQ(2, promise_reject_counter);
17980 5 : CHECK_EQ(1, promise_revoke_counter);
17981 5 : CHECK_EQ(0, promise_reject_frame_count);
17982 5 : CHECK_EQ(-1, promise_reject_line_number);
17983 5 : CHECK_EQ(-1, promise_reject_column_number);
17984 :
17985 5 : ResetPromiseStates();
17986 :
17987 : // Create promise t1, which rejects by throwing syntax error from eval.
17988 : CompileRunWithOrigin(
17989 : "var t1 = new Promise( \n"
17990 : " function(res, rej) { \n"
17991 : " var content = '\\n\\\n"
17992 : " }'; \n"
17993 : " eval(content); \n"
17994 : " } \n"
17995 : "); \n",
17996 5 : "pro", 0, 0);
17997 10 : CHECK(!GetPromise("t1")->HasHandler());
17998 5 : CHECK_EQ(1, promise_reject_counter);
17999 5 : CHECK_EQ(0, promise_revoke_counter);
18000 5 : CHECK_EQ(2, promise_reject_frame_count);
18001 5 : CHECK_EQ(5, promise_reject_line_number);
18002 5 : CHECK_EQ(10, promise_reject_column_number);
18003 5 : CHECK_EQ(2, promise_reject_msg_line_number);
18004 10 : CHECK_EQ(7, promise_reject_msg_column_number);
18005 5 : }
18006 :
18007 :
18008 10 : void AnalyzeStackOfEvalWithSourceURL(
18009 50 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18010 10 : v8::HandleScope scope(args.GetIsolate());
18011 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18012 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18013 10 : CHECK_EQ(5, stackTrace->GetFrameCount());
18014 10 : v8::Local<v8::String> url = v8_str("eval_url");
18015 40 : for (int i = 0; i < 3; i++) {
18016 : v8::Local<v8::String> name =
18017 60 : stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18018 30 : CHECK(!name.IsEmpty());
18019 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18020 10 : }
18021 10 : }
18022 :
18023 :
18024 23723 : TEST(SourceURLInStackTrace) {
18025 5 : v8::Isolate* isolate = CcTest::isolate();
18026 5 : v8::HandleScope scope(isolate);
18027 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18028 : templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18029 : v8::FunctionTemplate::New(isolate,
18030 15 : AnalyzeStackOfEvalWithSourceURL));
18031 10 : LocalContext context(0, templ);
18032 :
18033 : const char *source =
18034 : "function outer() {\n"
18035 : "function bar() {\n"
18036 : " AnalyzeStackOfEvalWithSourceURL();\n"
18037 : "}\n"
18038 : "function foo() {\n"
18039 : "\n"
18040 : " bar();\n"
18041 : "}\n"
18042 : "foo();\n"
18043 : "}\n"
18044 : "eval('(' + outer +')()%s');";
18045 :
18046 : i::ScopedVector<char> code(1024);
18047 5 : i::SNPrintF(code, source, "//# sourceURL=eval_url");
18048 5 : CHECK(CompileRun(code.start())->IsUndefined());
18049 5 : i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18050 10 : CHECK(CompileRun(code.start())->IsUndefined());
18051 5 : }
18052 :
18053 :
18054 : static int scriptIdInStack[2];
18055 :
18056 5 : void AnalyzeScriptIdInStack(
18057 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18058 5 : v8::HandleScope scope(args.GetIsolate());
18059 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18060 5 : args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18061 5 : CHECK_EQ(2, stackTrace->GetFrameCount());
18062 10 : for (int i = 0; i < 2; i++) {
18063 20 : scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18064 5 : }
18065 5 : }
18066 :
18067 :
18068 23723 : TEST(ScriptIdInStackTrace) {
18069 5 : v8::Isolate* isolate = CcTest::isolate();
18070 5 : v8::HandleScope scope(isolate);
18071 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18072 : templ->Set(v8_str("AnalyzeScriptIdInStack"),
18073 15 : v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18074 10 : LocalContext context(0, templ);
18075 :
18076 : v8::Local<v8::String> scriptSource = v8_str(
18077 : "function foo() {\n"
18078 : " AnalyzeScriptIdInStack();"
18079 : "}\n"
18080 5 : "foo();\n");
18081 : v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18082 5 : script->Run(context.local()).ToLocalChecked();
18083 15 : for (int i = 0; i < 2; i++) {
18084 10 : CHECK_NE(scriptIdInStack[i], v8::Message::kNoScriptIdInfo);
18085 20 : CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18086 5 : }
18087 5 : }
18088 :
18089 :
18090 10 : void AnalyzeStackOfInlineScriptWithSourceURL(
18091 50 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18092 10 : v8::HandleScope scope(args.GetIsolate());
18093 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18094 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18095 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18096 10 : v8::Local<v8::String> url = v8_str("source_url");
18097 40 : for (int i = 0; i < 3; i++) {
18098 : v8::Local<v8::String> name =
18099 60 : stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18100 30 : CHECK(!name.IsEmpty());
18101 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18102 10 : }
18103 10 : }
18104 :
18105 :
18106 23723 : TEST(InlineScriptWithSourceURLInStackTrace) {
18107 5 : v8::Isolate* isolate = CcTest::isolate();
18108 5 : v8::HandleScope scope(isolate);
18109 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18110 : templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18111 : v8::FunctionTemplate::New(
18112 15 : CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18113 10 : LocalContext context(0, templ);
18114 :
18115 : const char *source =
18116 : "function outer() {\n"
18117 : "function bar() {\n"
18118 : " AnalyzeStackOfInlineScriptWithSourceURL();\n"
18119 : "}\n"
18120 : "function foo() {\n"
18121 : "\n"
18122 : " bar();\n"
18123 : "}\n"
18124 : "foo();\n"
18125 : "}\n"
18126 : "outer()\n%s";
18127 :
18128 : i::ScopedVector<char> code(1024);
18129 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18130 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18131 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18132 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18133 5 : }
18134 :
18135 325 : void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
18136 : CcTest::global()
18137 975 : ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
18138 650 : .FromJust();
18139 325 : }
18140 :
18141 5 : class PromiseHookData {
18142 : public:
18143 : int before_hook_count = 0;
18144 : int after_hook_count = 0;
18145 : int promise_hook_count = 0;
18146 : int parent_promise_count = 0;
18147 : bool check_value = true;
18148 : std::string promise_hook_value;
18149 :
18150 : void Reset() {
18151 40 : before_hook_count = 0;
18152 40 : after_hook_count = 0;
18153 40 : promise_hook_count = 0;
18154 40 : parent_promise_count = 0;
18155 40 : check_value = true;
18156 40 : promise_hook_value = "";
18157 : }
18158 : };
18159 :
18160 : PromiseHookData* promise_hook_data;
18161 :
18162 285 : void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
18163 : v8::Local<v8::Value> parentPromise) {
18164 285 : promise_hook_data->promise_hook_count++;
18165 285 : switch (type) {
18166 : case v8::PromiseHookType::kInit:
18167 100 : SetPromise("init", promise);
18168 :
18169 100 : if (!parentPromise->IsUndefined()) {
18170 40 : promise_hook_data->parent_promise_count++;
18171 40 : SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
18172 : }
18173 :
18174 : break;
18175 : case v8::PromiseHookType::kResolve:
18176 95 : SetPromise("resolve", promise);
18177 95 : break;
18178 : case v8::PromiseHookType::kBefore:
18179 45 : promise_hook_data->before_hook_count++;
18180 45 : CHECK(promise_hook_data->before_hook_count >
18181 : promise_hook_data->after_hook_count);
18182 270 : CHECK(CcTest::global()
18183 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18184 : .ToLocalChecked()
18185 : ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
18186 : .FromJust());
18187 45 : SetPromise("before", promise);
18188 45 : break;
18189 : case v8::PromiseHookType::kAfter:
18190 45 : promise_hook_data->after_hook_count++;
18191 45 : CHECK(promise_hook_data->after_hook_count <=
18192 : promise_hook_data->before_hook_count);
18193 45 : if (promise_hook_data->check_value) {
18194 150 : CHECK(
18195 : CcTest::global()
18196 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18197 : .ToLocalChecked()
18198 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18199 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18200 : .FromJust());
18201 : }
18202 45 : SetPromise("after", promise);
18203 45 : break;
18204 : }
18205 285 : }
18206 :
18207 23723 : TEST(PromiseHook) {
18208 5 : LocalContext env;
18209 5 : v8::Isolate* isolate = env->GetIsolate();
18210 10 : v8::HandleScope scope(isolate);
18211 :
18212 5 : v8::Local<v8::Object> global = CcTest::global();
18213 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
18214 :
18215 10 : promise_hook_data = new PromiseHookData();
18216 5 : isolate->SetPromiseHook(CustomPromiseHook);
18217 :
18218 : // Test that an initialized promise is passed to init. Other hooks
18219 : // can not have un initialized promise.
18220 5 : promise_hook_data->check_value = false;
18221 : CompileRun("var p = new Promise(() => {});");
18222 :
18223 15 : auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18224 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18225 : auto init_promise_obj = v8::Local<v8::Promise>::Cast(init_promise);
18226 5 : CHECK_EQ(init_promise_obj->State(), v8::Promise::PromiseState::kPending);
18227 5 : CHECK(!init_promise_obj->HasHandler());
18228 :
18229 5 : promise_hook_data->Reset();
18230 5 : promise_hook_data->promise_hook_value = "fulfilled";
18231 : const char* source =
18232 : "var resolve, value = ''; \n"
18233 : "var p = new Promise(r => resolve = r); \n";
18234 :
18235 : CompileRun(source);
18236 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18237 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18238 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18239 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18240 :
18241 : CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
18242 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18243 15 : auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18244 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18245 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18246 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18247 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18248 :
18249 : CompileRun("resolve(); \n");
18250 : auto resolve_promise =
18251 15 : global->Get(context, v8_str("resolve")).ToLocalChecked();
18252 15 : auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18253 15 : auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18254 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18255 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18256 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18257 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18258 :
18259 : CompileRun("value = ''; var p2 = p1.then(() => { value = 'fulfilled' }); \n");
18260 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18261 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18262 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18263 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18264 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18265 15 : CHECK(GetPromise("p2")->Equals(env.local(), init_promise).FromJust());
18266 15 : CHECK(GetPromise("p1")->Equals(env.local(), parent_promise).FromJust());
18267 15 : CHECK(GetPromise("p2")->Equals(env.local(), before_promise).FromJust());
18268 15 : CHECK(GetPromise("p2")->Equals(env.local(), after_promise).FromJust());
18269 15 : CHECK(GetPromise("p2")->Equals(env.local(), resolve_promise).FromJust());
18270 5 : CHECK_EQ(10, promise_hook_data->promise_hook_count);
18271 :
18272 : promise_hook_data->Reset();
18273 5 : promise_hook_data->promise_hook_value = "rejected";
18274 : source =
18275 : "var reject, value = ''; \n"
18276 : "var p = new Promise((_, r) => reject = r); \n";
18277 :
18278 : CompileRun(source);
18279 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18280 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18281 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18282 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18283 :
18284 : CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
18285 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18286 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18287 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18288 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18289 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18290 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18291 :
18292 : CompileRun("reject(); \n");
18293 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18294 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18295 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18296 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18297 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18298 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18299 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18300 :
18301 : promise_hook_data->Reset();
18302 5 : promise_hook_data->promise_hook_value = "Promise.resolve";
18303 : source =
18304 : "var value = ''; \n"
18305 : "var p = Promise.resolve('Promise.resolve'); \n";
18306 :
18307 : CompileRun(source);
18308 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18309 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18310 : // init hook and resolve hook
18311 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18312 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18313 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18314 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18315 :
18316 : CompileRun("var p1 = p.then((v) => { value = v; }); \n");
18317 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18318 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18319 15 : parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
18320 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18321 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18322 15 : CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
18323 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18324 15 : CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
18325 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18326 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18327 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18328 5 : CHECK_EQ(1, promise_hook_data->parent_promise_count);
18329 :
18330 : promise_hook_data->Reset();
18331 : source =
18332 : "var resolve, value = ''; \n"
18333 : "var p = new Promise((_, r) => resolve = r); \n";
18334 :
18335 : CompileRun(source);
18336 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18337 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18338 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18339 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18340 :
18341 : CompileRun("resolve(); \n");
18342 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18343 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18344 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18345 :
18346 : promise_hook_data->Reset();
18347 : source =
18348 : "var reject, value = ''; \n"
18349 : "var p = new Promise((_, r) => reject = r); \n";
18350 :
18351 : CompileRun(source);
18352 15 : init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
18353 15 : CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
18354 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18355 5 : CHECK_EQ(0, promise_hook_data->parent_promise_count);
18356 :
18357 : CompileRun("reject(); \n");
18358 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18359 15 : CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
18360 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18361 :
18362 : promise_hook_data->Reset();
18363 : // This test triggers after callbacks right after each other, so
18364 : // lets just check the value at the end.
18365 5 : promise_hook_data->check_value = false;
18366 5 : promise_hook_data->promise_hook_value = "Promise.all";
18367 : source =
18368 : "var resolve, value = ''; \n"
18369 : "var tempPromise = new Promise(r => resolve = r); \n"
18370 : "var p = Promise.all([tempPromise]);\n "
18371 : "var p1 = p.then(v => value = v[0]); \n";
18372 :
18373 : CompileRun(source);
18374 : // 1) init hook (tempPromise)
18375 : // 2) init hook (p)
18376 : // 3) init hook (throwaway Promise in Promise.all, p)
18377 : // 4) init hook (p1, p)
18378 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
18379 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
18380 :
18381 5 : promise_hook_data->promise_hook_value = "Promise.all";
18382 : CompileRun("resolve('Promise.all'); \n");
18383 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18384 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18385 : // 5) resolve hook (tempPromise)
18386 : // 6) resolve hook (throwaway Promise in Promise.all)
18387 : // 6) before hook (throwaway Promise in Promise.all)
18388 : // 7) after hook (throwaway Promise in Promise.all)
18389 : // 8) before hook (p)
18390 : // 9) after hook (p)
18391 : // 10) resolve hook (p1)
18392 : // 11) before hook (p1)
18393 : // 12) after hook (p1)
18394 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18395 30 : CHECK(CcTest::global()
18396 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18397 : .ToLocalChecked()
18398 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18399 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18400 : .FromJust());
18401 :
18402 5 : promise_hook_data->Reset();
18403 : // This test triggers after callbacks right after each other, so
18404 : // lets just check the value at the end.
18405 5 : promise_hook_data->check_value = false;
18406 5 : promise_hook_data->promise_hook_value = "Promise.race";
18407 : source =
18408 : "var resolve, value = ''; \n"
18409 : "var tempPromise = new Promise(r => resolve = r); \n"
18410 : "var p = Promise.race([tempPromise]);\n "
18411 : "var p1 = p.then(v => value = v); \n";
18412 :
18413 : CompileRun(source);
18414 : // 1) init hook (tempPromise)
18415 : // 2) init hook (p)
18416 : // 3) init hook (throwaway Promise in Promise.race, p)
18417 : // 4) init hook (p1, p)
18418 5 : CHECK_EQ(4, promise_hook_data->promise_hook_count);
18419 5 : CHECK_EQ(2, promise_hook_data->parent_promise_count);
18420 :
18421 5 : promise_hook_data->promise_hook_value = "Promise.race";
18422 : CompileRun("resolve('Promise.race'); \n");
18423 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18424 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18425 : // 5) resolve hook (tempPromise)
18426 : // 6) resolve hook (throwaway Promise in Promise.race)
18427 : // 6) before hook (throwaway Promise in Promise.race)
18428 : // 7) after hook (throwaway Promise in Promise.race)
18429 : // 8) before hook (p)
18430 : // 9) after hook (p)
18431 : // 10) resolve hook (p1)
18432 : // 11) before hook (p1)
18433 : // 12) after hook (p1)
18434 5 : CHECK_EQ(12, promise_hook_data->promise_hook_count);
18435 30 : CHECK(CcTest::global()
18436 : ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
18437 : .ToLocalChecked()
18438 : ->Equals(CcTest::isolate()->GetCurrentContext(),
18439 : v8_str(promise_hook_data->promise_hook_value.c_str()))
18440 : .FromJust());
18441 :
18442 5 : promise_hook_data->Reset();
18443 5 : promise_hook_data->promise_hook_value = "subclass";
18444 : source =
18445 : "var resolve, value = '';\n"
18446 : "class MyPromise extends Promise { \n"
18447 : " then(onFulfilled, onRejected) { \n"
18448 : " return super.then(onFulfilled, onRejected); \n"
18449 : " };\n"
18450 : "};\n"
18451 : "var p = new MyPromise(r => resolve = r);\n";
18452 :
18453 : CompileRun(source);
18454 : // 1) init hook (p)
18455 5 : CHECK_EQ(1, promise_hook_data->promise_hook_count);
18456 :
18457 : CompileRun("var p1 = p.then(() => value = 'subclass');\n");
18458 : // 2) init hook (p1)
18459 5 : CHECK_EQ(2, promise_hook_data->promise_hook_count);
18460 :
18461 : CompileRun("resolve();\n");
18462 15 : resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18463 15 : before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18464 15 : after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18465 15 : CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18466 15 : CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18467 15 : CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18468 : // 3) resolve hook (p)
18469 : // 4) before hook (p)
18470 : // 5) after hook (p)
18471 : // 6) resolve hook (p1)
18472 5 : CHECK_EQ(6, promise_hook_data->promise_hook_count);
18473 :
18474 10 : delete promise_hook_data;
18475 10 : isolate->SetPromiseHook(nullptr);
18476 5 : }
18477 :
18478 10 : void AnalyzeStackOfDynamicScriptWithSourceURL(
18479 50 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18480 10 : v8::HandleScope scope(args.GetIsolate());
18481 : v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18482 10 : args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18483 10 : CHECK_EQ(4, stackTrace->GetFrameCount());
18484 10 : v8::Local<v8::String> url = v8_str("source_url");
18485 40 : for (int i = 0; i < 3; i++) {
18486 : v8::Local<v8::String> name =
18487 60 : stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18488 30 : CHECK(!name.IsEmpty());
18489 90 : CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18490 10 : }
18491 10 : }
18492 :
18493 :
18494 23723 : TEST(DynamicWithSourceURLInStackTrace) {
18495 5 : v8::Isolate* isolate = CcTest::isolate();
18496 5 : v8::HandleScope scope(isolate);
18497 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18498 : templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18499 : v8::FunctionTemplate::New(
18500 15 : CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18501 10 : LocalContext context(0, templ);
18502 :
18503 : const char *source =
18504 : "function outer() {\n"
18505 : "function bar() {\n"
18506 : " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18507 : "}\n"
18508 : "function foo() {\n"
18509 : "\n"
18510 : " bar();\n"
18511 : "}\n"
18512 : "foo();\n"
18513 : "}\n"
18514 : "outer()\n%s";
18515 :
18516 : i::ScopedVector<char> code(1024);
18517 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18518 10 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18519 5 : i::SNPrintF(code, source, "//@ sourceURL=source_url");
18520 15 : CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18521 5 : }
18522 :
18523 :
18524 23723 : TEST(DynamicWithSourceURLInStackTraceString) {
18525 5 : LocalContext context;
18526 10 : v8::HandleScope scope(context->GetIsolate());
18527 :
18528 : const char *source =
18529 : "function outer() {\n"
18530 : " function foo() {\n"
18531 : " FAIL.FAIL;\n"
18532 : " }\n"
18533 : " foo();\n"
18534 : "}\n"
18535 : "outer()\n%s";
18536 :
18537 : i::ScopedVector<char> code(1024);
18538 5 : i::SNPrintF(code, source, "//# sourceURL=source_url");
18539 10 : v8::TryCatch try_catch(context->GetIsolate());
18540 5 : CompileRunWithOrigin(code.start(), "", 0, 0);
18541 5 : CHECK(try_catch.HasCaught());
18542 : v8::String::Utf8Value stack(
18543 : context->GetIsolate(),
18544 15 : try_catch.StackTrace(context.local()).ToLocalChecked());
18545 15 : CHECK_NOT_NULL(strstr(*stack, "at foo (source_url:3:5)"));
18546 5 : }
18547 :
18548 :
18549 23723 : TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18550 5 : LocalContext context;
18551 10 : v8::HandleScope scope(context->GetIsolate());
18552 :
18553 : const char *source =
18554 : "function outer() {\n"
18555 : " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18556 : " //# sourceURL=source_url\";\n"
18557 : " eval(scriptContents);\n"
18558 : " foo(); }\n"
18559 : "outer();\n"
18560 : "//# sourceURL=outer_url";
18561 :
18562 10 : v8::TryCatch try_catch(context->GetIsolate());
18563 : CompileRun(source);
18564 5 : CHECK(try_catch.HasCaught());
18565 :
18566 5 : Local<v8::Message> message = try_catch.Message();
18567 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18568 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18569 5 : "source_url"));
18570 5 : }
18571 :
18572 :
18573 23723 : TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18574 5 : LocalContext context;
18575 10 : v8::HandleScope scope(context->GetIsolate());
18576 :
18577 : const char *source =
18578 : "function outer() {\n"
18579 : " var scriptContents = \"function boo(){ boo(); }\\\n"
18580 : " //# sourceURL=source_url\";\n"
18581 : " eval(scriptContents);\n"
18582 : " boo(); }\n"
18583 : "outer();\n"
18584 : "//# sourceURL=outer_url";
18585 :
18586 10 : v8::TryCatch try_catch(context->GetIsolate());
18587 : CompileRun(source);
18588 5 : CHECK(try_catch.HasCaught());
18589 :
18590 5 : Local<v8::Message> message = try_catch.Message();
18591 5 : Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18592 5 : CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18593 5 : "source_url"));
18594 5 : }
18595 :
18596 :
18597 5 : static void CreateGarbageInOldSpace() {
18598 : i::Factory* factory = CcTest::i_isolate()->factory();
18599 5 : v8::HandleScope scope(CcTest::isolate());
18600 : i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18601 5005 : for (int i = 0; i < 1000; i++) {
18602 5000 : factory->NewFixedArray(1000, i::TENURED);
18603 5 : }
18604 5 : }
18605 :
18606 :
18607 : // Test that idle notification can be handled and eventually collects garbage.
18608 23723 : TEST(TestIdleNotification) {
18609 5 : if (!i::FLAG_incremental_marking) return;
18610 : ManualGCScope manual_gc_scope;
18611 : const intptr_t MB = 1024 * 1024;
18612 : const double IdlePauseInSeconds = 1.0;
18613 10 : LocalContext env;
18614 10 : v8::HandleScope scope(env->GetIsolate());
18615 5 : intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18616 5 : CreateGarbageInOldSpace();
18617 5 : intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18618 5 : CHECK_GT(size_with_garbage, initial_size + MB);
18619 : bool finished = false;
18620 10 : for (int i = 0; i < 200 && !finished; i++) {
18621 20 : if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
18622 : CcTest::heap()->StartIdleIncrementalMarking(
18623 5 : i::GarbageCollectionReason::kTesting);
18624 : }
18625 : finished = env->GetIsolate()->IdleNotificationDeadline(
18626 30 : (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
18627 : static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
18628 20 : IdlePauseInSeconds);
18629 20 : if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
18630 5 : CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
18631 : }
18632 : }
18633 5 : intptr_t final_size = CcTest::heap()->SizeOfObjects();
18634 5 : CHECK(finished);
18635 5 : CHECK_LT(final_size, initial_size + 1);
18636 : }
18637 :
18638 :
18639 23723 : TEST(Regress2333) {
18640 5 : LocalContext env;
18641 20 : for (int i = 0; i < 3; i++) {
18642 15 : CcTest::CollectGarbage(i::NEW_SPACE);
18643 5 : }
18644 5 : }
18645 :
18646 : static uint32_t* stack_limit;
18647 :
18648 10 : static void GetStackLimitCallback(
18649 : const v8::FunctionCallbackInfo<v8::Value>& args) {
18650 : stack_limit = reinterpret_cast<uint32_t*>(
18651 10 : CcTest::i_isolate()->stack_guard()->real_climit());
18652 10 : }
18653 :
18654 :
18655 : // Uses the address of a local variable to determine the stack top now.
18656 : // Given a size, returns an address that is that far from the current
18657 : // top of stack.
18658 : static uint32_t* ComputeStackLimit(uint32_t size) {
18659 : uint32_t* answer = &size - (size / sizeof(size));
18660 : // If the size is very large and the stack is very near the bottom of
18661 : // memory then the calculation above may wrap around and give an address
18662 : // that is above the (downwards-growing) stack. In that case we return
18663 : // a very low address.
18664 : if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18665 : return answer;
18666 : }
18667 :
18668 :
18669 : // We need at least 165kB for an x64 debug build with clang and ASAN.
18670 : static const int stack_breathing_room = 256 * i::KB;
18671 :
18672 :
18673 23723 : TEST(SetStackLimit) {
18674 : uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18675 :
18676 : // Set stack limit.
18677 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18678 :
18679 : // Execute a script.
18680 5 : LocalContext env;
18681 10 : v8::HandleScope scope(env->GetIsolate());
18682 : Local<v8::FunctionTemplate> fun_templ =
18683 5 : v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18684 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18685 25 : CHECK(env->Global()
18686 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18687 : .FromJust());
18688 : CompileRun("get_stack_limit();");
18689 :
18690 10 : CHECK(stack_limit == set_limit);
18691 5 : }
18692 :
18693 :
18694 23723 : TEST(SetStackLimitInThread) {
18695 : uint32_t* set_limit;
18696 : {
18697 5 : v8::Locker locker(CcTest::isolate());
18698 : set_limit = ComputeStackLimit(stack_breathing_room);
18699 :
18700 : // Set stack limit.
18701 5 : CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18702 :
18703 : // Execute a script.
18704 10 : v8::HandleScope scope(CcTest::isolate());
18705 10 : LocalContext env;
18706 : Local<v8::FunctionTemplate> fun_templ =
18707 5 : v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18708 10 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18709 25 : CHECK(env->Global()
18710 : ->Set(env.local(), v8_str("get_stack_limit"), fun)
18711 : .FromJust());
18712 : CompileRun("get_stack_limit();");
18713 :
18714 10 : CHECK(stack_limit == set_limit);
18715 : }
18716 : {
18717 5 : v8::Locker locker(CcTest::isolate());
18718 5 : CHECK(stack_limit == set_limit);
18719 : }
18720 5 : }
18721 :
18722 :
18723 23724 : THREADED_TEST(GetHeapStatistics) {
18724 6 : LocalContext c1;
18725 12 : v8::HandleScope scope(c1->GetIsolate());
18726 6 : v8::HeapStatistics heap_statistics;
18727 6 : CHECK_EQ(0u, heap_statistics.total_heap_size());
18728 6 : CHECK_EQ(0u, heap_statistics.used_heap_size());
18729 6 : c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18730 6 : CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18731 12 : CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18732 6 : }
18733 :
18734 :
18735 : class VisitorImpl : public v8::ExternalResourceVisitor {
18736 : public:
18737 5 : explicit VisitorImpl(TestResource** resource) {
18738 20 : for (int i = 0; i < 4; i++) {
18739 20 : resource_[i] = resource[i];
18740 20 : found_resource_[i] = false;
18741 : }
18742 : }
18743 5 : virtual ~VisitorImpl() {}
18744 70 : virtual void VisitExternalString(v8::Local<v8::String> string) {
18745 70 : if (!string->IsExternal()) {
18746 50 : CHECK(string->IsExternalOneByte());
18747 70 : return;
18748 : }
18749 : v8::String::ExternalStringResource* resource =
18750 : string->GetExternalStringResource();
18751 20 : CHECK(resource);
18752 80 : for (int i = 0; i < 4; i++) {
18753 80 : if (resource_[i] == resource) {
18754 20 : CHECK(!found_resource_[i]);
18755 20 : found_resource_[i] = true;
18756 : }
18757 : }
18758 : }
18759 5 : void CheckVisitedResources() {
18760 25 : for (int i = 0; i < 4; i++) {
18761 20 : CHECK(found_resource_[i]);
18762 : }
18763 5 : }
18764 :
18765 : private:
18766 : v8::String::ExternalStringResource* resource_[4];
18767 : bool found_resource_[4];
18768 : };
18769 :
18770 :
18771 23723 : TEST(ExternalizeOldSpaceTwoByteCons) {
18772 5 : v8::Isolate* isolate = CcTest::isolate();
18773 5 : LocalContext env;
18774 10 : v8::HandleScope scope(isolate);
18775 : v8::Local<v8::String> cons =
18776 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18777 5 : ->ToString(env.local())
18778 5 : .ToLocalChecked();
18779 5 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18780 5 : CcTest::CollectAllAvailableGarbage();
18781 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18782 :
18783 : TestResource* resource = new TestResource(
18784 5 : AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18785 5 : cons->MakeExternal(resource);
18786 :
18787 5 : CHECK(cons->IsExternal());
18788 5 : CHECK_EQ(resource, cons->GetExternalStringResource());
18789 : String::Encoding encoding;
18790 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18791 10 : CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18792 5 : }
18793 :
18794 :
18795 23723 : TEST(ExternalizeOldSpaceOneByteCons) {
18796 5 : v8::Isolate* isolate = CcTest::isolate();
18797 5 : LocalContext env;
18798 10 : v8::HandleScope scope(isolate);
18799 : v8::Local<v8::String> cons =
18800 : CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18801 5 : ->ToString(env.local())
18802 5 : .ToLocalChecked();
18803 5 : CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18804 5 : CcTest::CollectAllAvailableGarbage();
18805 5 : CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18806 :
18807 : TestOneByteResource* resource =
18808 5 : new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18809 5 : cons->MakeExternal(resource);
18810 :
18811 5 : CHECK(cons->IsExternalOneByte());
18812 5 : CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18813 : String::Encoding encoding;
18814 5 : CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18815 10 : CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18816 5 : }
18817 :
18818 :
18819 23723 : TEST(VisitExternalStrings) {
18820 5 : v8::Isolate* isolate = CcTest::isolate();
18821 5 : LocalContext env;
18822 10 : v8::HandleScope scope(isolate);
18823 : const char* string = "Some string";
18824 5 : uint16_t* two_byte_string = AsciiToTwoByteString(string);
18825 : TestResource* resource[4];
18826 10 : resource[0] = new TestResource(two_byte_string);
18827 : v8::Local<v8::String> string0 =
18828 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
18829 5 : .ToLocalChecked();
18830 10 : resource[1] = new TestResource(two_byte_string, nullptr, false);
18831 : v8::Local<v8::String> string1 =
18832 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
18833 5 : .ToLocalChecked();
18834 :
18835 : // Externalized symbol.
18836 10 : resource[2] = new TestResource(two_byte_string, nullptr, false);
18837 : v8::Local<v8::String> string2 =
18838 : v8::String::NewFromUtf8(env->GetIsolate(), string,
18839 5 : v8::NewStringType::kInternalized)
18840 5 : .ToLocalChecked();
18841 5 : CHECK(string2->MakeExternal(resource[2]));
18842 :
18843 : // Symbolized External.
18844 10 : resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18845 : v8::Local<v8::String> string3 =
18846 5 : v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
18847 5 : .ToLocalChecked();
18848 5 : CcTest::CollectAllAvailableGarbage(); // Tenure string.
18849 : // Turn into a symbol.
18850 : i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18851 10 : CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18852 : string3_i).is_null());
18853 5 : CHECK(string3_i->IsInternalizedString());
18854 :
18855 : // We need to add usages for string* to avoid warnings in GCC 4.7
18856 5 : CHECK(string0->IsExternal());
18857 5 : CHECK(string1->IsExternal());
18858 5 : CHECK(string2->IsExternal());
18859 5 : CHECK(string3->IsExternal());
18860 :
18861 : VisitorImpl visitor(resource);
18862 5 : isolate->VisitExternalResources(&visitor);
18863 10 : visitor.CheckVisitedResources();
18864 5 : }
18865 :
18866 :
18867 23723 : TEST(ExternalStringCollectedAtTearDown) {
18868 5 : int destroyed = 0;
18869 : v8::Isolate::CreateParams create_params;
18870 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18871 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18872 : { v8::Isolate::Scope isolate_scope(isolate);
18873 10 : v8::HandleScope handle_scope(isolate);
18874 : const char* s = "One string to test them all, one string to find them.";
18875 : TestOneByteResource* inscription =
18876 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18877 : v8::Local<v8::String> ring =
18878 5 : v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
18879 : // Ring is still alive. Orcs are roaming freely across our lands.
18880 5 : CHECK_EQ(0, destroyed);
18881 : USE(ring);
18882 : }
18883 :
18884 5 : isolate->Dispose();
18885 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18886 5 : CHECK_EQ(1, destroyed);
18887 5 : }
18888 :
18889 :
18890 23723 : TEST(ExternalInternalizedStringCollectedAtTearDown) {
18891 5 : int destroyed = 0;
18892 : v8::Isolate::CreateParams create_params;
18893 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18894 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
18895 : { v8::Isolate::Scope isolate_scope(isolate);
18896 5 : LocalContext env(isolate);
18897 10 : v8::HandleScope handle_scope(isolate);
18898 : CompileRun("var ring = 'One string to test them all';");
18899 : const char* s = "One string to test them all";
18900 : TestOneByteResource* inscription =
18901 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18902 : v8::Local<v8::String> ring =
18903 10 : CompileRun("ring")->ToString(env.local()).ToLocalChecked();
18904 5 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18905 5 : ring->MakeExternal(inscription);
18906 : // Ring is still alive. Orcs are roaming freely across our lands.
18907 5 : CHECK_EQ(0, destroyed);
18908 : USE(ring);
18909 : }
18910 :
18911 5 : isolate->Dispose();
18912 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18913 5 : CHECK_EQ(1, destroyed);
18914 5 : }
18915 :
18916 :
18917 23723 : TEST(ExternalInternalizedStringCollectedAtGC) {
18918 5 : int destroyed = 0;
18919 5 : { LocalContext env;
18920 10 : v8::HandleScope handle_scope(env->GetIsolate());
18921 : CompileRun("var ring = 'One string to test them all';");
18922 : const char* s = "One string to test them all";
18923 : TestOneByteResource* inscription =
18924 5 : new TestOneByteResource(i::StrDup(s), &destroyed);
18925 : v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
18926 5 : CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18927 5 : ring->MakeExternal(inscription);
18928 : // Ring is still alive. Orcs are roaming freely across our lands.
18929 5 : CHECK_EQ(0, destroyed);
18930 5 : USE(ring);
18931 : }
18932 :
18933 : // Garbage collector deals swift blows to evil.
18934 5 : CcTest::i_isolate()->compilation_cache()->Clear();
18935 5 : CcTest::CollectAllAvailableGarbage();
18936 :
18937 : // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18938 5 : CHECK_EQ(1, destroyed);
18939 5 : }
18940 :
18941 :
18942 : static double DoubleFromBits(uint64_t value) {
18943 : double target;
18944 : i::MemCopy(&target, &value, sizeof(target));
18945 : return target;
18946 : }
18947 :
18948 :
18949 : static uint64_t DoubleToBits(double value) {
18950 : uint64_t target;
18951 : i::MemCopy(&target, &value, sizeof(target));
18952 : return target;
18953 : }
18954 :
18955 :
18956 120 : static double DoubleToDateTime(double input) {
18957 : double date_limit = 864e13;
18958 120 : if (std::isnan(input) || input < -date_limit || input > date_limit) {
18959 : return std::numeric_limits<double>::quiet_NaN();
18960 : }
18961 60 : return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18962 : }
18963 :
18964 :
18965 : // We don't have a consistent way to write 64-bit constants syntactically, so we
18966 : // split them into two 32-bit constants and combine them programmatically.
18967 : static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18968 : return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18969 : }
18970 :
18971 :
18972 23724 : THREADED_TEST(QuietSignalingNaNs) {
18973 6 : LocalContext context;
18974 6 : v8::Isolate* isolate = context->GetIsolate();
18975 12 : v8::HandleScope scope(isolate);
18976 12 : v8::TryCatch try_catch(isolate);
18977 :
18978 : // Special double values.
18979 : double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18980 : double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18981 : double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18982 : double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18983 : double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18984 : double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18985 : double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18986 :
18987 : // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18988 : // on either side of the epoch.
18989 : double date_limit = 864e13;
18990 :
18991 : double test_values[] = {
18992 : snan,
18993 : qnan,
18994 : infinity,
18995 : max_normal,
18996 : date_limit + 1,
18997 : date_limit,
18998 : min_normal,
18999 : max_denormal,
19000 : min_denormal,
19001 : 0,
19002 : -0,
19003 : -min_denormal,
19004 : -max_denormal,
19005 : -min_normal,
19006 : -date_limit,
19007 : -date_limit - 1,
19008 : -max_normal,
19009 : -infinity,
19010 : -qnan,
19011 : -snan
19012 6 : };
19013 : int num_test_values = 20;
19014 :
19015 126 : for (int i = 0; i < num_test_values; i++) {
19016 120 : double test_value = test_values[i];
19017 :
19018 : // Check that Number::New preserves non-NaNs and quiets SNaNs.
19019 120 : v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
19020 240 : double stored_number = number->NumberValue(context.local()).FromJust();
19021 120 : if (!std::isnan(test_value)) {
19022 96 : CHECK_EQ(test_value, stored_number);
19023 : } else {
19024 : uint64_t stored_bits = DoubleToBits(stored_number);
19025 : // Check if quiet nan (bits 51..62 all set).
19026 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19027 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
19028 : !defined(USE_SIMULATOR)
19029 : // Most significant fraction bit for quiet nan is set to 0
19030 : // on MIPS architecture. Allowed by IEEE-754.
19031 : CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19032 : #else
19033 24 : CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19034 : #endif
19035 : }
19036 :
19037 : // Check that Date::New preserves non-NaNs in the date range and
19038 : // quiets SNaNs.
19039 : v8::Local<v8::Value> date =
19040 120 : v8::Date::New(context.local(), test_value).ToLocalChecked();
19041 120 : double expected_stored_date = DoubleToDateTime(test_value);
19042 240 : double stored_date = date->NumberValue(context.local()).FromJust();
19043 120 : if (!std::isnan(expected_stored_date)) {
19044 60 : CHECK_EQ(expected_stored_date, stored_date);
19045 : } else {
19046 : uint64_t stored_bits = DoubleToBits(stored_date);
19047 : // Check if quiet nan (bits 51..62 all set).
19048 : #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19049 : !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
19050 : !defined(USE_SIMULATOR)
19051 : // Most significant fraction bit for quiet nan is set to 0
19052 : // on MIPS architecture. Allowed by IEEE-754.
19053 : CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19054 : #else
19055 60 : CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19056 : #endif
19057 : }
19058 6 : }
19059 6 : }
19060 :
19061 :
19062 66 : static void SpaghettiIncident(
19063 198 : const v8::FunctionCallbackInfo<v8::Value>& args) {
19064 66 : v8::HandleScope scope(args.GetIsolate());
19065 132 : v8::TryCatch tc(args.GetIsolate());
19066 : v8::MaybeLocal<v8::String> str(
19067 132 : args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
19068 : USE(str);
19069 66 : if (tc.HasCaught())
19070 132 : tc.ReThrow();
19071 66 : }
19072 :
19073 :
19074 : // Test that an exception can be propagated down through a spaghetti
19075 : // stack using ReThrow.
19076 23724 : THREADED_TEST(SpaghettiStackReThrow) {
19077 6 : v8::Isolate* isolate = CcTest::isolate();
19078 6 : v8::HandleScope scope(isolate);
19079 12 : LocalContext context;
19080 : context->Global()
19081 : ->Set(context.local(), v8_str("s"),
19082 6 : v8::FunctionTemplate::New(isolate, SpaghettiIncident)
19083 18 : ->GetFunction(context.local())
19084 30 : .ToLocalChecked())
19085 12 : .FromJust();
19086 12 : v8::TryCatch try_catch(isolate);
19087 : CompileRun(
19088 : "var i = 0;"
19089 : "var o = {"
19090 : " toString: function () {"
19091 : " if (i == 10) {"
19092 : " throw 'Hey!';"
19093 : " } else {"
19094 : " i++;"
19095 : " return s(o);"
19096 : " }"
19097 : " }"
19098 : "};"
19099 : "s(o);");
19100 6 : CHECK(try_catch.HasCaught());
19101 12 : v8::String::Utf8Value value(isolate, try_catch.Exception());
19102 12 : CHECK_EQ(0, strcmp(*value, "Hey!"));
19103 6 : }
19104 :
19105 :
19106 23723 : TEST(Regress528) {
19107 : ManualGCScope manual_gc_scope;
19108 5 : v8::V8::Initialize();
19109 5 : v8::Isolate* isolate = CcTest::isolate();
19110 5 : i::FLAG_retain_maps_for_n_gc = 0;
19111 10 : v8::HandleScope scope(isolate);
19112 : v8::Local<Context> other_context;
19113 : int gc_count;
19114 :
19115 : // Create a context used to keep the code from aging in the compilation
19116 : // cache.
19117 5 : other_context = Context::New(isolate);
19118 :
19119 : // Context-dependent context data creates reference from the compilation
19120 : // cache to the global object.
19121 : const char* source_simple = "1";
19122 : {
19123 5 : v8::HandleScope scope(isolate);
19124 5 : v8::Local<Context> context = Context::New(isolate);
19125 :
19126 5 : context->Enter();
19127 5 : Local<v8::String> obj = v8_str("");
19128 5 : context->SetEmbedderData(0, obj);
19129 : CompileRun(source_simple);
19130 5 : context->Exit();
19131 : }
19132 5 : isolate->ContextDisposedNotification();
19133 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19134 5 : other_context->Enter();
19135 : CompileRun(source_simple);
19136 5 : other_context->Exit();
19137 5 : CcTest::CollectAllGarbage();
19138 5 : if (GetGlobalObjectsCount() == 1) break;
19139 : }
19140 5 : CHECK_GE(2, gc_count);
19141 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19142 :
19143 : // Eval in a function creates reference from the compilation cache to the
19144 : // global object.
19145 : const char* source_eval = "function f(){eval('1')}; f()";
19146 : {
19147 5 : v8::HandleScope scope(isolate);
19148 5 : v8::Local<Context> context = Context::New(isolate);
19149 :
19150 5 : context->Enter();
19151 : CompileRun(source_eval);
19152 5 : context->Exit();
19153 : }
19154 5 : isolate->ContextDisposedNotification();
19155 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19156 5 : other_context->Enter();
19157 : CompileRun(source_eval);
19158 5 : other_context->Exit();
19159 5 : CcTest::CollectAllGarbage();
19160 5 : if (GetGlobalObjectsCount() == 1) break;
19161 : }
19162 5 : CHECK_GE(2, gc_count);
19163 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19164 :
19165 : // Looking up the line number for an exception creates reference from the
19166 : // compilation cache to the global object.
19167 : const char* source_exception = "function f(){throw 1;} f()";
19168 : {
19169 5 : v8::HandleScope scope(isolate);
19170 5 : v8::Local<Context> context = Context::New(isolate);
19171 :
19172 5 : context->Enter();
19173 10 : v8::TryCatch try_catch(isolate);
19174 : CompileRun(source_exception);
19175 5 : CHECK(try_catch.HasCaught());
19176 5 : v8::Local<v8::Message> message = try_catch.Message();
19177 5 : CHECK(!message.IsEmpty());
19178 10 : CHECK_EQ(1, message->GetLineNumber(context).FromJust());
19179 10 : context->Exit();
19180 : }
19181 5 : isolate->ContextDisposedNotification();
19182 5 : for (gc_count = 1; gc_count < 10; gc_count++) {
19183 5 : other_context->Enter();
19184 : CompileRun(source_exception);
19185 5 : other_context->Exit();
19186 5 : CcTest::CollectAllGarbage();
19187 5 : if (GetGlobalObjectsCount() == 1) break;
19188 : }
19189 5 : CHECK_GE(2, gc_count);
19190 5 : CHECK_EQ(1, GetGlobalObjectsCount());
19191 :
19192 5 : isolate->ContextDisposedNotification();
19193 5 : }
19194 :
19195 :
19196 23724 : THREADED_TEST(ScriptOrigin) {
19197 6 : LocalContext env;
19198 6 : v8::Isolate* isolate = env->GetIsolate();
19199 12 : v8::HandleScope scope(isolate);
19200 6 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 1));
19201 6 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
19202 6 : array->Set(0, symbol);
19203 :
19204 : v8::ScriptOrigin origin = v8::ScriptOrigin(
19205 : v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
19206 : v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
19207 : v8::Local<v8::Integer>(), v8_str("http://sourceMapUrl"),
19208 : v8::True(env->GetIsolate()), v8::False(env->GetIsolate()),
19209 42 : v8::False(env->GetIsolate()), array);
19210 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19211 6 : v8::Script::Compile(env.local(), script, &origin)
19212 6 : .ToLocalChecked()
19213 6 : ->Run(env.local())
19214 6 : .ToLocalChecked();
19215 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19216 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19217 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19218 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19219 :
19220 6 : v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19221 6 : CHECK_EQ(0, strcmp("test",
19222 : *v8::String::Utf8Value(env->GetIsolate(),
19223 : script_origin_f.ResourceName())));
19224 12 : CHECK_EQ(
19225 : 1,
19226 : script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
19227 6 : CHECK(script_origin_f.Options().IsSharedCrossOrigin());
19228 6 : CHECK(script_origin_f.Options().IsOpaque());
19229 6 : printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
19230 12 : CHECK(script_origin_f.HostDefinedOptions()->Get(0)->IsSymbol());
19231 :
19232 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
19233 : *v8::String::Utf8Value(env->GetIsolate(),
19234 : script_origin_f.SourceMapUrl())));
19235 :
19236 6 : v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19237 6 : CHECK_EQ(0, strcmp("test",
19238 : *v8::String::Utf8Value(env->GetIsolate(),
19239 : script_origin_g.ResourceName())));
19240 12 : CHECK_EQ(
19241 : 1,
19242 : script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
19243 6 : CHECK(script_origin_g.Options().IsSharedCrossOrigin());
19244 6 : CHECK(script_origin_g.Options().IsOpaque());
19245 6 : CHECK_EQ(0, strcmp("http://sourceMapUrl",
19246 : *v8::String::Utf8Value(env->GetIsolate(),
19247 : script_origin_g.SourceMapUrl())));
19248 18 : CHECK(script_origin_g.HostDefinedOptions()->Get(0)->IsSymbol());
19249 6 : }
19250 :
19251 :
19252 23724 : THREADED_TEST(FunctionGetInferredName) {
19253 6 : LocalContext env;
19254 12 : v8::HandleScope scope(env->GetIsolate());
19255 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19256 : v8::Local<v8::String> script =
19257 6 : v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19258 6 : v8::Script::Compile(env.local(), script, &origin)
19259 6 : .ToLocalChecked()
19260 6 : ->Run(env.local())
19261 6 : .ToLocalChecked();
19262 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19263 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19264 12 : CHECK_EQ(0,
19265 : strcmp("foo.bar.baz", *v8::String::Utf8Value(env->GetIsolate(),
19266 6 : f->GetInferredName())));
19267 6 : }
19268 :
19269 :
19270 23724 : THREADED_TEST(FunctionGetDebugName) {
19271 6 : LocalContext env;
19272 12 : v8::HandleScope scope(env->GetIsolate());
19273 : const char* code =
19274 : "var error = false;"
19275 : "function a() { this.x = 1; };"
19276 : "a.displayName = 'display_a';"
19277 : "var b = (function() {"
19278 : " var f = function() { this.x = 2; };"
19279 : " f.displayName = 'display_b';"
19280 : " return f;"
19281 : "})();"
19282 : "var c = function() {};"
19283 : "c.__defineGetter__('displayName', function() {"
19284 : " error = true;"
19285 : " throw new Error();"
19286 : "});"
19287 : "function d() {};"
19288 : "d.__defineGetter__('displayName', function() {"
19289 : " error = true;"
19290 : " return 'wrong_display_name';"
19291 : "});"
19292 : "function e() {};"
19293 : "e.displayName = 'wrong_display_name';"
19294 : "e.__defineSetter__('displayName', function() {"
19295 : " error = true;"
19296 : " throw new Error();"
19297 : "});"
19298 : "function f() {};"
19299 : "f.displayName = { 'foo': 6, toString: function() {"
19300 : " error = true;"
19301 : " return 'wrong_display_name';"
19302 : "}};"
19303 : "var g = function() {"
19304 : " arguments.callee.displayName = 'set_in_runtime';"
19305 : "}; g();"
19306 : "var h = function() {};"
19307 : "h.displayName = 'displayName';"
19308 : "Object.defineProperty(h, 'name', { value: 'function.name' });"
19309 : "var i = function() {};"
19310 : "i.displayName = 239;"
19311 : "Object.defineProperty(i, 'name', { value: 'function.name' });"
19312 : "var j = function() {};"
19313 : "Object.defineProperty(j, 'name', { value: 'function.name' });"
19314 : "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
19315 : "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
19316 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19317 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19318 6 : .ToLocalChecked()
19319 6 : ->Run(env.local())
19320 6 : .ToLocalChecked();
19321 : v8::Local<v8::Value> error =
19322 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19323 12 : CHECK(!error->BooleanValue(env.local()).FromJust());
19324 : const char* functions[] = {"a", "display_a",
19325 : "b", "display_b",
19326 : "c", "c",
19327 : "d", "d",
19328 : "e", "e",
19329 : "f", "f",
19330 : "g", "set_in_runtime",
19331 : "h", "displayName",
19332 : "i", "function.name",
19333 : "j", "function.name",
19334 : "k", "foo.bar.baz",
19335 6 : "l", "baz"};
19336 78 : for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
19337 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19338 : env->Global()
19339 : ->Get(env.local(),
19340 72 : v8::String::NewFromUtf8(env->GetIsolate(), functions[i * 2],
19341 144 : v8::NewStringType::kNormal)
19342 288 : .ToLocalChecked())
19343 72 : .ToLocalChecked());
19344 144 : CHECK_EQ(0, strcmp(functions[i * 2 + 1],
19345 : *v8::String::Utf8Value(env->GetIsolate(),
19346 : f->GetDebugName())));
19347 6 : }
19348 6 : }
19349 :
19350 :
19351 23724 : THREADED_TEST(FunctionGetDisplayName) {
19352 6 : LocalContext env;
19353 12 : v8::HandleScope scope(env->GetIsolate());
19354 : const char* code = "var error = false;"
19355 : "function a() { this.x = 1; };"
19356 : "a.displayName = 'display_a';"
19357 : "var b = (function() {"
19358 : " var f = function() { this.x = 2; };"
19359 : " f.displayName = 'display_b';"
19360 : " return f;"
19361 : "})();"
19362 : "var c = function() {};"
19363 : "c.__defineGetter__('displayName', function() {"
19364 : " error = true;"
19365 : " throw new Error();"
19366 : "});"
19367 : "function d() {};"
19368 : "d.__defineGetter__('displayName', function() {"
19369 : " error = true;"
19370 : " return 'wrong_display_name';"
19371 : "});"
19372 : "function e() {};"
19373 : "e.displayName = 'wrong_display_name';"
19374 : "e.__defineSetter__('displayName', function() {"
19375 : " error = true;"
19376 : " throw new Error();"
19377 : "});"
19378 : "function f() {};"
19379 : "f.displayName = { 'foo': 6, toString: function() {"
19380 : " error = true;"
19381 : " return 'wrong_display_name';"
19382 : "}};"
19383 : "var g = function() {"
19384 : " arguments.callee.displayName = 'set_in_runtime';"
19385 : "}; g();";
19386 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19387 6 : v8::Script::Compile(env.local(), v8_str(code), &origin)
19388 6 : .ToLocalChecked()
19389 6 : ->Run(env.local())
19390 6 : .ToLocalChecked();
19391 : v8::Local<v8::Value> error =
19392 30 : env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19393 : v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19394 30 : env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
19395 : v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19396 30 : env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
19397 : v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19398 30 : env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
19399 : v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19400 30 : env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
19401 : v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19402 30 : env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
19403 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19404 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19405 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19406 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19407 12 : CHECK(!error->BooleanValue(env.local()).FromJust());
19408 12 : CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(env->GetIsolate(),
19409 : a->GetDisplayName())));
19410 12 : CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(env->GetIsolate(),
19411 : b->GetDisplayName())));
19412 12 : CHECK(c->GetDisplayName()->IsUndefined());
19413 12 : CHECK(d->GetDisplayName()->IsUndefined());
19414 12 : CHECK(e->GetDisplayName()->IsUndefined());
19415 12 : CHECK(f->GetDisplayName()->IsUndefined());
19416 12 : CHECK_EQ(
19417 : 0, strcmp("set_in_runtime", *v8::String::Utf8Value(env->GetIsolate(),
19418 6 : g->GetDisplayName())));
19419 6 : }
19420 :
19421 :
19422 23724 : THREADED_TEST(ScriptLineNumber) {
19423 6 : LocalContext env;
19424 12 : v8::HandleScope scope(env->GetIsolate());
19425 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19426 6 : v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19427 6 : v8::Script::Compile(env.local(), script, &origin)
19428 6 : .ToLocalChecked()
19429 6 : ->Run(env.local())
19430 6 : .ToLocalChecked();
19431 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19432 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19433 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19434 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19435 6 : CHECK_EQ(0, f->GetScriptLineNumber());
19436 12 : CHECK_EQ(2, g->GetScriptLineNumber());
19437 6 : }
19438 :
19439 :
19440 23724 : THREADED_TEST(ScriptColumnNumber) {
19441 6 : LocalContext env;
19442 6 : v8::Isolate* isolate = env->GetIsolate();
19443 12 : v8::HandleScope scope(isolate);
19444 : v8::ScriptOrigin origin =
19445 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19446 6 : v8::Integer::New(isolate, 2));
19447 : v8::Local<v8::String> script =
19448 6 : v8_str("function foo() {}\n\n function bar() {}");
19449 6 : v8::Script::Compile(env.local(), script, &origin)
19450 6 : .ToLocalChecked()
19451 6 : ->Run(env.local())
19452 6 : .ToLocalChecked();
19453 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19454 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19455 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19456 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19457 6 : CHECK_EQ(14, foo->GetScriptColumnNumber());
19458 12 : CHECK_EQ(17, bar->GetScriptColumnNumber());
19459 6 : }
19460 :
19461 :
19462 23724 : THREADED_TEST(FunctionGetScriptId) {
19463 6 : LocalContext env;
19464 6 : v8::Isolate* isolate = env->GetIsolate();
19465 12 : v8::HandleScope scope(isolate);
19466 : v8::ScriptOrigin origin =
19467 : v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19468 6 : v8::Integer::New(isolate, 2));
19469 : v8::Local<v8::String> scriptSource =
19470 6 : v8_str("function foo() {}\n\n function bar() {}");
19471 : v8::Local<v8::Script> script(
19472 6 : v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
19473 6 : script->Run(env.local()).ToLocalChecked();
19474 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19475 30 : env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19476 : v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19477 30 : env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19478 12 : CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19479 18 : CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19480 6 : }
19481 :
19482 :
19483 23724 : THREADED_TEST(FunctionGetBoundFunction) {
19484 6 : LocalContext env;
19485 12 : v8::HandleScope scope(env->GetIsolate());
19486 6 : v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19487 : v8::Local<v8::String> script = v8_str(
19488 : "var a = new Object();\n"
19489 : "a.x = 1;\n"
19490 : "function f () { return this.x };\n"
19491 : "var g = f.bind(a);\n"
19492 6 : "var b = g();");
19493 6 : v8::Script::Compile(env.local(), script, &origin)
19494 6 : .ToLocalChecked()
19495 6 : ->Run(env.local())
19496 6 : .ToLocalChecked();
19497 : v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19498 30 : env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19499 : v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19500 30 : env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19501 12 : CHECK(g->GetBoundFunction()->IsFunction());
19502 : Local<v8::Function> original_function = Local<v8::Function>::Cast(
19503 6 : g->GetBoundFunction());
19504 18 : CHECK(f->GetName()
19505 : ->Equals(env.local(), original_function->GetName())
19506 : .FromJust());
19507 6 : CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19508 6 : CHECK_EQ(f->GetScriptColumnNumber(),
19509 6 : original_function->GetScriptColumnNumber());
19510 6 : }
19511 :
19512 :
19513 330 : static void GetterWhichReturns42(
19514 : Local<String> name,
19515 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19516 330 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19517 330 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19518 330 : info.GetReturnValue().Set(v8_num(42));
19519 330 : }
19520 :
19521 :
19522 270 : static void SetterWhichSetsYOnThisTo23(
19523 : Local<String> name,
19524 : Local<Value> value,
19525 : const v8::PropertyCallbackInfo<void>& info) {
19526 270 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19527 270 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19528 : Local<Object>::Cast(info.This())
19529 810 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19530 540 : .FromJust();
19531 270 : }
19532 :
19533 :
19534 120 : void FooGetInterceptor(Local<Name> name,
19535 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19536 120 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19537 120 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19538 360 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19539 240 : .FromJust()) {
19540 120 : return;
19541 : }
19542 96 : info.GetReturnValue().Set(v8_num(42));
19543 : }
19544 :
19545 :
19546 336 : void FooSetInterceptor(Local<Name> name, Local<Value> value,
19547 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19548 336 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19549 336 : CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19550 1008 : if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19551 672 : .FromJust()) {
19552 336 : return;
19553 : }
19554 : Local<Object>::Cast(info.This())
19555 288 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19556 192 : .FromJust();
19557 96 : info.GetReturnValue().Set(v8_num(23));
19558 : }
19559 :
19560 :
19561 23723 : TEST(SetterOnConstructorPrototype) {
19562 5 : v8::Isolate* isolate = CcTest::isolate();
19563 5 : v8::HandleScope scope(isolate);
19564 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19565 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19566 5 : SetterWhichSetsYOnThisTo23);
19567 10 : LocalContext context;
19568 30 : CHECK(context->Global()
19569 : ->Set(context.local(), v8_str("P"),
19570 : templ->NewInstance(context.local()).ToLocalChecked())
19571 : .FromJust());
19572 : CompileRun("function C1() {"
19573 : " this.x = 23;"
19574 : "};"
19575 : "C1.prototype = P;"
19576 : "function C2() {"
19577 : " this.x = 23"
19578 : "};"
19579 : "C2.prototype = { };"
19580 : "C2.prototype.__proto__ = P;");
19581 :
19582 : v8::Local<v8::Script> script;
19583 : script = v8_compile("new C1();");
19584 55 : for (int i = 0; i < 10; i++) {
19585 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19586 50 : script->Run(context.local()).ToLocalChecked());
19587 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19588 : .ToLocalChecked()
19589 : ->Int32Value(context.local())
19590 : .FromJust());
19591 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19592 : .ToLocalChecked()
19593 : ->Int32Value(context.local())
19594 : .FromJust());
19595 : }
19596 :
19597 : script = v8_compile("new C2();");
19598 55 : for (int i = 0; i < 10; i++) {
19599 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19600 50 : script->Run(context.local()).ToLocalChecked());
19601 200 : CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
19602 : .ToLocalChecked()
19603 : ->Int32Value(context.local())
19604 : .FromJust());
19605 200 : CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
19606 : .ToLocalChecked()
19607 : ->Int32Value(context.local())
19608 : .FromJust());
19609 5 : }
19610 5 : }
19611 :
19612 :
19613 0 : static void NamedPropertySetterWhichSetsYOnThisTo23(
19614 : Local<Name> name, Local<Value> value,
19615 : const v8::PropertyCallbackInfo<v8::Value>& info) {
19616 0 : if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
19617 0 : .FromJust()) {
19618 : Local<Object>::Cast(info.This())
19619 0 : ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19620 0 : .FromJust();
19621 : }
19622 0 : }
19623 :
19624 :
19625 23724 : THREADED_TEST(InterceptorOnConstructorPrototype) {
19626 6 : v8::Isolate* isolate = CcTest::isolate();
19627 6 : v8::HandleScope scope(isolate);
19628 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19629 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19630 : NamedPropertyGetterWhichReturns42,
19631 6 : NamedPropertySetterWhichSetsYOnThisTo23));
19632 12 : LocalContext context;
19633 36 : CHECK(context->Global()
19634 : ->Set(context.local(), v8_str("P"),
19635 : templ->NewInstance(context.local()).ToLocalChecked())
19636 : .FromJust());
19637 : CompileRun("function C1() {"
19638 : " this.x = 23;"
19639 : "};"
19640 : "C1.prototype = P;"
19641 : "function C2() {"
19642 : " this.x = 23"
19643 : "};"
19644 : "C2.prototype = { };"
19645 : "C2.prototype.__proto__ = P;");
19646 :
19647 : v8::Local<v8::Script> script;
19648 : script = v8_compile("new C1();");
19649 66 : for (int i = 0; i < 10; i++) {
19650 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19651 60 : script->Run(context.local()).ToLocalChecked());
19652 240 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19653 : .ToLocalChecked()
19654 : ->Int32Value(context.local())
19655 : .FromJust());
19656 240 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19657 : .ToLocalChecked()
19658 : ->Int32Value(context.local())
19659 : .FromJust());
19660 : }
19661 :
19662 : script = v8_compile("new C2();");
19663 66 : for (int i = 0; i < 10; i++) {
19664 : v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19665 60 : script->Run(context.local()).ToLocalChecked());
19666 240 : CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
19667 : .ToLocalChecked()
19668 : ->Int32Value(context.local())
19669 : .FromJust());
19670 240 : CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
19671 : .ToLocalChecked()
19672 : ->Int32Value(context.local())
19673 : .FromJust());
19674 6 : }
19675 6 : }
19676 :
19677 :
19678 23723 : TEST(Regress618) {
19679 : const char* source = "function C1() {"
19680 : " this.x = 23;"
19681 : "};"
19682 : "C1.prototype = P;";
19683 :
19684 5 : LocalContext context;
19685 5 : v8::Isolate* isolate = context->GetIsolate();
19686 10 : v8::HandleScope scope(isolate);
19687 : v8::Local<v8::Script> script;
19688 :
19689 : // Use a simple object as prototype.
19690 5 : v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19691 20 : prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
19692 25 : CHECK(context->Global()
19693 : ->Set(context.local(), v8_str("P"), prototype)
19694 : .FromJust());
19695 :
19696 : // This compile will add the code to the compilation cache.
19697 : CompileRun(source);
19698 :
19699 : script = v8_compile("new C1();");
19700 : // Allow enough iterations for the inobject slack tracking logic
19701 : // to finalize instance size and install the fast construct stub.
19702 1285 : for (int i = 0; i < 256; i++) {
19703 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19704 1280 : script->Run(context.local()).ToLocalChecked());
19705 5120 : CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19706 : .ToLocalChecked()
19707 : ->Int32Value(context.local())
19708 : .FromJust());
19709 5120 : CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19710 : .ToLocalChecked()
19711 : ->Int32Value(context.local())
19712 : .FromJust());
19713 : }
19714 :
19715 : // Use an API object with accessors as prototype.
19716 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19717 : templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19718 5 : SetterWhichSetsYOnThisTo23);
19719 30 : CHECK(context->Global()
19720 : ->Set(context.local(), v8_str("P"),
19721 : templ->NewInstance(context.local()).ToLocalChecked())
19722 : .FromJust());
19723 :
19724 : // This compile will get the code from the compilation cache.
19725 : CompileRun(source);
19726 :
19727 : script = v8_compile("new C1();");
19728 55 : for (int i = 0; i < 10; i++) {
19729 : v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19730 50 : script->Run(context.local()).ToLocalChecked());
19731 200 : CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19732 : .ToLocalChecked()
19733 : ->Int32Value(context.local())
19734 : .FromJust());
19735 200 : CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19736 : .ToLocalChecked()
19737 : ->Int32Value(context.local())
19738 : .FromJust());
19739 5 : }
19740 5 : }
19741 :
19742 : v8::Isolate* gc_callbacks_isolate = nullptr;
19743 : int prologue_call_count = 0;
19744 : int epilogue_call_count = 0;
19745 : int prologue_call_count_second = 0;
19746 : int epilogue_call_count_second = 0;
19747 : int prologue_call_count_alloc = 0;
19748 : int epilogue_call_count_alloc = 0;
19749 :
19750 20 : void PrologueCallback(v8::Isolate* isolate,
19751 : v8::GCType,
19752 : v8::GCCallbackFlags flags) {
19753 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19754 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19755 20 : ++prologue_call_count;
19756 20 : }
19757 :
19758 20 : void EpilogueCallback(v8::Isolate* isolate,
19759 : v8::GCType,
19760 : v8::GCCallbackFlags flags) {
19761 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19762 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19763 20 : ++epilogue_call_count;
19764 20 : }
19765 :
19766 :
19767 20 : void PrologueCallbackSecond(v8::Isolate* isolate,
19768 : v8::GCType,
19769 : v8::GCCallbackFlags flags) {
19770 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19771 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19772 20 : ++prologue_call_count_second;
19773 20 : }
19774 :
19775 :
19776 20 : void EpilogueCallbackSecond(v8::Isolate* isolate,
19777 : v8::GCType,
19778 : v8::GCCallbackFlags flags) {
19779 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19780 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19781 20 : ++epilogue_call_count_second;
19782 20 : }
19783 :
19784 20 : void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
19785 : v8::GCCallbackFlags flags, void* data) {
19786 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19787 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19788 20 : ++*static_cast<int*>(data);
19789 20 : }
19790 :
19791 20 : void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
19792 : v8::GCCallbackFlags flags, void* data) {
19793 20 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19794 20 : CHECK_EQ(gc_callbacks_isolate, isolate);
19795 20 : ++*static_cast<int*>(data);
19796 20 : }
19797 :
19798 5 : void PrologueCallbackAlloc(v8::Isolate* isolate,
19799 : v8::GCType,
19800 : v8::GCCallbackFlags flags) {
19801 5 : v8::HandleScope scope(isolate);
19802 :
19803 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19804 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19805 5 : ++prologue_call_count_alloc;
19806 :
19807 : // Simulate full heap to see if we will reenter this callback
19808 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19809 :
19810 5 : Local<Object> obj = Object::New(isolate);
19811 5 : CHECK(!obj.IsEmpty());
19812 :
19813 5 : CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
19814 5 : }
19815 :
19816 :
19817 5 : void EpilogueCallbackAlloc(v8::Isolate* isolate,
19818 : v8::GCType,
19819 : v8::GCCallbackFlags flags) {
19820 5 : v8::HandleScope scope(isolate);
19821 :
19822 5 : CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19823 5 : CHECK_EQ(gc_callbacks_isolate, isolate);
19824 5 : ++epilogue_call_count_alloc;
19825 :
19826 : // Simulate full heap to see if we will reenter this callback
19827 5 : i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19828 :
19829 5 : Local<Object> obj = Object::New(isolate);
19830 5 : CHECK(!obj.IsEmpty());
19831 :
19832 5 : CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
19833 5 : }
19834 :
19835 :
19836 23723 : TEST(GCCallbacksOld) {
19837 5 : LocalContext context;
19838 :
19839 5 : gc_callbacks_isolate = context->GetIsolate();
19840 :
19841 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
19842 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
19843 5 : CHECK_EQ(0, prologue_call_count);
19844 5 : CHECK_EQ(0, epilogue_call_count);
19845 5 : CcTest::CollectAllGarbage();
19846 5 : CHECK_EQ(1, prologue_call_count);
19847 5 : CHECK_EQ(1, epilogue_call_count);
19848 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
19849 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
19850 5 : CcTest::CollectAllGarbage();
19851 5 : CHECK_EQ(2, prologue_call_count);
19852 5 : CHECK_EQ(2, epilogue_call_count);
19853 5 : CHECK_EQ(1, prologue_call_count_second);
19854 5 : CHECK_EQ(1, epilogue_call_count_second);
19855 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
19856 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
19857 5 : CcTest::CollectAllGarbage();
19858 5 : CHECK_EQ(2, prologue_call_count);
19859 5 : CHECK_EQ(2, epilogue_call_count);
19860 5 : CHECK_EQ(2, prologue_call_count_second);
19861 5 : CHECK_EQ(2, epilogue_call_count_second);
19862 5 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
19863 5 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19864 5 : CcTest::CollectAllGarbage();
19865 5 : CHECK_EQ(2, prologue_call_count);
19866 5 : CHECK_EQ(2, epilogue_call_count);
19867 5 : CHECK_EQ(2, prologue_call_count_second);
19868 5 : CHECK_EQ(2, epilogue_call_count_second);
19869 5 : }
19870 :
19871 23723 : TEST(GCCallbacksWithData) {
19872 5 : LocalContext context;
19873 :
19874 5 : gc_callbacks_isolate = context->GetIsolate();
19875 5 : int prologue1 = 0;
19876 5 : int epilogue1 = 0;
19877 5 : int prologue2 = 0;
19878 5 : int epilogue2 = 0;
19879 :
19880 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
19881 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
19882 5 : CHECK_EQ(0, prologue1);
19883 5 : CHECK_EQ(0, epilogue1);
19884 5 : CHECK_EQ(0, prologue2);
19885 5 : CHECK_EQ(0, epilogue2);
19886 5 : CcTest::CollectAllGarbage();
19887 5 : CHECK_EQ(1, prologue1);
19888 5 : CHECK_EQ(1, epilogue1);
19889 5 : CHECK_EQ(0, prologue2);
19890 5 : CHECK_EQ(0, epilogue2);
19891 5 : context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
19892 5 : context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
19893 5 : CcTest::CollectAllGarbage();
19894 5 : CHECK_EQ(2, prologue1);
19895 5 : CHECK_EQ(2, epilogue1);
19896 5 : CHECK_EQ(1, prologue2);
19897 5 : CHECK_EQ(1, epilogue2);
19898 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19899 5 : &prologue1);
19900 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19901 5 : &epilogue1);
19902 5 : CcTest::CollectAllGarbage();
19903 5 : CHECK_EQ(2, prologue1);
19904 5 : CHECK_EQ(2, epilogue1);
19905 5 : CHECK_EQ(2, prologue2);
19906 5 : CHECK_EQ(2, epilogue2);
19907 : context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19908 5 : &prologue2);
19909 : context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19910 5 : &epilogue2);
19911 5 : CcTest::CollectAllGarbage();
19912 5 : CHECK_EQ(2, prologue1);
19913 5 : CHECK_EQ(2, epilogue1);
19914 5 : CHECK_EQ(2, prologue2);
19915 5 : CHECK_EQ(2, epilogue2);
19916 5 : }
19917 :
19918 23723 : TEST(GCCallbacks) {
19919 5 : LocalContext context;
19920 5 : v8::Isolate* isolate = context->GetIsolate();
19921 5 : gc_callbacks_isolate = isolate;
19922 5 : isolate->AddGCPrologueCallback(PrologueCallback);
19923 5 : isolate->AddGCEpilogueCallback(EpilogueCallback);
19924 5 : CHECK_EQ(0, prologue_call_count);
19925 5 : CHECK_EQ(0, epilogue_call_count);
19926 5 : CcTest::CollectAllGarbage();
19927 5 : CHECK_EQ(1, prologue_call_count);
19928 5 : CHECK_EQ(1, epilogue_call_count);
19929 5 : isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19930 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19931 5 : CcTest::CollectAllGarbage();
19932 5 : CHECK_EQ(2, prologue_call_count);
19933 5 : CHECK_EQ(2, epilogue_call_count);
19934 5 : CHECK_EQ(1, prologue_call_count_second);
19935 5 : CHECK_EQ(1, epilogue_call_count_second);
19936 5 : isolate->RemoveGCPrologueCallback(PrologueCallback);
19937 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19938 5 : CcTest::CollectAllGarbage();
19939 5 : CHECK_EQ(2, prologue_call_count);
19940 5 : CHECK_EQ(2, epilogue_call_count);
19941 5 : CHECK_EQ(2, prologue_call_count_second);
19942 5 : CHECK_EQ(2, epilogue_call_count_second);
19943 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19944 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19945 5 : CcTest::CollectAllGarbage();
19946 5 : CHECK_EQ(2, prologue_call_count);
19947 5 : CHECK_EQ(2, epilogue_call_count);
19948 5 : CHECK_EQ(2, prologue_call_count_second);
19949 5 : CHECK_EQ(2, epilogue_call_count_second);
19950 :
19951 5 : CHECK_EQ(0, prologue_call_count_alloc);
19952 5 : CHECK_EQ(0, epilogue_call_count_alloc);
19953 5 : isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19954 5 : isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19955 5 : CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
19956 5 : CHECK_EQ(1, prologue_call_count_alloc);
19957 5 : CHECK_EQ(1, epilogue_call_count_alloc);
19958 5 : isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19959 5 : isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19960 5 : }
19961 :
19962 :
19963 23724 : THREADED_TEST(TwoByteStringInOneByteCons) {
19964 : // See Chromium issue 47824.
19965 6 : LocalContext context;
19966 12 : v8::HandleScope scope(context->GetIsolate());
19967 :
19968 : const char* init_code =
19969 : "var str1 = 'abelspendabel';"
19970 : "var str2 = str1 + str1 + str1;"
19971 : "str2;";
19972 : Local<Value> result = CompileRun(init_code);
19973 :
19974 6 : Local<Value> indexof = CompileRun("str2.indexOf('els')");
19975 6 : Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19976 :
19977 6 : CHECK(result->IsString());
19978 : i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19979 : int length = string->length();
19980 6 : CHECK(string->IsOneByteRepresentation());
19981 :
19982 6 : i::Handle<i::String> flat_string = i::String::Flatten(string);
19983 :
19984 6 : CHECK(string->IsOneByteRepresentation());
19985 6 : CHECK(flat_string->IsOneByteRepresentation());
19986 :
19987 : // Create external resource.
19988 6 : uint16_t* uc16_buffer = new uint16_t[length + 1];
19989 :
19990 6 : i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19991 6 : uc16_buffer[length] = 0;
19992 :
19993 6 : TestResource resource(uc16_buffer);
19994 :
19995 6 : flat_string->MakeExternal(&resource);
19996 :
19997 6 : CHECK(flat_string->IsTwoByteRepresentation());
19998 :
19999 : // If the cons string has been short-circuited, skip the following checks.
20000 6 : if (!string.is_identical_to(flat_string)) {
20001 : // At this point, we should have a Cons string which is flat and one-byte,
20002 : // with a first half that is a two-byte string (although it only contains
20003 : // one-byte characters). This is a valid sequence of steps, and it can
20004 : // happen in real pages.
20005 6 : CHECK(string->IsOneByteRepresentation());
20006 : i::ConsString* cons = i::ConsString::cast(*string);
20007 6 : CHECK_EQ(0, cons->second()->length());
20008 6 : CHECK(cons->first()->IsTwoByteRepresentation());
20009 : }
20010 :
20011 : // Check that some string operations work.
20012 :
20013 : // Atom RegExp.
20014 : Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
20015 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
20016 :
20017 : // Nonatom RegExp.
20018 : reresult = CompileRun("str2.match(/abe./g).length;");
20019 12 : CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
20020 :
20021 : reresult = CompileRun("str2.search(/bel/g);");
20022 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
20023 :
20024 : reresult = CompileRun("str2.search(/be./g);");
20025 12 : CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
20026 :
20027 : ExpectTrue("/bel/g.test(str2);");
20028 :
20029 : ExpectTrue("/be./g.test(str2);");
20030 :
20031 : reresult = CompileRun("/bel/g.exec(str2);");
20032 6 : CHECK(!reresult->IsNull());
20033 :
20034 : reresult = CompileRun("/be./g.exec(str2);");
20035 6 : CHECK(!reresult->IsNull());
20036 :
20037 6 : ExpectString("str2.substring(2, 10);", "elspenda");
20038 :
20039 6 : ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
20040 :
20041 6 : ExpectString("str2.charAt(2);", "e");
20042 :
20043 6 : ExpectObject("str2.indexOf('els');", indexof);
20044 :
20045 6 : ExpectObject("str2.lastIndexOf('dab');", lastindexof);
20046 :
20047 : reresult = CompileRun("str2.charCodeAt(2);");
20048 12 : CHECK_EQ(static_cast<int32_t>('e'),
20049 6 : reresult->Int32Value(context.local()).FromJust());
20050 6 : }
20051 :
20052 :
20053 23723 : TEST(ContainsOnlyOneByte) {
20054 5 : v8::V8::Initialize();
20055 5 : v8::Isolate* isolate = CcTest::isolate();
20056 5 : v8::HandleScope scope(isolate);
20057 : // Make a buffer long enough that it won't automatically be converted.
20058 : const int length = 512;
20059 : // Ensure word aligned assignment.
20060 : const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
20061 5 : std::unique_ptr<uintptr_t[]> aligned_contents(new uintptr_t[aligned_length]);
20062 : uint16_t* string_contents =
20063 : reinterpret_cast<uint16_t*>(aligned_contents.get());
20064 : // Set to contain only one byte.
20065 2560 : for (int i = 0; i < length-1; i++) {
20066 2555 : string_contents[i] = 0x41;
20067 : }
20068 5 : string_contents[length-1] = 0;
20069 : // Simple case.
20070 : Local<String> string =
20071 : String::NewExternalTwoByte(
20072 5 : isolate, new TestResource(string_contents, nullptr, false))
20073 5 : .ToLocalChecked();
20074 5 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20075 : // Counter example.
20076 : string = String::NewFromTwoByte(isolate, string_contents,
20077 : v8::NewStringType::kNormal)
20078 5 : .ToLocalChecked();
20079 5 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20080 : // Test left right and balanced cons strings.
20081 5 : Local<String> base = v8_str("a");
20082 5 : Local<String> left = base;
20083 5 : Local<String> right = base;
20084 5005 : for (int i = 0; i < 1000; i++) {
20085 5000 : left = String::Concat(base, left);
20086 5000 : right = String::Concat(right, base);
20087 : }
20088 5 : Local<String> balanced = String::Concat(left, base);
20089 5 : balanced = String::Concat(balanced, right);
20090 5 : Local<String> cons_strings[] = {left, balanced, right};
20091 : Local<String> two_byte =
20092 : String::NewExternalTwoByte(
20093 5 : isolate, new TestResource(string_contents, nullptr, false))
20094 10 : .ToLocalChecked();
20095 : USE(two_byte); USE(cons_strings);
20096 20 : for (size_t i = 0; i < arraysize(cons_strings); i++) {
20097 : // Base assumptions.
20098 15 : string = cons_strings[i];
20099 15 : CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20100 : // Test left and right concatentation.
20101 15 : string = String::Concat(two_byte, cons_strings[i]);
20102 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20103 15 : string = String::Concat(cons_strings[i], two_byte);
20104 15 : CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20105 : }
20106 : // Set bits in different positions
20107 : // for strings of different lengths and alignments.
20108 35 : for (int alignment = 0; alignment < 7; alignment++) {
20109 280 : for (int size = 2; alignment + size < length; size *= 2) {
20110 : int zero_offset = size + alignment;
20111 280 : string_contents[zero_offset] = 0;
20112 18130 : for (int i = 0; i < size; i++) {
20113 17850 : int shift = 8 + (i % 7);
20114 17850 : string_contents[alignment + i] = 1 << shift;
20115 : string = String::NewExternalTwoByte(
20116 : isolate, new TestResource(string_contents + alignment,
20117 17850 : nullptr, false))
20118 17850 : .ToLocalChecked();
20119 17850 : CHECK_EQ(size, string->Length());
20120 17850 : CHECK(!string->ContainsOnlyOneByte());
20121 17850 : string_contents[alignment + i] = 0x41;
20122 : }
20123 280 : string_contents[zero_offset] = 0x41;
20124 : }
20125 5 : }
20126 5 : }
20127 :
20128 :
20129 : // Failed access check callback that performs a GC on each invocation.
20130 75 : void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20131 : v8::AccessType type,
20132 : Local<v8::Value> data) {
20133 75 : CcTest::CollectAllGarbage();
20134 : CcTest::isolate()->ThrowException(
20135 75 : v8::Exception::Error(v8_str("cross context")));
20136 75 : }
20137 :
20138 :
20139 23723 : TEST(GCInFailedAccessCheckCallback) {
20140 : // Install a failed access check callback that performs a GC on each
20141 : // invocation. Then force the callback to be called from va
20142 :
20143 5 : v8::V8::Initialize();
20144 5 : v8::Isolate* isolate = CcTest::isolate();
20145 :
20146 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20147 :
20148 5 : v8::HandleScope scope(isolate);
20149 :
20150 : // Create an ObjectTemplate for global objects and install access
20151 : // check callbacks that will block access.
20152 : v8::Local<v8::ObjectTemplate> global_template =
20153 5 : v8::ObjectTemplate::New(isolate);
20154 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
20155 :
20156 : // Create a context and set an x property on it's global object.
20157 10 : LocalContext context0(nullptr, global_template);
20158 25 : CHECK(context0->Global()
20159 : ->Set(context0.local(), v8_str("x"), v8_num(42))
20160 : .FromJust());
20161 5 : v8::Local<v8::Object> global0 = context0->Global();
20162 :
20163 : // Create a context with a different security token so that the
20164 : // failed access check callback will be called on each access.
20165 10 : LocalContext context1(nullptr, global_template);
20166 25 : CHECK(context1->Global()
20167 : ->Set(context1.local(), v8_str("other"), global0)
20168 : .FromJust());
20169 :
20170 10 : v8::TryCatch try_catch(isolate);
20171 :
20172 : // Get property with failed access check.
20173 5 : CHECK(CompileRun("other.x").IsEmpty());
20174 5 : CHECK(try_catch.HasCaught());
20175 5 : try_catch.Reset();
20176 :
20177 : // Get element with failed access check.
20178 5 : CHECK(CompileRun("other[0]").IsEmpty());
20179 5 : CHECK(try_catch.HasCaught());
20180 5 : try_catch.Reset();
20181 :
20182 : // Set property with failed access check.
20183 5 : CHECK(CompileRun("other.x = new Object()").IsEmpty());
20184 5 : CHECK(try_catch.HasCaught());
20185 5 : try_catch.Reset();
20186 :
20187 : // Set element with failed access check.
20188 5 : CHECK(CompileRun("other[0] = new Object()").IsEmpty());
20189 5 : CHECK(try_catch.HasCaught());
20190 5 : try_catch.Reset();
20191 :
20192 : // Get property attribute with failed access check.
20193 5 : CHECK(CompileRun("\'x\' in other").IsEmpty());
20194 5 : CHECK(try_catch.HasCaught());
20195 5 : try_catch.Reset();
20196 :
20197 : // Get property attribute for element with failed access check.
20198 5 : CHECK(CompileRun("0 in other").IsEmpty());
20199 5 : CHECK(try_catch.HasCaught());
20200 5 : try_catch.Reset();
20201 :
20202 : // Delete property.
20203 5 : CHECK(CompileRun("delete other.x").IsEmpty());
20204 5 : CHECK(try_catch.HasCaught());
20205 5 : try_catch.Reset();
20206 :
20207 : // Delete element.
20208 10 : CHECK(global0->Delete(context1.local(), 0).IsNothing());
20209 5 : CHECK(try_catch.HasCaught());
20210 5 : try_catch.Reset();
20211 :
20212 : // DefineAccessor.
20213 20 : CHECK(global0
20214 : ->SetAccessor(context1.local(), v8_str("x"), GetXValue, nullptr,
20215 : v8_str("x"))
20216 : .IsNothing());
20217 5 : CHECK(try_catch.HasCaught());
20218 5 : try_catch.Reset();
20219 :
20220 : // Define JavaScript accessor.
20221 5 : CHECK(CompileRun(
20222 : "Object.prototype.__defineGetter__.call("
20223 : " other, \'x\', function() { return 42; })").IsEmpty());
20224 5 : CHECK(try_catch.HasCaught());
20225 5 : try_catch.Reset();
20226 :
20227 : // LookupAccessor.
20228 5 : CHECK(CompileRun(
20229 : "Object.prototype.__lookupGetter__.call("
20230 : " other, \'x\')").IsEmpty());
20231 5 : CHECK(try_catch.HasCaught());
20232 5 : try_catch.Reset();
20233 :
20234 : // HasOwnElement.
20235 5 : CHECK(CompileRun(
20236 : "Object.prototype.hasOwnProperty.call("
20237 : "other, \'0\')").IsEmpty());
20238 5 : CHECK(try_catch.HasCaught());
20239 5 : try_catch.Reset();
20240 :
20241 10 : CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
20242 5 : CHECK(try_catch.HasCaught());
20243 5 : try_catch.Reset();
20244 :
20245 15 : CHECK(
20246 : global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
20247 5 : CHECK(try_catch.HasCaught());
20248 5 : try_catch.Reset();
20249 :
20250 15 : CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
20251 : .IsNothing());
20252 5 : CHECK(try_catch.HasCaught());
20253 5 : try_catch.Reset();
20254 :
20255 : // Reset the failed access check callback so it does not influence
20256 : // the other tests.
20257 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
20258 5 : }
20259 :
20260 :
20261 23723 : TEST(IsolateNewDispose) {
20262 5 : v8::Isolate* current_isolate = CcTest::isolate();
20263 : v8::Isolate::CreateParams create_params;
20264 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20265 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20266 5 : CHECK_NOT_NULL(isolate);
20267 5 : CHECK(current_isolate != isolate);
20268 5 : CHECK(current_isolate == CcTest::isolate());
20269 :
20270 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20271 5 : last_location = last_message = nullptr;
20272 5 : isolate->Dispose();
20273 5 : CHECK(!last_location);
20274 5 : CHECK(!last_message);
20275 5 : }
20276 :
20277 :
20278 23723 : UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20279 : v8::Isolate::CreateParams create_params;
20280 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20281 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20282 : {
20283 : v8::Isolate::Scope i_scope(isolate);
20284 10 : v8::HandleScope scope(isolate);
20285 5 : LocalContext context(isolate);
20286 : // Run something in this isolate.
20287 : ExpectTrue("true");
20288 5 : isolate->SetFatalErrorHandler(StoringErrorCallback);
20289 5 : last_location = last_message = nullptr;
20290 : // Still entered, should fail.
20291 5 : isolate->Dispose();
20292 5 : CHECK(last_location);
20293 5 : CHECK(last_message);
20294 : }
20295 5 : isolate->Dispose();
20296 5 : }
20297 :
20298 :
20299 40 : static void BreakArrayGuarantees(const char* script) {
20300 : v8::Isolate::CreateParams create_params;
20301 40 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20302 40 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20303 40 : isolate1->Enter();
20304 : v8::Persistent<v8::Context> context1;
20305 : {
20306 40 : v8::HandleScope scope(isolate1);
20307 80 : context1.Reset(isolate1, Context::New(isolate1));
20308 : }
20309 :
20310 : {
20311 40 : v8::HandleScope scope(isolate1);
20312 : v8::Local<v8::Context> context =
20313 : v8::Local<v8::Context>::New(isolate1, context1);
20314 : v8::Context::Scope context_scope(context);
20315 : v8::internal::Isolate* i_isolate =
20316 : reinterpret_cast<v8::internal::Isolate*>(isolate1);
20317 40 : CHECK(i_isolate->IsFastArrayConstructorPrototypeChainIntact());
20318 : // Run something in new isolate.
20319 : CompileRun(script);
20320 80 : CHECK(!i_isolate->IsFastArrayConstructorPrototypeChainIntact());
20321 : }
20322 40 : isolate1->Exit();
20323 40 : isolate1->Dispose();
20324 40 : }
20325 :
20326 :
20327 23723 : TEST(VerifyArrayPrototypeGuarantees) {
20328 : // Break fast array hole handling by element changes.
20329 5 : BreakArrayGuarantees("[].__proto__[1] = 3;");
20330 5 : BreakArrayGuarantees("Object.prototype[3] = 'three';");
20331 5 : BreakArrayGuarantees("Array.prototype.push(1);");
20332 5 : BreakArrayGuarantees("Array.prototype.unshift(1);");
20333 : // Break fast array hole handling by changing length.
20334 5 : BreakArrayGuarantees("Array.prototype.length = 30;");
20335 : // Break fast array hole handling by prototype structure changes.
20336 5 : BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
20337 : // By sending elements to dictionary mode.
20338 : BreakArrayGuarantees(
20339 : "Object.defineProperty(Array.prototype, 0, {"
20340 5 : " get: function() { return 3; }});");
20341 : BreakArrayGuarantees(
20342 : "Object.defineProperty(Object.prototype, 0, {"
20343 5 : " get: function() { return 3; }});");
20344 5 : }
20345 :
20346 :
20347 23723 : TEST(RunTwoIsolatesOnSingleThread) {
20348 : // Run isolate 1.
20349 : v8::Isolate::CreateParams create_params;
20350 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20351 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20352 5 : isolate1->Enter();
20353 : v8::Persistent<v8::Context> context1;
20354 : {
20355 5 : v8::HandleScope scope(isolate1);
20356 10 : context1.Reset(isolate1, Context::New(isolate1));
20357 : }
20358 :
20359 : {
20360 5 : v8::HandleScope scope(isolate1);
20361 : v8::Local<v8::Context> context =
20362 : v8::Local<v8::Context>::New(isolate1, context1);
20363 : v8::Context::Scope context_scope(context);
20364 : // Run something in new isolate.
20365 : CompileRun("var foo = 'isolate 1';");
20366 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20367 : }
20368 :
20369 : // Run isolate 2.
20370 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
20371 : v8::Persistent<v8::Context> context2;
20372 :
20373 : {
20374 : v8::Isolate::Scope iscope(isolate2);
20375 10 : v8::HandleScope scope(isolate2);
20376 10 : context2.Reset(isolate2, Context::New(isolate2));
20377 : v8::Local<v8::Context> context =
20378 : v8::Local<v8::Context>::New(isolate2, context2);
20379 : v8::Context::Scope context_scope(context);
20380 :
20381 : // Run something in new isolate.
20382 : CompileRun("var foo = 'isolate 2';");
20383 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20384 : }
20385 :
20386 : {
20387 5 : v8::HandleScope scope(isolate1);
20388 : v8::Local<v8::Context> context =
20389 : v8::Local<v8::Context>::New(isolate1, context1);
20390 : v8::Context::Scope context_scope(context);
20391 : // Now again in isolate 1
20392 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20393 : }
20394 :
20395 5 : isolate1->Exit();
20396 :
20397 : // Run some stuff in default isolate.
20398 : v8::Persistent<v8::Context> context_default;
20399 : {
20400 5 : v8::Isolate* isolate = CcTest::isolate();
20401 : v8::Isolate::Scope iscope(isolate);
20402 10 : v8::HandleScope scope(isolate);
20403 10 : context_default.Reset(isolate, Context::New(isolate));
20404 : }
20405 :
20406 : {
20407 5 : v8::HandleScope scope(CcTest::isolate());
20408 : v8::Local<v8::Context> context =
20409 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20410 : v8::Context::Scope context_scope(context);
20411 : // Variables in other isolates should be not available, verify there
20412 : // is an exception.
20413 : ExpectTrue("function f() {"
20414 : " try {"
20415 : " foo;"
20416 : " return false;"
20417 : " } catch(e) {"
20418 : " return true;"
20419 : " }"
20420 : "};"
20421 : "var isDefaultIsolate = true;"
20422 5 : "f()");
20423 : }
20424 :
20425 5 : isolate1->Enter();
20426 :
20427 : {
20428 : v8::Isolate::Scope iscope(isolate2);
20429 10 : v8::HandleScope scope(isolate2);
20430 : v8::Local<v8::Context> context =
20431 : v8::Local<v8::Context>::New(isolate2, context2);
20432 : v8::Context::Scope context_scope(context);
20433 5 : ExpectString("function f() { return foo; }; f()", "isolate 2");
20434 : }
20435 :
20436 : {
20437 5 : v8::HandleScope scope(v8::Isolate::GetCurrent());
20438 : v8::Local<v8::Context> context =
20439 5 : v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20440 : v8::Context::Scope context_scope(context);
20441 10 : ExpectString("function f() { return foo; }; f()", "isolate 1");
20442 : }
20443 :
20444 : {
20445 : v8::Isolate::Scope iscope(isolate2);
20446 : context2.Reset();
20447 : }
20448 :
20449 : context1.Reset();
20450 5 : isolate1->Exit();
20451 :
20452 5 : isolate2->SetFatalErrorHandler(StoringErrorCallback);
20453 5 : last_location = last_message = nullptr;
20454 :
20455 5 : isolate1->Dispose();
20456 5 : CHECK(!last_location);
20457 5 : CHECK(!last_message);
20458 :
20459 5 : isolate2->Dispose();
20460 5 : CHECK(!last_location);
20461 5 : CHECK(!last_message);
20462 :
20463 : // Check that default isolate still runs.
20464 : {
20465 5 : v8::HandleScope scope(CcTest::isolate());
20466 : v8::Local<v8::Context> context =
20467 5 : v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20468 : v8::Context::Scope context_scope(context);
20469 5 : ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20470 : }
20471 5 : }
20472 :
20473 :
20474 20 : static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20475 : v8::Isolate::Scope isolate_scope(isolate);
20476 40 : v8::HandleScope scope(isolate);
20477 20 : LocalContext context(isolate);
20478 : i::ScopedVector<char> code(1024);
20479 : i::SNPrintF(code, "function fib(n) {"
20480 : " if (n <= 2) return 1;"
20481 : " return fib(n-1) + fib(n-2);"
20482 : "}"
20483 20 : "fib(%d)", limit);
20484 : Local<Value> value = CompileRun(code.start());
20485 20 : CHECK(value->IsNumber());
20486 60 : return static_cast<int>(value->NumberValue(context.local()).FromJust());
20487 : }
20488 :
20489 5 : class IsolateThread : public v8::base::Thread {
20490 : public:
20491 : explicit IsolateThread(int fib_limit)
20492 10 : : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20493 :
20494 10 : void Run() {
20495 : v8::Isolate::CreateParams create_params;
20496 10 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20497 10 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20498 10 : result_ = CalcFibonacci(isolate, fib_limit_);
20499 10 : isolate->Dispose();
20500 10 : }
20501 :
20502 : int result() { return result_; }
20503 :
20504 : private:
20505 : int fib_limit_;
20506 : int result_;
20507 : };
20508 :
20509 :
20510 23723 : TEST(MultipleIsolatesOnIndividualThreads) {
20511 : IsolateThread thread1(21);
20512 : IsolateThread thread2(12);
20513 :
20514 : // Compute some fibonacci numbers on 3 threads in 3 isolates.
20515 5 : thread1.Start();
20516 5 : thread2.Start();
20517 :
20518 5 : int result1 = CalcFibonacci(CcTest::isolate(), 21);
20519 5 : int result2 = CalcFibonacci(CcTest::isolate(), 12);
20520 :
20521 5 : thread1.Join();
20522 5 : thread2.Join();
20523 :
20524 : // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20525 : // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20526 5 : CHECK_EQ(result1, 10946);
20527 5 : CHECK_EQ(result2, 144);
20528 5 : CHECK_EQ(result1, thread1.result());
20529 5 : CHECK_EQ(result2, thread2.result());
20530 5 : }
20531 :
20532 :
20533 23723 : TEST(IsolateDifferentContexts) {
20534 : v8::Isolate::CreateParams create_params;
20535 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20536 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20537 : Local<v8::Context> context;
20538 : {
20539 : v8::Isolate::Scope isolate_scope(isolate);
20540 10 : v8::HandleScope handle_scope(isolate);
20541 5 : context = v8::Context::New(isolate);
20542 : v8::Context::Scope context_scope(context);
20543 : Local<Value> v = CompileRun("2");
20544 5 : CHECK(v->IsNumber());
20545 10 : CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
20546 : }
20547 : {
20548 : v8::Isolate::Scope isolate_scope(isolate);
20549 10 : v8::HandleScope handle_scope(isolate);
20550 5 : context = v8::Context::New(isolate);
20551 : v8::Context::Scope context_scope(context);
20552 : Local<Value> v = CompileRun("22");
20553 5 : CHECK(v->IsNumber());
20554 10 : CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
20555 : }
20556 5 : isolate->Dispose();
20557 5 : }
20558 :
20559 25 : class InitDefaultIsolateThread : public v8::base::Thread {
20560 : public:
20561 : enum TestCase {
20562 : SetResourceConstraints,
20563 : SetFatalHandler,
20564 : SetCounterFunction,
20565 : SetCreateHistogramFunction,
20566 : SetAddHistogramSampleFunction
20567 : };
20568 :
20569 : explicit InitDefaultIsolateThread(TestCase testCase)
20570 : : Thread(Options("InitDefaultIsolateThread")),
20571 : testCase_(testCase),
20572 25 : result_(false) {}
20573 :
20574 25 : void Run() {
20575 : v8::Isolate::CreateParams create_params;
20576 25 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20577 25 : switch (testCase_) {
20578 : case SetResourceConstraints: {
20579 : create_params.constraints.set_max_semi_space_size_in_kb(1024);
20580 : create_params.constraints.set_max_old_space_size(6);
20581 : break;
20582 : }
20583 : default:
20584 : break;
20585 : }
20586 25 : v8::Isolate* isolate = v8::Isolate::New(create_params);
20587 25 : isolate->Enter();
20588 25 : switch (testCase_) {
20589 : case SetResourceConstraints:
20590 : // Already handled in pre-Isolate-creation block.
20591 : break;
20592 :
20593 : case SetFatalHandler:
20594 5 : isolate->SetFatalErrorHandler(nullptr);
20595 5 : break;
20596 :
20597 : case SetCounterFunction:
20598 5 : CcTest::isolate()->SetCounterFunction(nullptr);
20599 5 : break;
20600 :
20601 : case SetCreateHistogramFunction:
20602 5 : CcTest::isolate()->SetCreateHistogramFunction(nullptr);
20603 5 : break;
20604 :
20605 : case SetAddHistogramSampleFunction:
20606 5 : CcTest::isolate()->SetAddHistogramSampleFunction(nullptr);
20607 5 : break;
20608 : }
20609 25 : isolate->Exit();
20610 25 : isolate->Dispose();
20611 25 : result_ = true;
20612 25 : }
20613 :
20614 : bool result() { return result_; }
20615 :
20616 : private:
20617 : TestCase testCase_;
20618 : bool result_;
20619 : };
20620 :
20621 :
20622 25 : static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20623 : InitDefaultIsolateThread thread(testCase);
20624 25 : thread.Start();
20625 25 : thread.Join();
20626 25 : CHECK(thread.result());
20627 25 : }
20628 :
20629 :
20630 23723 : TEST(InitializeDefaultIsolateOnSecondaryThread1) {
20631 5 : InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20632 5 : }
20633 :
20634 :
20635 23723 : TEST(InitializeDefaultIsolateOnSecondaryThread2) {
20636 5 : InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20637 5 : }
20638 :
20639 :
20640 23723 : TEST(InitializeDefaultIsolateOnSecondaryThread3) {
20641 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20642 5 : }
20643 :
20644 :
20645 23723 : TEST(InitializeDefaultIsolateOnSecondaryThread4) {
20646 5 : InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20647 5 : }
20648 :
20649 :
20650 23723 : TEST(InitializeDefaultIsolateOnSecondaryThread5) {
20651 5 : InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20652 5 : }
20653 :
20654 :
20655 23723 : TEST(StringCheckMultipleContexts) {
20656 : const char* code =
20657 : "(function() { return \"a\".charAt(0); })()";
20658 :
20659 : {
20660 : // Run the code twice in the first context to initialize the call IC.
20661 5 : LocalContext context1;
20662 10 : v8::HandleScope scope(context1->GetIsolate());
20663 5 : ExpectString(code, "a");
20664 10 : ExpectString(code, "a");
20665 : }
20666 :
20667 : {
20668 : // Change the String.prototype in the second context and check
20669 : // that the right function gets called.
20670 5 : LocalContext context2;
20671 10 : v8::HandleScope scope(context2->GetIsolate());
20672 : CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20673 10 : ExpectString(code, "not a");
20674 : }
20675 5 : }
20676 :
20677 :
20678 23723 : TEST(NumberCheckMultipleContexts) {
20679 : const char* code =
20680 : "(function() { return (42).toString(); })()";
20681 :
20682 : {
20683 : // Run the code twice in the first context to initialize the call IC.
20684 5 : LocalContext context1;
20685 10 : v8::HandleScope scope(context1->GetIsolate());
20686 5 : ExpectString(code, "42");
20687 10 : ExpectString(code, "42");
20688 : }
20689 :
20690 : {
20691 : // Change the Number.prototype in the second context and check
20692 : // that the right function gets called.
20693 5 : LocalContext context2;
20694 10 : v8::HandleScope scope(context2->GetIsolate());
20695 : CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20696 10 : ExpectString(code, "not 42");
20697 : }
20698 5 : }
20699 :
20700 :
20701 23723 : TEST(BooleanCheckMultipleContexts) {
20702 : const char* code =
20703 : "(function() { return true.toString(); })()";
20704 :
20705 : {
20706 : // Run the code twice in the first context to initialize the call IC.
20707 5 : LocalContext context1;
20708 10 : v8::HandleScope scope(context1->GetIsolate());
20709 5 : ExpectString(code, "true");
20710 10 : ExpectString(code, "true");
20711 : }
20712 :
20713 : {
20714 : // Change the Boolean.prototype in the second context and check
20715 : // that the right function gets called.
20716 5 : LocalContext context2;
20717 10 : v8::HandleScope scope(context2->GetIsolate());
20718 : CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20719 10 : ExpectString(code, "");
20720 : }
20721 5 : }
20722 :
20723 :
20724 23723 : TEST(DontDeleteCellLoadIC) {
20725 : const char* function_code =
20726 : "function readCell() { while (true) { return cell; } }";
20727 :
20728 : {
20729 : // Run the code twice in the first context to initialize the load
20730 : // IC for a don't delete cell.
20731 5 : LocalContext context1;
20732 10 : v8::HandleScope scope(context1->GetIsolate());
20733 : CompileRun("var cell = \"first\";");
20734 5 : ExpectBoolean("delete cell", false);
20735 : CompileRun(function_code);
20736 5 : ExpectString("readCell()", "first");
20737 10 : ExpectString("readCell()", "first");
20738 : }
20739 :
20740 : {
20741 : // Use a deletable cell in the second context.
20742 5 : LocalContext context2;
20743 10 : v8::HandleScope scope(context2->GetIsolate());
20744 : CompileRun("cell = \"second\";");
20745 : CompileRun(function_code);
20746 5 : ExpectString("readCell()", "second");
20747 5 : ExpectBoolean("delete cell", true);
20748 : ExpectString("(function() {"
20749 : " try {"
20750 : " return readCell();"
20751 : " } catch(e) {"
20752 : " return e.toString();"
20753 : " }"
20754 : "})()",
20755 5 : "ReferenceError: cell is not defined");
20756 : CompileRun("cell = \"new_second\";");
20757 5 : CcTest::CollectAllGarbage();
20758 5 : ExpectString("readCell()", "new_second");
20759 10 : ExpectString("readCell()", "new_second");
20760 : }
20761 5 : }
20762 :
20763 :
20764 10 : class Visitor42 : public v8::PersistentHandleVisitor {
20765 : public:
20766 : explicit Visitor42(v8::Persistent<v8::Object>* object)
20767 10 : : counter_(0), object_(object) { }
20768 :
20769 10 : virtual void VisitPersistentHandle(Persistent<Value>* value,
20770 : uint16_t class_id) {
20771 10 : if (class_id != 42) return;
20772 10 : CHECK_EQ(42, value->WrapperClassId());
20773 10 : v8::Isolate* isolate = CcTest::isolate();
20774 10 : v8::HandleScope handle_scope(isolate);
20775 : v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20776 10 : v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
20777 10 : CHECK(handle->IsObject());
20778 20 : CHECK(Local<Object>::Cast(handle)
20779 : ->Equals(isolate->GetCurrentContext(), object)
20780 : .FromJust());
20781 10 : ++counter_;
20782 : }
20783 :
20784 : int counter_;
20785 : v8::Persistent<v8::Object>* object_;
20786 : };
20787 :
20788 :
20789 23723 : TEST(PersistentHandleVisitor) {
20790 5 : LocalContext context;
20791 5 : v8::Isolate* isolate = context->GetIsolate();
20792 10 : v8::HandleScope scope(isolate);
20793 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20794 5 : CHECK_EQ(0, object.WrapperClassId());
20795 : object.SetWrapperClassId(42);
20796 5 : CHECK_EQ(42, object.WrapperClassId());
20797 :
20798 : Visitor42 visitor(&object);
20799 5 : isolate->VisitHandlesWithClassIds(&visitor);
20800 5 : CHECK_EQ(1, visitor.counter_);
20801 :
20802 5 : object.Reset();
20803 5 : }
20804 :
20805 :
20806 23723 : TEST(WrapperClassId) {
20807 5 : LocalContext context;
20808 5 : v8::Isolate* isolate = context->GetIsolate();
20809 10 : v8::HandleScope scope(isolate);
20810 5 : v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20811 5 : CHECK_EQ(0, object.WrapperClassId());
20812 : object.SetWrapperClassId(65535);
20813 5 : CHECK_EQ(65535, object.WrapperClassId());
20814 5 : object.Reset();
20815 5 : }
20816 :
20817 :
20818 23723 : TEST(PersistentHandleInNewSpaceVisitor) {
20819 5 : LocalContext context;
20820 5 : v8::Isolate* isolate = context->GetIsolate();
20821 10 : v8::HandleScope scope(isolate);
20822 5 : v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
20823 5 : CHECK_EQ(0, object1.WrapperClassId());
20824 : object1.SetWrapperClassId(42);
20825 5 : CHECK_EQ(42, object1.WrapperClassId());
20826 :
20827 5 : CcTest::CollectAllGarbage();
20828 5 : CcTest::CollectAllGarbage();
20829 :
20830 5 : v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
20831 5 : CHECK_EQ(0, object2.WrapperClassId());
20832 : object2.SetWrapperClassId(42);
20833 5 : CHECK_EQ(42, object2.WrapperClassId());
20834 :
20835 : Visitor42 visitor(&object2);
20836 5 : isolate->VisitHandlesForPartialDependence(&visitor);
20837 5 : CHECK_EQ(1, visitor.counter_);
20838 :
20839 : object1.Reset();
20840 5 : object2.Reset();
20841 5 : }
20842 :
20843 :
20844 23723 : TEST(RegExp) {
20845 5 : LocalContext context;
20846 10 : v8::HandleScope scope(context->GetIsolate());
20847 :
20848 : v8::Local<v8::RegExp> re =
20849 5 : v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
20850 5 : .ToLocalChecked();
20851 5 : CHECK(re->IsRegExp());
20852 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
20853 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20854 :
20855 : re = v8::RegExp::New(context.local(), v8_str("bar"),
20856 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20857 5 : v8::RegExp::kGlobal))
20858 5 : .ToLocalChecked();
20859 5 : CHECK(re->IsRegExp());
20860 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
20861 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20862 : static_cast<int>(re->GetFlags()));
20863 :
20864 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20865 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20866 5 : v8::RegExp::kMultiline))
20867 5 : .ToLocalChecked();
20868 5 : CHECK(re->IsRegExp());
20869 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20870 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20871 : static_cast<int>(re->GetFlags()));
20872 :
20873 : re = v8::RegExp::New(context.local(), v8_str("baz"),
20874 : static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
20875 5 : v8::RegExp::kSticky))
20876 5 : .ToLocalChecked();
20877 5 : CHECK(re->IsRegExp());
20878 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20879 5 : CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
20880 : static_cast<int>(re->GetFlags()));
20881 :
20882 : re = CompileRun("/quux/").As<v8::RegExp>();
20883 5 : CHECK(re->IsRegExp());
20884 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20885 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20886 :
20887 : re = CompileRun("/quux/gm").As<v8::RegExp>();
20888 5 : CHECK(re->IsRegExp());
20889 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20890 5 : CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20891 : static_cast<int>(re->GetFlags()));
20892 :
20893 : // Override the RegExp constructor and check the API constructor
20894 : // still works.
20895 : CompileRun("RegExp = function() {}");
20896 :
20897 5 : re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
20898 5 : .ToLocalChecked();
20899 5 : CHECK(re->IsRegExp());
20900 20 : CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
20901 5 : CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20902 :
20903 : re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
20904 : static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20905 5 : v8::RegExp::kMultiline))
20906 5 : .ToLocalChecked();
20907 5 : CHECK(re->IsRegExp());
20908 20 : CHECK(
20909 : re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
20910 5 : CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20911 : static_cast<int>(re->GetFlags()));
20912 :
20913 25 : CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
20914 : ExpectTrue("re.test('FoobarbaZ')");
20915 :
20916 : // RegExps are objects on which you can set properties.
20917 : re->Set(context.local(), v8_str("property"),
20918 20 : v8::Integer::New(context->GetIsolate(), 32))
20919 10 : .FromJust();
20920 : v8::Local<v8::Value> value(CompileRun("re.property"));
20921 10 : CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
20922 :
20923 10 : v8::TryCatch try_catch(context->GetIsolate());
20924 10 : CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
20925 : .IsEmpty());
20926 5 : CHECK(try_catch.HasCaught());
20927 25 : CHECK(context->Global()
20928 : ->Set(context.local(), v8_str("ex"), try_catch.Exception())
20929 : .FromJust());
20930 5 : ExpectTrue("ex instanceof SyntaxError");
20931 5 : }
20932 :
20933 :
20934 23724 : THREADED_TEST(Equals) {
20935 6 : LocalContext localContext;
20936 12 : v8::HandleScope handleScope(localContext->GetIsolate());
20937 :
20938 6 : v8::Local<v8::Object> globalProxy = localContext->Global();
20939 6 : v8::Local<Value> global = globalProxy->GetPrototype();
20940 :
20941 6 : CHECK(global->StrictEquals(global));
20942 6 : CHECK(!global->StrictEquals(globalProxy));
20943 6 : CHECK(!globalProxy->StrictEquals(global));
20944 6 : CHECK(globalProxy->StrictEquals(globalProxy));
20945 :
20946 12 : CHECK(global->Equals(localContext.local(), global).FromJust());
20947 12 : CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
20948 12 : CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
20949 18 : CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
20950 6 : }
20951 :
20952 :
20953 5 : static void Getter(v8::Local<v8::Name> property,
20954 : const v8::PropertyCallbackInfo<v8::Value>& info) {
20955 5 : info.GetReturnValue().Set(v8_str("42!"));
20956 5 : }
20957 :
20958 :
20959 5 : static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20960 5 : v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
20961 : result->Set(info.GetIsolate()->GetCurrentContext(), 0,
20962 15 : v8_str("universalAnswer"))
20963 10 : .FromJust();
20964 : info.GetReturnValue().Set(result);
20965 5 : }
20966 :
20967 :
20968 23723 : TEST(NamedEnumeratorAndForIn) {
20969 5 : LocalContext context;
20970 5 : v8::Isolate* isolate = context->GetIsolate();
20971 10 : v8::HandleScope handle_scope(isolate);
20972 5 : v8::Context::Scope context_scope(context.local());
20973 :
20974 5 : v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20975 : tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
20976 5 : Getter, nullptr, nullptr, nullptr, Enumerator));
20977 30 : CHECK(context->Global()
20978 : ->Set(context.local(), v8_str("o"),
20979 : tmpl->NewInstance(context.local()).ToLocalChecked())
20980 : .FromJust());
20981 : v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
20982 : CompileRun("var result = []; for (var k in o) result.push(k); result"));
20983 5 : CHECK_EQ(1u, result->Length());
20984 20 : CHECK(v8_str("universalAnswer")
20985 : ->Equals(context.local(),
20986 : result->Get(context.local(), 0).ToLocalChecked())
20987 5 : .FromJust());
20988 5 : }
20989 :
20990 :
20991 23723 : TEST(DefinePropertyPostDetach) {
20992 5 : LocalContext context;
20993 10 : v8::HandleScope scope(context->GetIsolate());
20994 5 : v8::Local<v8::Object> proxy = context->Global();
20995 : v8::Local<v8::Function> define_property =
20996 : CompileRun(
20997 : "(function() {"
20998 : " Object.defineProperty("
20999 : " this,"
21000 : " 1,"
21001 : " { configurable: true, enumerable: true, value: 3 });"
21002 : "})")
21003 : .As<Function>();
21004 5 : context->DetachGlobal();
21005 15 : CHECK(define_property->Call(context.local(), proxy, 0, nullptr).IsEmpty());
21006 5 : }
21007 :
21008 :
21009 36 : static void InstallContextId(v8::Local<Context> context, int id) {
21010 : Context::Scope scope(context);
21011 144 : CHECK(CompileRun("Object.prototype")
21012 : .As<Object>()
21013 : ->Set(context, v8_str("context_id"),
21014 : v8::Integer::New(context->GetIsolate(), id))
21015 : .FromJust());
21016 36 : }
21017 :
21018 :
21019 126 : static void CheckContextId(v8::Local<Object> object, int expected) {
21020 126 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
21021 504 : CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
21022 : .ToLocalChecked()
21023 : ->Int32Value(context)
21024 : .FromJust());
21025 126 : }
21026 :
21027 :
21028 23724 : THREADED_TEST(CreationContext) {
21029 6 : v8::Isolate* isolate = CcTest::isolate();
21030 6 : HandleScope handle_scope(isolate);
21031 6 : Local<Context> context1 = Context::New(isolate);
21032 6 : InstallContextId(context1, 1);
21033 6 : Local<Context> context2 = Context::New(isolate);
21034 6 : InstallContextId(context2, 2);
21035 6 : Local<Context> context3 = Context::New(isolate);
21036 6 : InstallContextId(context3, 3);
21037 :
21038 6 : Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
21039 :
21040 : Local<Object> object1;
21041 : Local<Function> func1;
21042 : {
21043 : Context::Scope scope(context1);
21044 6 : object1 = Object::New(isolate);
21045 6 : func1 = tmpl->GetFunction(context1).ToLocalChecked();
21046 : }
21047 :
21048 : Local<Object> object2;
21049 : Local<Function> func2;
21050 : {
21051 : Context::Scope scope(context2);
21052 6 : object2 = Object::New(isolate);
21053 6 : func2 = tmpl->GetFunction(context2).ToLocalChecked();
21054 : }
21055 :
21056 : Local<Object> instance1;
21057 : Local<Object> instance2;
21058 :
21059 : {
21060 : Context::Scope scope(context3);
21061 : instance1 = func1->NewInstance(context3).ToLocalChecked();
21062 : instance2 = func2->NewInstance(context3).ToLocalChecked();
21063 : }
21064 :
21065 : {
21066 6 : Local<Context> other_context = Context::New(isolate);
21067 : Context::Scope scope(other_context);
21068 12 : CHECK(object1->CreationContext() == context1);
21069 6 : CheckContextId(object1, 1);
21070 12 : CHECK(func1->CreationContext() == context1);
21071 6 : CheckContextId(func1, 1);
21072 12 : CHECK(instance1->CreationContext() == context1);
21073 6 : CheckContextId(instance1, 1);
21074 12 : CHECK(object2->CreationContext() == context2);
21075 6 : CheckContextId(object2, 2);
21076 12 : CHECK(func2->CreationContext() == context2);
21077 6 : CheckContextId(func2, 2);
21078 12 : CHECK(instance2->CreationContext() == context2);
21079 6 : CheckContextId(instance2, 2);
21080 : }
21081 :
21082 : {
21083 : Context::Scope scope(context1);
21084 12 : CHECK(object1->CreationContext() == context1);
21085 6 : CheckContextId(object1, 1);
21086 12 : CHECK(func1->CreationContext() == context1);
21087 6 : CheckContextId(func1, 1);
21088 12 : CHECK(instance1->CreationContext() == context1);
21089 6 : CheckContextId(instance1, 1);
21090 12 : CHECK(object2->CreationContext() == context2);
21091 6 : CheckContextId(object2, 2);
21092 12 : CHECK(func2->CreationContext() == context2);
21093 6 : CheckContextId(func2, 2);
21094 12 : CHECK(instance2->CreationContext() == context2);
21095 6 : CheckContextId(instance2, 2);
21096 : }
21097 :
21098 : {
21099 : Context::Scope scope(context2);
21100 12 : CHECK(object1->CreationContext() == context1);
21101 6 : CheckContextId(object1, 1);
21102 12 : CHECK(func1->CreationContext() == context1);
21103 6 : CheckContextId(func1, 1);
21104 12 : CHECK(instance1->CreationContext() == context1);
21105 6 : CheckContextId(instance1, 1);
21106 12 : CHECK(object2->CreationContext() == context2);
21107 6 : CheckContextId(object2, 2);
21108 12 : CHECK(func2->CreationContext() == context2);
21109 6 : CheckContextId(func2, 2);
21110 12 : CHECK(instance2->CreationContext() == context2);
21111 6 : CheckContextId(instance2, 2);
21112 6 : }
21113 6 : }
21114 :
21115 :
21116 23724 : THREADED_TEST(CreationContextOfJsFunction) {
21117 6 : HandleScope handle_scope(CcTest::isolate());
21118 6 : Local<Context> context = Context::New(CcTest::isolate());
21119 6 : InstallContextId(context, 1);
21120 :
21121 : Local<Object> function;
21122 : {
21123 : Context::Scope scope(context);
21124 : function = CompileRun("function foo() {}; foo").As<Object>();
21125 : }
21126 :
21127 6 : Local<Context> other_context = Context::New(CcTest::isolate());
21128 : Context::Scope scope(other_context);
21129 12 : CHECK(function->CreationContext() == context);
21130 12 : CheckContextId(function, 1);
21131 6 : }
21132 :
21133 :
21134 23724 : THREADED_TEST(CreationContextOfJsBoundFunction) {
21135 6 : HandleScope handle_scope(CcTest::isolate());
21136 6 : Local<Context> context1 = Context::New(CcTest::isolate());
21137 6 : InstallContextId(context1, 1);
21138 6 : Local<Context> context2 = Context::New(CcTest::isolate());
21139 6 : InstallContextId(context2, 2);
21140 :
21141 : Local<Function> target_function;
21142 : {
21143 : Context::Scope scope(context1);
21144 : target_function = CompileRun("function foo() {}; foo").As<Function>();
21145 : }
21146 :
21147 : Local<Function> bound_function1, bound_function2;
21148 : {
21149 : Context::Scope scope(context2);
21150 24 : CHECK(context2->Global()
21151 : ->Set(context2, v8_str("foo"), target_function)
21152 : .FromJust());
21153 : bound_function1 = CompileRun("foo.bind(1)").As<Function>();
21154 : bound_function2 =
21155 : CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
21156 : }
21157 :
21158 6 : Local<Context> other_context = Context::New(CcTest::isolate());
21159 : Context::Scope scope(other_context);
21160 12 : CHECK(bound_function1->CreationContext() == context1);
21161 6 : CheckContextId(bound_function1, 1);
21162 12 : CHECK(bound_function2->CreationContext() == context1);
21163 12 : CheckContextId(bound_function2, 1);
21164 6 : }
21165 :
21166 :
21167 20 : void HasOwnPropertyIndexedPropertyGetter(
21168 : uint32_t index,
21169 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21170 20 : if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
21171 20 : }
21172 :
21173 :
21174 10 : void HasOwnPropertyNamedPropertyGetter(
21175 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21176 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21177 20 : .FromJust()) {
21178 5 : info.GetReturnValue().Set(v8_str("yes"));
21179 : }
21180 10 : }
21181 :
21182 :
21183 50 : void HasOwnPropertyIndexedPropertyQuery(
21184 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21185 50 : if (index == 42) info.GetReturnValue().Set(1);
21186 50 : }
21187 :
21188 :
21189 10 : void HasOwnPropertyNamedPropertyQuery(
21190 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21191 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21192 20 : .FromJust()) {
21193 : info.GetReturnValue().Set(1);
21194 : }
21195 10 : }
21196 :
21197 :
21198 10 : void HasOwnPropertyNamedPropertyQuery2(
21199 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21200 30 : if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
21201 20 : .FromJust()) {
21202 : info.GetReturnValue().Set(1);
21203 : }
21204 10 : }
21205 :
21206 0 : void HasOwnPropertyAccessorGetter(
21207 : Local<String> property,
21208 : const v8::PropertyCallbackInfo<v8::Value>& info) {
21209 0 : info.GetReturnValue().Set(v8_str("yes"));
21210 0 : }
21211 :
21212 5 : void HasOwnPropertyAccessorNameGetter(
21213 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21214 5 : info.GetReturnValue().Set(v8_str("yes"));
21215 5 : }
21216 :
21217 23723 : TEST(HasOwnProperty) {
21218 5 : LocalContext env;
21219 5 : v8::Isolate* isolate = env->GetIsolate();
21220 10 : v8::HandleScope scope(isolate);
21221 : { // Check normal properties and defined getters.
21222 : Local<Value> value = CompileRun(
21223 : "function Foo() {"
21224 : " this.foo = 11;"
21225 : " this.__defineGetter__('baz', function() { return 1; });"
21226 : "};"
21227 : "function Bar() { "
21228 : " this.bar = 13;"
21229 : " this.__defineGetter__('bla', function() { return 2; });"
21230 : "};"
21231 : "Bar.prototype = new Foo();"
21232 : "new Bar();");
21233 5 : CHECK(value->IsObject());
21234 5 : Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
21235 15 : CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
21236 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21237 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21238 15 : CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
21239 15 : CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
21240 15 : CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
21241 : }
21242 : { // Check named getter interceptors.
21243 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21244 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21245 5 : HasOwnPropertyNamedPropertyGetter));
21246 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21247 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21248 10 : CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
21249 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21250 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21251 : }
21252 : { // Check indexed getter interceptors.
21253 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21254 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21255 5 : HasOwnPropertyIndexedPropertyGetter));
21256 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21257 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21258 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
21259 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
21260 10 : CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
21261 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21262 : }
21263 : { // Check named query interceptors.
21264 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21265 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21266 5 : 0, 0, HasOwnPropertyNamedPropertyQuery));
21267 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21268 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21269 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21270 : }
21271 : { // Check indexed query interceptors.
21272 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21273 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21274 5 : 0, 0, HasOwnPropertyIndexedPropertyQuery));
21275 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21276 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
21277 10 : CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
21278 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
21279 10 : CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
21280 : }
21281 : { // Check callbacks.
21282 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21283 5 : templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21284 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21285 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21286 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21287 : }
21288 : { // Check that query wins on disagreement.
21289 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21290 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21291 : HasOwnPropertyNamedPropertyGetter, 0,
21292 5 : HasOwnPropertyNamedPropertyQuery2));
21293 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21294 15 : CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
21295 15 : CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
21296 : }
21297 : { // Check that non-internalized keys are handled correctly.
21298 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21299 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21300 5 : HasOwnPropertyAccessorNameGetter));
21301 5 : Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
21302 25 : env->Global()->Set(env.local(), v8_str("obj"), instance).FromJust();
21303 : const char* src =
21304 : "var dyn_string = 'this string ';"
21305 : "dyn_string += 'does not exist elsewhere';"
21306 : "({}).hasOwnProperty.call(obj, dyn_string)";
21307 15 : CHECK(CompileRun(src)->BooleanValue(env.local()).FromJust());
21308 5 : }
21309 5 : }
21310 :
21311 :
21312 23723 : TEST(IndexedInterceptorWithStringProto) {
21313 5 : v8::Isolate* isolate = CcTest::isolate();
21314 5 : v8::HandleScope scope(isolate);
21315 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21316 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21317 5 : nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
21318 10 : LocalContext context;
21319 30 : CHECK(context->Global()
21320 : ->Set(context.local(), v8_str("obj"),
21321 : templ->NewInstance(context.local()).ToLocalChecked())
21322 : .FromJust());
21323 : CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21324 : // These should be intercepted.
21325 15 : CHECK(CompileRun("42 in obj")->BooleanValue(context.local()).FromJust());
21326 15 : CHECK(CompileRun("'42' in obj")->BooleanValue(context.local()).FromJust());
21327 : // These should fall through to the String prototype.
21328 15 : CHECK(CompileRun("0 in obj")->BooleanValue(context.local()).FromJust());
21329 15 : CHECK(CompileRun("'0' in obj")->BooleanValue(context.local()).FromJust());
21330 : // And these should both fail.
21331 15 : CHECK(!CompileRun("32 in obj")->BooleanValue(context.local()).FromJust());
21332 20 : CHECK(!CompileRun("'32' in obj")->BooleanValue(context.local()).FromJust());
21333 5 : }
21334 :
21335 :
21336 18 : void CheckCodeGenerationAllowed() {
21337 18 : Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
21338 : Local<Value> result = CompileRun("eval('42')");
21339 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21340 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21341 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21342 : result = CompileRun("var f = new Function('return 42'); f()");
21343 36 : CHECK_EQ(42, result->Int32Value(context).FromJust());
21344 18 : }
21345 :
21346 :
21347 12 : void CheckCodeGenerationDisallowed() {
21348 12 : TryCatch try_catch(CcTest::isolate());
21349 :
21350 : Local<Value> result = CompileRun("eval('42')");
21351 12 : CHECK(result.IsEmpty());
21352 12 : CHECK(try_catch.HasCaught());
21353 12 : try_catch.Reset();
21354 :
21355 : result = CompileRun("(function(e) { return e('42'); })(eval)");
21356 12 : CHECK(result.IsEmpty());
21357 12 : CHECK(try_catch.HasCaught());
21358 12 : try_catch.Reset();
21359 :
21360 : result = CompileRun("var f = new Function('return 42'); f()");
21361 12 : CHECK(result.IsEmpty());
21362 12 : CHECK(try_catch.HasCaught());
21363 12 : }
21364 :
21365 : char first_fourty_bytes[41];
21366 :
21367 23 : bool CodeGenerationAllowed(Local<Context> context, Local<String> source) {
21368 23 : String::Utf8Value str(CcTest::isolate(), source);
21369 : size_t len = std::min(sizeof(first_fourty_bytes) - 1,
21370 46 : static_cast<size_t>(str.length()));
21371 23 : strncpy(first_fourty_bytes, *str, len);
21372 23 : first_fourty_bytes[len] = 0;
21373 23 : ApiTestFuzzer::Fuzz();
21374 23 : return true;
21375 : }
21376 :
21377 23 : bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) {
21378 23 : ApiTestFuzzer::Fuzz();
21379 23 : return false;
21380 : }
21381 :
21382 :
21383 23724 : THREADED_TEST(AllowCodeGenFromStrings) {
21384 6 : LocalContext context;
21385 12 : v8::HandleScope scope(context->GetIsolate());
21386 :
21387 : // eval and the Function constructor allowed by default.
21388 6 : CHECK(context->IsCodeGenerationFromStringsAllowed());
21389 6 : CheckCodeGenerationAllowed();
21390 :
21391 : // Disallow eval and the Function constructor.
21392 6 : context->AllowCodeGenerationFromStrings(false);
21393 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21394 6 : CheckCodeGenerationDisallowed();
21395 :
21396 : // Allow again.
21397 6 : context->AllowCodeGenerationFromStrings(true);
21398 6 : CheckCodeGenerationAllowed();
21399 :
21400 : // Disallow but setting a global callback that will allow the calls.
21401 6 : context->AllowCodeGenerationFromStrings(false);
21402 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21403 6 : &CodeGenerationAllowed);
21404 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21405 6 : CheckCodeGenerationAllowed();
21406 :
21407 : // Set a callback that disallows the code generation.
21408 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21409 6 : &CodeGenerationDisallowed);
21410 6 : CHECK(!context->IsCodeGenerationFromStringsAllowed());
21411 12 : CheckCodeGenerationDisallowed();
21412 6 : }
21413 :
21414 :
21415 23723 : TEST(SetErrorMessageForCodeGenFromStrings) {
21416 5 : LocalContext context;
21417 10 : v8::HandleScope scope(context->GetIsolate());
21418 10 : TryCatch try_catch(context->GetIsolate());
21419 :
21420 5 : Local<String> message = v8_str("Message");
21421 5 : Local<String> expected_message = v8_str("Uncaught EvalError: Message");
21422 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21423 5 : &CodeGenerationDisallowed);
21424 5 : context->AllowCodeGenerationFromStrings(false);
21425 5 : context->SetErrorMessageForCodeGenerationFromStrings(message);
21426 : Local<Value> result = CompileRun("eval('42')");
21427 5 : CHECK(result.IsEmpty());
21428 5 : CHECK(try_catch.HasCaught());
21429 10 : Local<String> actual_message = try_catch.Message()->Get();
21430 20 : CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
21431 5 : }
21432 :
21433 23723 : TEST(CaptureSourceForCodeGenFromStrings) {
21434 5 : LocalContext context;
21435 10 : v8::HandleScope scope(context->GetIsolate());
21436 10 : TryCatch try_catch(context->GetIsolate());
21437 :
21438 : context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21439 5 : &CodeGenerationAllowed);
21440 5 : context->AllowCodeGenerationFromStrings(false);
21441 : CompileRun("eval('42')");
21442 10 : CHECK(!strcmp(first_fourty_bytes, "42"));
21443 5 : }
21444 :
21445 6 : static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21446 6 : }
21447 :
21448 :
21449 23724 : THREADED_TEST(CallAPIFunctionOnNonObject) {
21450 6 : LocalContext context;
21451 6 : v8::Isolate* isolate = context->GetIsolate();
21452 12 : v8::HandleScope scope(isolate);
21453 : Local<FunctionTemplate> templ =
21454 6 : v8::FunctionTemplate::New(isolate, NonObjectThis);
21455 : Local<Function> function =
21456 12 : templ->GetFunction(context.local()).ToLocalChecked();
21457 30 : CHECK(context->Global()
21458 : ->Set(context.local(), v8_str("f"), function)
21459 : .FromJust());
21460 12 : TryCatch try_catch(isolate);
21461 6 : CompileRun("f.call(2)");
21462 6 : }
21463 :
21464 :
21465 : // Regression test for issue 1470.
21466 23724 : THREADED_TEST(ReadOnlyIndexedProperties) {
21467 6 : v8::Isolate* isolate = CcTest::isolate();
21468 6 : v8::HandleScope scope(isolate);
21469 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21470 :
21471 12 : LocalContext context;
21472 12 : Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
21473 30 : CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
21474 : obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
21475 24 : v8::ReadOnly)
21476 12 : .FromJust();
21477 24 : obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
21478 30 : CHECK(v8_str("DONT_CHANGE")
21479 : ->Equals(context.local(),
21480 : obj->Get(context.local(), v8_str("1")).ToLocalChecked())
21481 : .FromJust());
21482 : obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
21483 24 : v8::ReadOnly)
21484 12 : .FromJust();
21485 18 : obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
21486 24 : CHECK(v8_str("DONT_CHANGE")
21487 : ->Equals(context.local(),
21488 : obj->Get(context.local(), v8_num(2)).ToLocalChecked())
21489 : .FromJust());
21490 :
21491 : // Test non-smi case.
21492 : obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
21493 24 : v8_str("DONT_CHANGE"), v8::ReadOnly)
21494 12 : .FromJust();
21495 24 : obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
21496 30 : CHECK(v8_str("DONT_CHANGE")
21497 : ->Equals(context.local(),
21498 : obj->Get(context.local(), v8_str("2000000000"))
21499 : .ToLocalChecked())
21500 6 : .FromJust());
21501 6 : }
21502 :
21503 :
21504 12 : static int CountLiveMapsInMapCache(i::Context* context) {
21505 : i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
21506 : int length = map_cache->length();
21507 : int count = 0;
21508 1548 : for (int i = 0; i < length; i++) {
21509 : i::Object* value = map_cache->get(i);
21510 1548 : if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
21511 : }
21512 12 : return count;
21513 : }
21514 :
21515 :
21516 23724 : THREADED_TEST(Regress1516) {
21517 6 : LocalContext context;
21518 12 : v8::HandleScope scope(context->GetIsolate());
21519 :
21520 : // Object with 20 properties is not a common case, so it should be removed
21521 : // from the cache after GC.
21522 6 : { v8::HandleScope temp_scope(context->GetIsolate());
21523 : CompileRun(
21524 : "({"
21525 : "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21526 : "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21527 : "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21528 : "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21529 6 : "})");
21530 : }
21531 :
21532 6 : int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21533 6 : CHECK_LE(1, elements);
21534 :
21535 : // We have to abort incremental marking here to abandon black pages.
21536 6 : CcTest::CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
21537 :
21538 12 : CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21539 6 : }
21540 :
21541 :
21542 23724 : THREADED_TEST(Regress93759) {
21543 6 : v8::Isolate* isolate = CcTest::isolate();
21544 6 : HandleScope scope(isolate);
21545 :
21546 : // Template for object with security check.
21547 6 : Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21548 6 : no_proto_template->SetAccessCheckCallback(AccessAlwaysBlocked);
21549 :
21550 : // Templates for objects with hidden prototypes and possibly security check.
21551 : Local<FunctionTemplate> hidden_proto_template =
21552 6 : v8::FunctionTemplate::New(isolate);
21553 6 : hidden_proto_template->SetHiddenPrototype(true);
21554 :
21555 : Local<FunctionTemplate> protected_hidden_proto_template =
21556 6 : v8::FunctionTemplate::New(isolate);
21557 : protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallback(
21558 12 : AccessAlwaysBlocked);
21559 6 : protected_hidden_proto_template->SetHiddenPrototype(true);
21560 :
21561 : // Context for "foreign" objects used in test.
21562 6 : Local<Context> context = v8::Context::New(isolate);
21563 6 : context->Enter();
21564 :
21565 : // Plain object, no security check.
21566 6 : Local<Object> simple_object = Object::New(isolate);
21567 :
21568 : // Object with explicit security check.
21569 : Local<Object> protected_object =
21570 6 : no_proto_template->NewInstance(context).ToLocalChecked();
21571 :
21572 : // JSGlobalProxy object, always have security check.
21573 6 : Local<Object> proxy_object = context->Global();
21574 :
21575 : // Global object, the prototype of proxy_object. No security checks.
21576 : Local<Object> global_object =
21577 18 : proxy_object->GetPrototype()->ToObject(context).ToLocalChecked();
21578 :
21579 : // Hidden prototype without security check.
21580 : Local<Object> hidden_prototype = hidden_proto_template->GetFunction(context)
21581 6 : .ToLocalChecked()
21582 : ->NewInstance(context)
21583 : .ToLocalChecked();
21584 : Local<Object> object_with_hidden =
21585 6 : Object::New(isolate);
21586 12 : object_with_hidden->SetPrototype(context, hidden_prototype).FromJust();
21587 :
21588 6 : context->Exit();
21589 :
21590 12 : LocalContext context2;
21591 6 : v8::Local<v8::Object> global = context2->Global();
21592 :
21593 : // Setup global variables.
21594 18 : CHECK(global->Set(context2.local(), v8_str("simple"), simple_object)
21595 : .FromJust());
21596 18 : CHECK(global->Set(context2.local(), v8_str("protected"), protected_object)
21597 : .FromJust());
21598 18 : CHECK(global->Set(context2.local(), v8_str("global"), global_object)
21599 : .FromJust());
21600 18 : CHECK(
21601 : global->Set(context2.local(), v8_str("proxy"), proxy_object).FromJust());
21602 18 : CHECK(global->Set(context2.local(), v8_str("hidden"), object_with_hidden)
21603 : .FromJust());
21604 :
21605 : Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21606 12 : CHECK(result1->Equals(context2.local(), simple_object->GetPrototype())
21607 : .FromJust());
21608 :
21609 : Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21610 6 : CHECK(result2->IsNull());
21611 :
21612 : Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21613 12 : CHECK(result3->Equals(context2.local(), global_object->GetPrototype())
21614 : .FromJust());
21615 :
21616 : Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21617 6 : CHECK(result4->IsNull());
21618 :
21619 : Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21620 24 : CHECK(result5->Equals(context2.local(), object_with_hidden->GetPrototype()
21621 : ->ToObject(context2.local())
21622 : .ToLocalChecked()
21623 : ->GetPrototype())
21624 6 : .FromJust());
21625 6 : }
21626 :
21627 :
21628 84 : static void TestReceiver(Local<Value> expected_result,
21629 : Local<Value> expected_receiver,
21630 : const char* code) {
21631 : Local<Value> result = CompileRun(code);
21632 84 : Local<Context> context = CcTest::isolate()->GetCurrentContext();
21633 84 : CHECK(result->IsObject());
21634 252 : CHECK(expected_receiver
21635 : ->Equals(context,
21636 : result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
21637 : .FromJust());
21638 252 : CHECK(expected_result
21639 : ->Equals(context,
21640 : result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
21641 : .FromJust());
21642 84 : }
21643 :
21644 :
21645 23724 : THREADED_TEST(ForeignFunctionReceiver) {
21646 6 : v8::Isolate* isolate = CcTest::isolate();
21647 6 : HandleScope scope(isolate);
21648 :
21649 : // Create two contexts with different "id" properties ('i' and 'o').
21650 : // Call a function both from its own context and from a the foreign
21651 : // context, and see what "this" is bound to (returning both "this"
21652 : // and "this.id" for comparison).
21653 :
21654 6 : Local<Context> foreign_context = v8::Context::New(isolate);
21655 6 : foreign_context->Enter();
21656 : Local<Value> foreign_function =
21657 : CompileRun("function func() { return { 0: this.id, "
21658 : " 1: this, "
21659 : " toString: function() { "
21660 : " return this[0];"
21661 : " }"
21662 : " };"
21663 : "}"
21664 : "var id = 'i';"
21665 : "func;");
21666 6 : CHECK(foreign_function->IsFunction());
21667 6 : foreign_context->Exit();
21668 :
21669 12 : LocalContext context;
21670 :
21671 6 : Local<String> password = v8_str("Password");
21672 : // Don't get hit by security checks when accessing foreign_context's
21673 : // global receiver (aka. global proxy).
21674 6 : context->SetSecurityToken(password);
21675 6 : foreign_context->SetSecurityToken(password);
21676 :
21677 6 : Local<String> i = v8_str("i");
21678 6 : Local<String> o = v8_str("o");
21679 6 : Local<String> id = v8_str("id");
21680 :
21681 : CompileRun("function ownfunc() { return { 0: this.id, "
21682 : " 1: this, "
21683 : " toString: function() { "
21684 : " return this[0];"
21685 : " }"
21686 : " };"
21687 : "}"
21688 : "var id = 'o';"
21689 : "ownfunc");
21690 30 : CHECK(context->Global()
21691 : ->Set(context.local(), v8_str("func"), foreign_function)
21692 : .FromJust());
21693 :
21694 : // Sanity check the contexts.
21695 24 : CHECK(
21696 : i->Equals(
21697 : context.local(),
21698 : foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
21699 : .FromJust());
21700 30 : CHECK(o->Equals(context.local(),
21701 : context->Global()->Get(context.local(), id).ToLocalChecked())
21702 : .FromJust());
21703 :
21704 : // Checking local function's receiver.
21705 : // Calling function using its call/apply methods.
21706 12 : TestReceiver(o, context->Global(), "ownfunc.call()");
21707 12 : TestReceiver(o, context->Global(), "ownfunc.apply()");
21708 : // Making calls through built-in functions.
21709 12 : TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21710 12 : CHECK(
21711 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
21712 : .FromJust());
21713 12 : CHECK(
21714 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
21715 : .FromJust());
21716 12 : CHECK(
21717 : o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
21718 : .FromJust());
21719 : // Calling with environment record as base.
21720 12 : TestReceiver(o, context->Global(), "ownfunc()");
21721 : // Calling with no base.
21722 12 : TestReceiver(o, context->Global(), "(1,ownfunc)()");
21723 :
21724 : // Checking foreign function return value.
21725 : // Calling function using its call/apply methods.
21726 12 : TestReceiver(i, foreign_context->Global(), "func.call()");
21727 12 : TestReceiver(i, foreign_context->Global(), "func.apply()");
21728 : // Calling function using another context's call/apply methods.
21729 : TestReceiver(i, foreign_context->Global(),
21730 12 : "Function.prototype.call.call(func)");
21731 : TestReceiver(i, foreign_context->Global(),
21732 12 : "Function.prototype.call.apply(func)");
21733 : TestReceiver(i, foreign_context->Global(),
21734 12 : "Function.prototype.apply.call(func)");
21735 : TestReceiver(i, foreign_context->Global(),
21736 12 : "Function.prototype.apply.apply(func)");
21737 : // Making calls through built-in functions.
21738 12 : TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21739 : // ToString(func()) is func()[0], i.e., the returned this.id.
21740 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
21741 : .FromJust());
21742 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
21743 : .FromJust());
21744 12 : CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
21745 : .FromJust());
21746 :
21747 : // Calling with environment record as base.
21748 12 : TestReceiver(i, foreign_context->Global(), "func()");
21749 : // Calling with no base.
21750 18 : TestReceiver(i, foreign_context->Global(), "(1,func)()");
21751 6 : }
21752 :
21753 :
21754 : uint8_t callback_fired = 0;
21755 : uint8_t before_call_entered_callback_count1 = 0;
21756 : uint8_t before_call_entered_callback_count2 = 0;
21757 :
21758 :
21759 5 : void CallCompletedCallback1(v8::Isolate*) {
21760 5 : v8::base::OS::Print("Firing callback 1.\n");
21761 5 : callback_fired ^= 1; // Toggle first bit.
21762 5 : }
21763 :
21764 :
21765 15 : void CallCompletedCallback2(v8::Isolate*) {
21766 15 : v8::base::OS::Print("Firing callback 2.\n");
21767 15 : callback_fired ^= 2; // Toggle second bit.
21768 15 : }
21769 :
21770 :
21771 20 : void BeforeCallEnteredCallback1(v8::Isolate*) {
21772 20 : v8::base::OS::Print("Firing before call entered callback 1.\n");
21773 20 : before_call_entered_callback_count1++;
21774 20 : }
21775 :
21776 :
21777 60 : void BeforeCallEnteredCallback2(v8::Isolate*) {
21778 60 : v8::base::OS::Print("Firing before call entered callback 2.\n");
21779 60 : before_call_entered_callback_count2++;
21780 60 : }
21781 :
21782 :
21783 60 : void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21784 : int32_t level =
21785 180 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
21786 60 : if (level < 3) {
21787 45 : level++;
21788 45 : v8::base::OS::Print("Entering recursion level %d.\n", level);
21789 : char script[64];
21790 : i::Vector<char> script_vector(script, sizeof(script));
21791 45 : i::SNPrintF(script_vector, "recursion(%d)", level);
21792 : CompileRun(script_vector.start());
21793 45 : v8::base::OS::Print("Leaving recursion level %d.\n", level);
21794 90 : CHECK_EQ(0, callback_fired);
21795 : } else {
21796 15 : v8::base::OS::Print("Recursion ends.\n");
21797 30 : CHECK_EQ(0, callback_fired);
21798 : }
21799 60 : }
21800 :
21801 :
21802 23723 : TEST(CallCompletedCallback) {
21803 5 : LocalContext env;
21804 10 : v8::HandleScope scope(env->GetIsolate());
21805 : v8::Local<v8::FunctionTemplate> recursive_runtime =
21806 5 : v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21807 : env->Global()
21808 : ->Set(env.local(), v8_str("recursion"),
21809 30 : recursive_runtime->GetFunction(env.local()).ToLocalChecked())
21810 10 : .FromJust();
21811 : // Adding the same callback a second time has no effect.
21812 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21813 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21814 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21815 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21816 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
21817 5 : env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21818 5 : v8::base::OS::Print("--- Script (1) ---\n");
21819 5 : callback_fired = 0;
21820 5 : before_call_entered_callback_count1 = 0;
21821 5 : before_call_entered_callback_count2 = 0;
21822 : Local<Script> script =
21823 5 : v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
21824 5 : script->Run(env.local()).ToLocalChecked();
21825 10 : CHECK_EQ(3, callback_fired);
21826 10 : CHECK_EQ(4, before_call_entered_callback_count1);
21827 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21828 :
21829 5 : v8::base::OS::Print("\n--- Script (2) ---\n");
21830 5 : callback_fired = 0;
21831 5 : before_call_entered_callback_count1 = 0;
21832 5 : before_call_entered_callback_count2 = 0;
21833 5 : env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21834 : env->GetIsolate()->RemoveBeforeCallEnteredCallback(
21835 5 : BeforeCallEnteredCallback1);
21836 5 : script->Run(env.local()).ToLocalChecked();
21837 10 : CHECK_EQ(2, callback_fired);
21838 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21839 10 : CHECK_EQ(4, before_call_entered_callback_count2);
21840 :
21841 5 : v8::base::OS::Print("\n--- Function ---\n");
21842 5 : callback_fired = 0;
21843 5 : before_call_entered_callback_count1 = 0;
21844 5 : before_call_entered_callback_count2 = 0;
21845 : Local<Function> recursive_function = Local<Function>::Cast(
21846 25 : env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
21847 5 : v8::Local<Value> args[] = {v8_num(0)};
21848 15 : recursive_function->Call(env.local(), env->Global(), 1, args)
21849 5 : .ToLocalChecked();
21850 10 : CHECK_EQ(2, callback_fired);
21851 10 : CHECK_EQ(0, before_call_entered_callback_count1);
21852 15 : CHECK_EQ(4, before_call_entered_callback_count2);
21853 5 : }
21854 :
21855 :
21856 5 : void CallCompletedCallbackNoException(v8::Isolate*) {
21857 5 : v8::HandleScope scope(CcTest::isolate());
21858 5 : CompileRun("1+1;");
21859 5 : }
21860 :
21861 :
21862 5 : void CallCompletedCallbackException(v8::Isolate*) {
21863 5 : v8::HandleScope scope(CcTest::isolate());
21864 5 : CompileRun("throw 'second exception';");
21865 5 : }
21866 :
21867 :
21868 23723 : TEST(CallCompletedCallbackOneException) {
21869 5 : LocalContext env;
21870 10 : v8::HandleScope scope(env->GetIsolate());
21871 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21872 5 : CompileRun("throw 'exception';");
21873 5 : }
21874 :
21875 :
21876 23723 : TEST(CallCompletedCallbackTwoExceptions) {
21877 5 : LocalContext env;
21878 10 : v8::HandleScope scope(env->GetIsolate());
21879 5 : env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21880 5 : CompileRun("throw 'first exception';");
21881 5 : }
21882 :
21883 :
21884 135 : static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21885 45 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21886 45 : v8::HandleScope scope(info.GetIsolate());
21887 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21888 90 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21889 45 : CompileRun("ext1Calls++;");
21890 45 : }
21891 :
21892 :
21893 150 : static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21894 50 : CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21895 50 : v8::HandleScope scope(info.GetIsolate());
21896 : v8::MicrotasksScope microtasks(info.GetIsolate(),
21897 100 : v8::MicrotasksScope::kDoNotRunMicrotasks);
21898 50 : CompileRun("ext2Calls++;");
21899 50 : }
21900 :
21901 : void* g_passed_to_three = nullptr;
21902 :
21903 10 : static void MicrotaskThree(void* data) {
21904 10 : g_passed_to_three = data;
21905 10 : }
21906 :
21907 :
21908 23723 : TEST(EnqueueMicrotask) {
21909 5 : LocalContext env;
21910 10 : v8::HandleScope scope(env->GetIsolate());
21911 5 : CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
21912 : CompileRun(
21913 : "var ext1Calls = 0;"
21914 : "var ext2Calls = 0;");
21915 : CompileRun("1+1;");
21916 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21917 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21918 :
21919 : env->GetIsolate()->EnqueueMicrotask(
21920 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21921 : CompileRun("1+1;");
21922 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21923 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21924 :
21925 : env->GetIsolate()->EnqueueMicrotask(
21926 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21927 : env->GetIsolate()->EnqueueMicrotask(
21928 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21929 : CompileRun("1+1;");
21930 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21931 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21932 :
21933 : env->GetIsolate()->EnqueueMicrotask(
21934 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21935 : CompileRun("1+1;");
21936 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21937 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21938 :
21939 : CompileRun("1+1;");
21940 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21941 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21942 :
21943 5 : g_passed_to_three = nullptr;
21944 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21945 : CompileRun("1+1;");
21946 5 : CHECK(!g_passed_to_three);
21947 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21948 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21949 :
21950 : int dummy;
21951 : env->GetIsolate()->EnqueueMicrotask(
21952 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21953 5 : env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21954 : env->GetIsolate()->EnqueueMicrotask(
21955 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21956 : CompileRun("1+1;");
21957 5 : CHECK_EQ(&dummy, g_passed_to_three);
21958 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21959 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21960 10 : g_passed_to_three = nullptr;
21961 5 : }
21962 :
21963 :
21964 5 : static void MicrotaskExceptionOne(
21965 10 : const v8::FunctionCallbackInfo<Value>& info) {
21966 5 : v8::HandleScope scope(info.GetIsolate());
21967 : CompileRun("exception1Calls++;");
21968 : info.GetIsolate()->ThrowException(
21969 10 : v8::Exception::Error(v8_str("first")));
21970 5 : }
21971 :
21972 :
21973 5 : static void MicrotaskExceptionTwo(
21974 10 : const v8::FunctionCallbackInfo<Value>& info) {
21975 5 : v8::HandleScope scope(info.GetIsolate());
21976 : CompileRun("exception2Calls++;");
21977 : info.GetIsolate()->ThrowException(
21978 10 : v8::Exception::Error(v8_str("second")));
21979 5 : }
21980 :
21981 :
21982 23723 : TEST(RunMicrotasksIgnoresThrownExceptions) {
21983 5 : LocalContext env;
21984 5 : v8::Isolate* isolate = env->GetIsolate();
21985 10 : v8::HandleScope scope(isolate);
21986 : CompileRun(
21987 : "var exception1Calls = 0;"
21988 : "var exception2Calls = 0;");
21989 : isolate->EnqueueMicrotask(
21990 10 : Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
21991 : isolate->EnqueueMicrotask(
21992 10 : Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
21993 10 : TryCatch try_catch(isolate);
21994 : CompileRun("1+1;");
21995 5 : CHECK(!try_catch.HasCaught());
21996 15 : CHECK_EQ(1,
21997 : CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
21998 15 : CHECK_EQ(1,
21999 5 : CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
22000 5 : }
22001 :
22002 :
22003 : uint8_t microtasks_completed_callback_count = 0;
22004 :
22005 :
22006 25 : static void MicrotasksCompletedCallback(v8::Isolate* isolate) {
22007 25 : ++microtasks_completed_callback_count;
22008 25 : }
22009 :
22010 :
22011 23723 : TEST(SetAutorunMicrotasks) {
22012 5 : LocalContext env;
22013 10 : v8::HandleScope scope(env->GetIsolate());
22014 : env->GetIsolate()->AddMicrotasksCompletedCallback(
22015 5 : &MicrotasksCompletedCallback);
22016 : CompileRun(
22017 : "var ext1Calls = 0;"
22018 : "var ext2Calls = 0;");
22019 : CompileRun("1+1;");
22020 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22021 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22022 5 : CHECK_EQ(0u, microtasks_completed_callback_count);
22023 :
22024 : env->GetIsolate()->EnqueueMicrotask(
22025 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22026 : CompileRun("1+1;");
22027 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22028 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22029 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
22030 :
22031 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
22032 : env->GetIsolate()->EnqueueMicrotask(
22033 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22034 : env->GetIsolate()->EnqueueMicrotask(
22035 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22036 : CompileRun("1+1;");
22037 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22038 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22039 5 : CHECK_EQ(1u, microtasks_completed_callback_count);
22040 :
22041 5 : env->GetIsolate()->RunMicrotasks();
22042 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22043 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22044 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
22045 :
22046 : env->GetIsolate()->EnqueueMicrotask(
22047 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22048 : CompileRun("1+1;");
22049 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22050 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22051 5 : CHECK_EQ(2u, microtasks_completed_callback_count);
22052 :
22053 5 : env->GetIsolate()->RunMicrotasks();
22054 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22055 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22056 5 : CHECK_EQ(3u, microtasks_completed_callback_count);
22057 :
22058 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22059 : env->GetIsolate()->EnqueueMicrotask(
22060 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22061 : CompileRun("1+1;");
22062 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22063 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22064 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
22065 :
22066 : env->GetIsolate()->EnqueueMicrotask(
22067 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22068 : {
22069 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
22070 : CompileRun("1+1;");
22071 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22072 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22073 5 : CHECK_EQ(4u, microtasks_completed_callback_count);
22074 : }
22075 :
22076 : CompileRun("1+1;");
22077 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22078 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22079 5 : CHECK_EQ(5u, microtasks_completed_callback_count);
22080 :
22081 : env->GetIsolate()->RemoveMicrotasksCompletedCallback(
22082 5 : &MicrotasksCompletedCallback);
22083 : env->GetIsolate()->EnqueueMicrotask(
22084 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22085 : CompileRun("1+1;");
22086 15 : CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22087 15 : CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22088 10 : CHECK_EQ(5u, microtasks_completed_callback_count);
22089 5 : }
22090 :
22091 :
22092 23723 : TEST(RunMicrotasksWithoutEnteringContext) {
22093 5 : v8::Isolate* isolate = CcTest::isolate();
22094 5 : HandleScope handle_scope(isolate);
22095 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
22096 5 : Local<Context> context = Context::New(isolate);
22097 : {
22098 : Context::Scope context_scope(context);
22099 : CompileRun("var ext1Calls = 0;");
22100 : isolate->EnqueueMicrotask(
22101 10 : Function::New(context, MicrotaskOne).ToLocalChecked());
22102 : }
22103 5 : isolate->RunMicrotasks();
22104 : {
22105 : Context::Scope context_scope(context);
22106 10 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
22107 : }
22108 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22109 5 : }
22110 :
22111 :
22112 23723 : TEST(ScopedMicrotasks) {
22113 5 : LocalContext env;
22114 10 : v8::HandleScope handles(env->GetIsolate());
22115 5 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
22116 : {
22117 : v8::MicrotasksScope scope1(env->GetIsolate(),
22118 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22119 : env->GetIsolate()->EnqueueMicrotask(
22120 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22121 : CompileRun(
22122 : "var ext1Calls = 0;"
22123 : "var ext2Calls = 0;");
22124 : CompileRun("1+1;");
22125 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22126 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22127 : {
22128 : v8::MicrotasksScope scope2(env->GetIsolate(),
22129 5 : v8::MicrotasksScope::kRunMicrotasks);
22130 : CompileRun("1+1;");
22131 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22132 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22133 : {
22134 : v8::MicrotasksScope scope3(env->GetIsolate(),
22135 5 : v8::MicrotasksScope::kRunMicrotasks);
22136 : CompileRun("1+1;");
22137 15 : CHECK_EQ(0,
22138 : CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22139 15 : CHECK_EQ(0,
22140 5 : CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22141 : }
22142 15 : CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22143 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22144 : }
22145 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22146 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22147 : env->GetIsolate()->EnqueueMicrotask(
22148 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22149 : }
22150 :
22151 : {
22152 : v8::MicrotasksScope scope(env->GetIsolate(),
22153 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22154 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22155 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22156 : }
22157 :
22158 : {
22159 : v8::MicrotasksScope scope1(env->GetIsolate(),
22160 5 : v8::MicrotasksScope::kRunMicrotasks);
22161 : CompileRun("1+1;");
22162 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22163 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22164 : {
22165 : v8::MicrotasksScope scope2(env->GetIsolate(),
22166 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22167 : }
22168 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22169 15 : CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22170 : }
22171 :
22172 : {
22173 : v8::MicrotasksScope scope(env->GetIsolate(),
22174 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22175 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22176 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22177 : env->GetIsolate()->EnqueueMicrotask(
22178 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22179 : }
22180 :
22181 : {
22182 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
22183 : {
22184 : v8::MicrotasksScope scope2(env->GetIsolate(),
22185 5 : v8::MicrotasksScope::kRunMicrotasks);
22186 : }
22187 : v8::MicrotasksScope scope3(env->GetIsolate(),
22188 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22189 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22190 20 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22191 : }
22192 :
22193 : {
22194 : v8::MicrotasksScope scope1(env->GetIsolate(),
22195 5 : v8::MicrotasksScope::kRunMicrotasks);
22196 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22197 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22198 15 : CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22199 : }
22200 :
22201 : {
22202 : v8::MicrotasksScope scope(env->GetIsolate(),
22203 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22204 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22205 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22206 : }
22207 :
22208 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22209 :
22210 : {
22211 : v8::MicrotasksScope scope(env->GetIsolate(),
22212 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22213 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22214 15 : CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22215 : env->GetIsolate()->EnqueueMicrotask(
22216 10 : Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
22217 : }
22218 :
22219 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22220 :
22221 : {
22222 : v8::MicrotasksScope scope(env->GetIsolate(),
22223 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22224 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22225 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22226 : }
22227 :
22228 : env->GetIsolate()->EnqueueMicrotask(
22229 10 : Function::New(env.local(), MicrotaskOne).ToLocalChecked());
22230 : {
22231 5 : v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
22232 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22233 : v8::MicrotasksScope scope2(env->GetIsolate(),
22234 10 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22235 15 : CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22236 20 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22237 : }
22238 :
22239 5 : v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
22240 :
22241 : {
22242 : v8::MicrotasksScope scope(env->GetIsolate(),
22243 5 : v8::MicrotasksScope::kDoNotRunMicrotasks);
22244 15 : CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
22245 15 : CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
22246 : }
22247 :
22248 10 : env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
22249 5 : }
22250 :
22251 : namespace {
22252 :
22253 : int probes_counter = 0;
22254 : int misses_counter = 0;
22255 : int updates_counter = 0;
22256 :
22257 0 : int* LookupCounter(const char* name) {
22258 0 : if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
22259 : return &probes_counter;
22260 0 : } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
22261 : return &misses_counter;
22262 0 : } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
22263 : return &updates_counter;
22264 : }
22265 0 : return nullptr;
22266 : }
22267 :
22268 : template <typename Stub, typename... Args>
22269 : void Recompile(Args... args) {
22270 : Stub stub(args...);
22271 : stub.DeleteStubFromCacheForTesting();
22272 : stub.GetCode();
22273 : }
22274 :
22275 : void RecompileICStubs(i::Isolate* isolate) {
22276 : // BUG(5784): We had a list of IC stubs here to recompile. These are now
22277 : // builtins and we can't compile them again (easily). Bug 5784 tracks
22278 : // our progress in finding another way to do this.
22279 : }
22280 :
22281 : } // namespace
22282 :
22283 : #ifdef ENABLE_DISASSEMBLER
22284 : // FLAG_test_primary_stub_cache and FLAG_test_secondary_stub_cache are read
22285 : // only when ENABLE_DISASSEMBLER is not defined.
22286 :
22287 : namespace {
22288 :
22289 : const char* kMegamorphicTestProgram =
22290 : "function CreateClass(name) {\n"
22291 : " var src = \n"
22292 : // Disable constant tracking of "a" field by assigning different Smi values
22293 : // twice to ease megamorphic probes counting.
22294 : " ` function ${name}() { this.a = 0; this.a = 1; };` +\n"
22295 : " ` ${name}.prototype.foo = function() {};` +\n"
22296 : " ` ${name};\\n`;\n"
22297 : " return (0, eval)(src);\n"
22298 : "}\n"
22299 : "function trigger_ics(obj, v) {\n"
22300 : " obj.foo();\n"
22301 : " obj.a = v;\n"
22302 : "};\n"
22303 : "var objs = [];\n"
22304 : "for (var i = 0; i < 50; i++) {\n"
22305 : " var Class = CreateClass('Class' + i);\n"
22306 : " var obj = new Class();\n"
22307 : " objs.push(obj);\n"
22308 : "}\n"
22309 : "for (var i = 0; i < 1000; i++) {\n"
22310 : " for (var obj of objs) {\n"
22311 : " trigger_ics(obj, 1);\n"
22312 : " }\n"
22313 : "}\n";
22314 :
22315 : void TestStubCache(bool primary) {
22316 : i::FLAG_native_code_counters = true;
22317 : if (primary) {
22318 : i::FLAG_test_primary_stub_cache = true;
22319 : } else {
22320 : i::FLAG_test_secondary_stub_cache = true;
22321 : }
22322 : i::FLAG_opt = false;
22323 :
22324 : v8::Isolate::CreateParams create_params;
22325 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
22326 : create_params.counter_lookup_callback = LookupCounter;
22327 : v8::Isolate* isolate = v8::Isolate::New(create_params);
22328 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22329 :
22330 : {
22331 : v8::Isolate::Scope isolate_scope(isolate);
22332 : LocalContext env(isolate);
22333 : v8::HandleScope scope(isolate);
22334 :
22335 : // Enforce recompilation of IC stubs that access megamorphic stub cache
22336 : // to respect enabled native code counters and stub cache test flags.
22337 : RecompileICStubs(i_isolate);
22338 :
22339 : int initial_probes = probes_counter;
22340 : int initial_misses = misses_counter;
22341 : int initial_updates = updates_counter;
22342 : CompileRun(kMegamorphicTestProgram);
22343 : int probes = probes_counter - initial_probes;
22344 : int misses = misses_counter - initial_misses;
22345 : int updates = updates_counter - initial_updates;
22346 : const int kClassesCount = 50;
22347 : const int kIterationsCount = 1000;
22348 : const int kICKinds = 2; // LoadIC and StoreIC
22349 : CHECK_LE(kClassesCount * kICKinds, updates);
22350 : // Check that updates and misses counts are bounded.
22351 : // If there are too many updates then most likely the stub cache does not
22352 : // work properly.
22353 : CHECK_LE(updates, kClassesCount * 2 * kICKinds);
22354 : CHECK_LE(kICKinds, misses);
22355 : CHECK_LE(misses, kClassesCount * 2 * kICKinds);
22356 : // 2 is for PREMONOMORPHIC and MONOMORPHIC states,
22357 : // 4 is for POLYMORPHIC states,
22358 : // and all the others probes are for MEGAMORPHIC state.
22359 : CHECK_EQ((kIterationsCount * kClassesCount - 2 - 4) * kICKinds, probes);
22360 : }
22361 : isolate->Dispose();
22362 : }
22363 :
22364 : } // namespace
22365 :
22366 : UNINITIALIZED_TEST(PrimaryStubCache) {
22367 : TestStubCache(true);
22368 : }
22369 :
22370 : UNINITIALIZED_TEST(SecondaryStubCache) {
22371 : TestStubCache(false);
22372 : }
22373 :
22374 : #endif // ENABLE_DISASSEMBLER
22375 :
22376 : namespace {
22377 :
22378 35 : void AssertCowElements(bool expected, const char* source) {
22379 : Local<Value> object = CompileRun(source);
22380 : i::Handle<i::JSObject> array =
22381 : i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*object.As<Object>()));
22382 35 : CHECK_EQ(expected, array->elements()->IsCowArray());
22383 35 : }
22384 :
22385 : } // namespace
22386 :
22387 23723 : TEST(CheckCOWArraysCreatedRuntimeCounter) {
22388 5 : LocalContext env;
22389 10 : v8::HandleScope scope(env->GetIsolate());
22390 5 : AssertCowElements(true, "[1, 2, 3]");
22391 5 : AssertCowElements(false, "[[1], 2, 3]");
22392 5 : AssertCowElements(true, "[[1], 2, 3][0]");
22393 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.foo)");
22394 5 : AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.bar)");
22395 5 : AssertCowElements(false, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo)");
22396 10 : AssertCowElements(true, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo[3])");
22397 5 : }
22398 :
22399 :
22400 23723 : TEST(StaticGetters) {
22401 5 : LocalContext context;
22402 : i::Factory* factory = CcTest::i_isolate()->factory();
22403 5 : v8::Isolate* isolate = CcTest::isolate();
22404 10 : v8::HandleScope scope(isolate);
22405 : i::Handle<i::Object> undefined_value = factory->undefined_value();
22406 5 : CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
22407 : i::Handle<i::Object> null_value = factory->null_value();
22408 5 : CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
22409 : i::Handle<i::Object> true_value = factory->true_value();
22410 5 : CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
22411 : i::Handle<i::Object> false_value = factory->false_value();
22412 10 : CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
22413 5 : }
22414 :
22415 :
22416 23723 : UNINITIALIZED_TEST(IsolateEmbedderData) {
22417 5 : CcTest::DisableAutomaticDispose();
22418 : v8::Isolate::CreateParams create_params;
22419 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
22420 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
22421 5 : isolate->Enter();
22422 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22423 25 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22424 20 : CHECK(!isolate->GetData(slot));
22425 20 : CHECK(!i_isolate->GetData(slot));
22426 : }
22427 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22428 20 : void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22429 : isolate->SetData(slot, data);
22430 : }
22431 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22432 20 : void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22433 20 : CHECK_EQ(data, isolate->GetData(slot));
22434 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22435 : }
22436 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22437 20 : void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22438 : isolate->SetData(slot, data);
22439 : }
22440 20 : for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22441 20 : void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22442 20 : CHECK_EQ(data, isolate->GetData(slot));
22443 20 : CHECK_EQ(data, i_isolate->GetData(slot));
22444 : }
22445 5 : isolate->Exit();
22446 5 : isolate->Dispose();
22447 5 : }
22448 :
22449 :
22450 23723 : TEST(StringEmpty) {
22451 5 : LocalContext context;
22452 : i::Factory* factory = CcTest::i_isolate()->factory();
22453 5 : v8::Isolate* isolate = CcTest::isolate();
22454 10 : v8::HandleScope scope(isolate);
22455 : i::Handle<i::Object> empty_string = factory->empty_string();
22456 10 : CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22457 5 : }
22458 :
22459 :
22460 : static int instance_checked_getter_count = 0;
22461 120 : static void InstanceCheckedGetter(
22462 : Local<String> name,
22463 : const v8::PropertyCallbackInfo<v8::Value>& info) {
22464 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22465 : .FromJust());
22466 120 : instance_checked_getter_count++;
22467 120 : info.GetReturnValue().Set(v8_num(11));
22468 120 : }
22469 :
22470 :
22471 : static int instance_checked_setter_count = 0;
22472 120 : static void InstanceCheckedSetter(Local<String> name,
22473 : Local<Value> value,
22474 : const v8::PropertyCallbackInfo<void>& info) {
22475 480 : CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
22476 : .FromJust());
22477 480 : CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
22478 : .FromJust());
22479 120 : instance_checked_setter_count++;
22480 120 : }
22481 :
22482 :
22483 420 : static void CheckInstanceCheckedResult(int getters, int setters,
22484 : bool expects_callbacks,
22485 : TryCatch* try_catch) {
22486 420 : if (expects_callbacks) {
22487 240 : CHECK(!try_catch->HasCaught());
22488 240 : CHECK_EQ(getters, instance_checked_getter_count);
22489 240 : CHECK_EQ(setters, instance_checked_setter_count);
22490 : } else {
22491 180 : CHECK(try_catch->HasCaught());
22492 180 : CHECK_EQ(0, instance_checked_getter_count);
22493 180 : CHECK_EQ(0, instance_checked_setter_count);
22494 : }
22495 420 : try_catch->Reset();
22496 420 : }
22497 :
22498 :
22499 42 : static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22500 42 : instance_checked_getter_count = 0;
22501 42 : instance_checked_setter_count = 0;
22502 42 : TryCatch try_catch(CcTest::isolate());
22503 :
22504 : // Test path through generic runtime code.
22505 : CompileRun("obj.foo");
22506 42 : CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22507 : CompileRun("obj.foo = 23");
22508 42 : CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22509 :
22510 : // Test path through generated LoadIC and StoredIC.
22511 : CompileRun("function test_get(o) { o.foo; }"
22512 : "test_get(obj);");
22513 42 : CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22514 : CompileRun("test_get(obj);");
22515 42 : CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22516 : CompileRun("test_get(obj);");
22517 42 : CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22518 : CompileRun("function test_set(o) { o.foo = 23; }"
22519 : "test_set(obj);");
22520 42 : CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22521 : CompileRun("test_set(obj);");
22522 42 : CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22523 : CompileRun("test_set(obj);");
22524 42 : CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22525 :
22526 : // Test path through optimized code.
22527 : CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22528 : "test_get(obj);");
22529 42 : CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22530 : CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22531 : "test_set(obj);");
22532 42 : CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22533 :
22534 : // Cleanup so that closures start out fresh in next check.
22535 : CompileRun(
22536 : "%DeoptimizeFunction(test_get);"
22537 : "%ClearFunctionFeedback(test_get);"
22538 : "%DeoptimizeFunction(test_set);"
22539 42 : "%ClearFunctionFeedback(test_set);");
22540 42 : }
22541 :
22542 :
22543 23724 : THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22544 6 : v8::internal::FLAG_allow_natives_syntax = true;
22545 6 : LocalContext context;
22546 12 : v8::HandleScope scope(context->GetIsolate());
22547 :
22548 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22549 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22550 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22551 : Local<Value>(), v8::DEFAULT, v8::None,
22552 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22553 36 : CHECK(context->Global()
22554 : ->Set(context.local(), v8_str("f"),
22555 : templ->GetFunction(context.local()).ToLocalChecked())
22556 : .FromJust());
22557 :
22558 : printf("Testing positive ...\n");
22559 : CompileRun("var obj = new f();");
22560 30 : CHECK(templ->HasInstance(
22561 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22562 6 : CheckInstanceCheckedAccessors(true);
22563 :
22564 : printf("Testing negative ...\n");
22565 : CompileRun("var obj = {};"
22566 : "obj.__proto__ = new f();");
22567 30 : CHECK(!templ->HasInstance(
22568 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22569 12 : CheckInstanceCheckedAccessors(false);
22570 6 : }
22571 :
22572 :
22573 90 : static void EmptyInterceptorGetter(
22574 90 : Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22575 :
22576 :
22577 30 : static void EmptyInterceptorSetter(
22578 : Local<String> name, Local<Value> value,
22579 30 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
22580 :
22581 :
22582 23724 : THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22583 6 : v8::internal::FLAG_allow_natives_syntax = true;
22584 6 : LocalContext context;
22585 12 : v8::HandleScope scope(context->GetIsolate());
22586 :
22587 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22588 6 : Local<ObjectTemplate> inst = templ->InstanceTemplate();
22589 : templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
22590 12 : EmptyInterceptorSetter);
22591 : inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22592 : Local<Value>(), v8::DEFAULT, v8::None,
22593 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22594 36 : CHECK(context->Global()
22595 : ->Set(context.local(), v8_str("f"),
22596 : templ->GetFunction(context.local()).ToLocalChecked())
22597 : .FromJust());
22598 :
22599 : printf("Testing positive ...\n");
22600 : CompileRun("var obj = new f();");
22601 30 : CHECK(templ->HasInstance(
22602 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22603 6 : CheckInstanceCheckedAccessors(true);
22604 :
22605 : printf("Testing negative ...\n");
22606 : CompileRun("var obj = {};"
22607 : "obj.__proto__ = new f();");
22608 30 : CHECK(!templ->HasInstance(
22609 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22610 12 : CheckInstanceCheckedAccessors(false);
22611 6 : }
22612 :
22613 :
22614 23724 : THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22615 6 : v8::internal::FLAG_allow_natives_syntax = true;
22616 6 : LocalContext context;
22617 12 : v8::HandleScope scope(context->GetIsolate());
22618 :
22619 6 : Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22620 6 : Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22621 : proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22622 : InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
22623 : v8::None,
22624 18 : v8::AccessorSignature::New(context->GetIsolate(), templ));
22625 36 : CHECK(context->Global()
22626 : ->Set(context.local(), v8_str("f"),
22627 : templ->GetFunction(context.local()).ToLocalChecked())
22628 : .FromJust());
22629 :
22630 : printf("Testing positive ...\n");
22631 : CompileRun("var obj = new f();");
22632 30 : CHECK(templ->HasInstance(
22633 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22634 6 : CheckInstanceCheckedAccessors(true);
22635 :
22636 : printf("Testing negative ...\n");
22637 : CompileRun("var obj = {};"
22638 : "obj.__proto__ = new f();");
22639 30 : CHECK(!templ->HasInstance(
22640 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22641 6 : CheckInstanceCheckedAccessors(false);
22642 :
22643 : printf("Testing positive with modified prototype chain ...\n");
22644 : CompileRun("var obj = new f();"
22645 : "var pro = {};"
22646 : "pro.__proto__ = obj.__proto__;"
22647 : "obj.__proto__ = pro;");
22648 30 : CHECK(templ->HasInstance(
22649 : context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22650 12 : CheckInstanceCheckedAccessors(true);
22651 6 : }
22652 :
22653 :
22654 23723 : TEST(TryFinallyMessage) {
22655 5 : LocalContext context;
22656 10 : v8::HandleScope scope(context->GetIsolate());
22657 : {
22658 : // Test that the original error message is not lost if there is a
22659 : // recursive call into Javascript is done in the finally block, e.g. to
22660 : // initialize an IC. (crbug.com/129171)
22661 5 : TryCatch try_catch(context->GetIsolate());
22662 : const char* trigger_ic =
22663 : "try { \n"
22664 : " throw new Error('test'); \n"
22665 : "} finally { \n"
22666 : " var x = 0; \n"
22667 : " x++; \n" // Trigger an IC initialization here.
22668 : "} \n";
22669 : CompileRun(trigger_ic);
22670 5 : CHECK(try_catch.HasCaught());
22671 5 : Local<Message> message = try_catch.Message();
22672 5 : CHECK(!message.IsEmpty());
22673 10 : CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
22674 : }
22675 :
22676 : {
22677 : // Test that the original exception message is indeed overwritten if
22678 : // a new error is thrown in the finally block.
22679 5 : TryCatch try_catch(context->GetIsolate());
22680 : const char* throw_again =
22681 : "try { \n"
22682 : " throw new Error('test'); \n"
22683 : "} finally { \n"
22684 : " var x = 0; \n"
22685 : " x++; \n"
22686 : " throw new Error('again'); \n" // This is the new uncaught error.
22687 : "} \n";
22688 : CompileRun(throw_again);
22689 5 : CHECK(try_catch.HasCaught());
22690 5 : Local<Message> message = try_catch.Message();
22691 5 : CHECK(!message.IsEmpty());
22692 10 : CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
22693 5 : }
22694 5 : }
22695 :
22696 :
22697 96 : static void Helper137002(bool do_store,
22698 : bool polymorphic,
22699 : bool remove_accessor,
22700 : bool interceptor) {
22701 96 : LocalContext context;
22702 96 : Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22703 96 : if (interceptor) {
22704 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22705 48 : FooSetInterceptor));
22706 : } else {
22707 : templ->SetAccessor(v8_str("foo"),
22708 : GetterWhichReturns42,
22709 48 : SetterWhichSetsYOnThisTo23);
22710 : }
22711 576 : CHECK(context->Global()
22712 : ->Set(context.local(), v8_str("obj"),
22713 : templ->NewInstance(context.local()).ToLocalChecked())
22714 : .FromJust());
22715 :
22716 : // Turn monomorphic on slow object with native accessor, then turn
22717 : // polymorphic, finally optimize to create negative lookup and fail.
22718 : CompileRun(do_store ?
22719 : "function f(x) { x.foo = void 0; }" :
22720 96 : "function f(x) { return x.foo; }");
22721 : CompileRun("obj.y = void 0;");
22722 96 : if (!interceptor) {
22723 : CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22724 : }
22725 : CompileRun("obj.__proto__ = null;"
22726 : "f(obj); f(obj); f(obj);");
22727 96 : if (polymorphic) {
22728 : CompileRun("f({});");
22729 : }
22730 : CompileRun("obj.y = void 0;"
22731 : "%OptimizeFunctionOnNextCall(f);");
22732 96 : if (remove_accessor) {
22733 : CompileRun("delete obj.foo;");
22734 : }
22735 : CompileRun("var result = f(obj);");
22736 96 : if (do_store) {
22737 : CompileRun("result = obj.y;");
22738 : }
22739 96 : if (remove_accessor && !interceptor) {
22740 120 : CHECK(context->Global()
22741 : ->Get(context.local(), v8_str("result"))
22742 : .ToLocalChecked()
22743 : ->IsUndefined());
22744 : } else {
22745 432 : CHECK_EQ(do_store ? 23 : 42, context->Global()
22746 : ->Get(context.local(), v8_str("result"))
22747 : .ToLocalChecked()
22748 : ->Int32Value(context.local())
22749 : .FromJust());
22750 96 : }
22751 96 : }
22752 :
22753 :
22754 23724 : THREADED_TEST(Regress137002a) {
22755 6 : i::FLAG_allow_natives_syntax = true;
22756 6 : i::FLAG_compilation_cache = false;
22757 6 : v8::HandleScope scope(CcTest::isolate());
22758 102 : for (int i = 0; i < 16; i++) {
22759 96 : Helper137002(i & 8, i & 4, i & 2, i & 1);
22760 6 : }
22761 6 : }
22762 :
22763 :
22764 23724 : THREADED_TEST(Regress137002b) {
22765 6 : i::FLAG_allow_natives_syntax = true;
22766 6 : LocalContext context;
22767 6 : v8::Isolate* isolate = context->GetIsolate();
22768 12 : v8::HandleScope scope(isolate);
22769 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22770 : templ->SetAccessor(v8_str("foo"),
22771 : GetterWhichReturns42,
22772 6 : SetterWhichSetsYOnThisTo23);
22773 36 : CHECK(context->Global()
22774 : ->Set(context.local(), v8_str("obj"),
22775 : templ->NewInstance(context.local()).ToLocalChecked())
22776 : .FromJust());
22777 :
22778 : // Turn monomorphic on slow object with native accessor, then just
22779 : // delete the property and fail.
22780 : CompileRun("function load(x) { return x.foo; }"
22781 : "function store(x) { x.foo = void 0; }"
22782 : "function keyed_load(x, key) { return x[key]; }"
22783 : // Second version of function has a different source (add void 0)
22784 : // so that it does not share code with the first version. This
22785 : // ensures that the ICs are monomorphic.
22786 : "function load2(x) { void 0; return x.foo; }"
22787 : "function store2(x) { void 0; x.foo = void 0; }"
22788 : "function keyed_load2(x, key) { void 0; return x[key]; }"
22789 :
22790 : "obj.y = void 0;"
22791 : "obj.__proto__ = null;"
22792 : "var subobj = {};"
22793 : "subobj.y = void 0;"
22794 : "subobj.__proto__ = obj;"
22795 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22796 :
22797 : // Make the ICs monomorphic.
22798 : "load(obj); load(obj);"
22799 : "load2(subobj); load2(subobj);"
22800 : "store(obj); store(obj);"
22801 : "store2(subobj); store2(subobj);"
22802 : "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22803 : "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22804 :
22805 : // Actually test the shiny new ICs and better not crash. This
22806 : // serves as a regression test for issue 142088 as well.
22807 : "load(obj);"
22808 : "load2(subobj);"
22809 : "store(obj);"
22810 : "store2(subobj);"
22811 : "keyed_load(obj, 'foo');"
22812 : "keyed_load2(subobj, 'foo');"
22813 :
22814 : // Delete the accessor. It better not be called any more now.
22815 : "delete obj.foo;"
22816 : "obj.y = void 0;"
22817 : "subobj.y = void 0;"
22818 :
22819 : "var load_result = load(obj);"
22820 : "var load_result2 = load2(subobj);"
22821 : "var keyed_load_result = keyed_load(obj, 'foo');"
22822 : "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22823 : "store(obj);"
22824 : "store2(subobj);"
22825 : "var y_from_obj = obj.y;"
22826 : "var y_from_subobj = subobj.y;");
22827 30 : CHECK(context->Global()
22828 : ->Get(context.local(), v8_str("load_result"))
22829 : .ToLocalChecked()
22830 : ->IsUndefined());
22831 30 : CHECK(context->Global()
22832 : ->Get(context.local(), v8_str("load_result2"))
22833 : .ToLocalChecked()
22834 : ->IsUndefined());
22835 30 : CHECK(context->Global()
22836 : ->Get(context.local(), v8_str("keyed_load_result"))
22837 : .ToLocalChecked()
22838 : ->IsUndefined());
22839 30 : CHECK(context->Global()
22840 : ->Get(context.local(), v8_str("keyed_load_result2"))
22841 : .ToLocalChecked()
22842 : ->IsUndefined());
22843 30 : CHECK(context->Global()
22844 : ->Get(context.local(), v8_str("y_from_obj"))
22845 : .ToLocalChecked()
22846 : ->IsUndefined());
22847 30 : CHECK(context->Global()
22848 : ->Get(context.local(), v8_str("y_from_subobj"))
22849 : .ToLocalChecked()
22850 6 : ->IsUndefined());
22851 6 : }
22852 :
22853 :
22854 23724 : THREADED_TEST(Regress142088) {
22855 6 : i::FLAG_allow_natives_syntax = true;
22856 6 : LocalContext context;
22857 6 : v8::Isolate* isolate = context->GetIsolate();
22858 12 : v8::HandleScope scope(isolate);
22859 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22860 : templ->SetAccessor(v8_str("foo"),
22861 : GetterWhichReturns42,
22862 6 : SetterWhichSetsYOnThisTo23);
22863 36 : CHECK(context->Global()
22864 : ->Set(context.local(), v8_str("obj"),
22865 : templ->NewInstance(context.local()).ToLocalChecked())
22866 : .FromJust());
22867 :
22868 : CompileRun("function load(x) { return x.foo; }"
22869 : "var o = Object.create(obj);"
22870 : "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22871 6 : "load(o); load(o); load(o); load(o);");
22872 6 : }
22873 :
22874 :
22875 23724 : THREADED_TEST(Regress137496) {
22876 6 : i::FLAG_expose_gc = true;
22877 6 : LocalContext context;
22878 12 : v8::HandleScope scope(context->GetIsolate());
22879 :
22880 : // Compile a try-finally clause where the finally block causes a GC
22881 : // while there still is a message pending for external reporting.
22882 12 : TryCatch try_catch(context->GetIsolate());
22883 6 : try_catch.SetVerbose(true);
22884 : CompileRun("try { throw new Error(); } finally { gc(); }");
22885 12 : CHECK(try_catch.HasCaught());
22886 6 : }
22887 :
22888 :
22889 23724 : THREADED_TEST(Regress157124) {
22890 6 : LocalContext context;
22891 6 : v8::Isolate* isolate = context->GetIsolate();
22892 12 : v8::HandleScope scope(isolate);
22893 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22894 12 : Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
22895 6 : obj->GetIdentityHash();
22896 : obj->DeletePrivate(context.local(),
22897 6 : v8::Private::ForApi(isolate, v8_str("Bug")))
22898 18 : .FromJust();
22899 6 : }
22900 :
22901 :
22902 23724 : THREADED_TEST(Regress2535) {
22903 6 : LocalContext context;
22904 12 : v8::HandleScope scope(context->GetIsolate());
22905 : Local<Value> set_value = CompileRun("new Set();");
22906 : Local<Object> set_object(Local<Object>::Cast(set_value));
22907 6 : CHECK_EQ(0, set_object->InternalFieldCount());
22908 : Local<Value> map_value = CompileRun("new Map();");
22909 : Local<Object> map_object(Local<Object>::Cast(map_value));
22910 12 : CHECK_EQ(0, map_object->InternalFieldCount());
22911 6 : }
22912 :
22913 :
22914 23724 : THREADED_TEST(Regress2746) {
22915 6 : LocalContext context;
22916 6 : v8::Isolate* isolate = context->GetIsolate();
22917 12 : v8::HandleScope scope(isolate);
22918 6 : Local<Object> obj = Object::New(isolate);
22919 6 : Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
22920 12 : CHECK(
22921 : obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
22922 6 : Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
22923 6 : CHECK(!value.IsEmpty());
22924 12 : CHECK(value->IsUndefined());
22925 6 : }
22926 :
22927 :
22928 23724 : THREADED_TEST(Regress260106) {
22929 6 : LocalContext context;
22930 6 : v8::Isolate* isolate = context->GetIsolate();
22931 12 : v8::HandleScope scope(isolate);
22932 : Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22933 6 : DummyCallHandler);
22934 : CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22935 : Local<Function> function =
22936 12 : templ->GetFunction(context.local()).ToLocalChecked();
22937 6 : CHECK(!function.IsEmpty());
22938 12 : CHECK(function->IsFunction());
22939 6 : }
22940 :
22941 23724 : THREADED_TEST(JSONParseObject) {
22942 6 : LocalContext context;
22943 12 : HandleScope scope(context->GetIsolate());
22944 : Local<Value> obj =
22945 12 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22946 6 : Local<Object> global = context->Global();
22947 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22948 12 : ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22949 6 : }
22950 :
22951 23724 : THREADED_TEST(JSONParseNumber) {
22952 6 : LocalContext context;
22953 12 : HandleScope scope(context->GetIsolate());
22954 : Local<Value> obj =
22955 12 : v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
22956 6 : Local<Object> global = context->Global();
22957 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
22958 12 : ExpectString("JSON.stringify(obj)", "42");
22959 6 : }
22960 :
22961 : namespace {
22962 42 : void TestJSONParseArray(Local<Context> context, const char* input_str,
22963 : const char* expected_output_str,
22964 : i::ElementsKind expected_elements_kind) {
22965 : Local<Value> obj =
22966 42 : v8::JSON::Parse(context, v8_str(input_str)).ToLocalChecked();
22967 :
22968 : i::Handle<i::JSArray> a =
22969 : i::Handle<i::JSArray>::cast(v8::Utils::OpenHandle(*obj));
22970 42 : CHECK_EQ(expected_elements_kind, a->GetElementsKind());
22971 :
22972 42 : Local<Object> global = context->Global();
22973 126 : global->Set(context, v8_str("obj"), obj).FromJust();
22974 42 : ExpectString("JSON.stringify(obj)", expected_output_str);
22975 42 : }
22976 : } // namespace
22977 :
22978 23724 : THREADED_TEST(JSONParseArray) {
22979 6 : LocalContext context;
22980 12 : HandleScope scope(context->GetIsolate());
22981 :
22982 : TestJSONParseArray(context.local(), "[0, 1, 2]", "[0,1,2]",
22983 6 : i::PACKED_SMI_ELEMENTS);
22984 : TestJSONParseArray(context.local(), "[0, 1.2, 2]", "[0,1.2,2]",
22985 6 : i::PACKED_DOUBLE_ELEMENTS);
22986 : TestJSONParseArray(context.local(), "[0.2, 1, 2]", "[0.2,1,2]",
22987 6 : i::PACKED_DOUBLE_ELEMENTS);
22988 : TestJSONParseArray(context.local(), "[0, \"a\", 2]", "[0,\"a\",2]",
22989 6 : i::PACKED_ELEMENTS);
22990 : TestJSONParseArray(context.local(), "[\"a\", 1, 2]", "[\"a\",1,2]",
22991 6 : i::PACKED_ELEMENTS);
22992 : TestJSONParseArray(context.local(), "[\"a\", 1.2, 2]", "[\"a\",1.2,2]",
22993 6 : i::PACKED_ELEMENTS);
22994 : TestJSONParseArray(context.local(), "[0, 1.2, \"a\"]", "[0,1.2,\"a\"]",
22995 12 : i::PACKED_ELEMENTS);
22996 6 : }
22997 :
22998 23724 : THREADED_TEST(JSONStringifyObject) {
22999 6 : LocalContext context;
23000 12 : HandleScope scope(context->GetIsolate());
23001 : Local<Value> value =
23002 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
23003 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
23004 6 : Local<Object> global = context->Global();
23005 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23006 : Local<String> json =
23007 12 : v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
23008 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
23009 12 : ExpectString("JSON.stringify(obj)", *utf8);
23010 6 : }
23011 :
23012 23724 : THREADED_TEST(JSONStringifyObjectWithGap) {
23013 6 : LocalContext context;
23014 12 : HandleScope scope(context->GetIsolate());
23015 : Local<Value> value =
23016 6 : v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
23017 6 : Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
23018 6 : Local<Object> global = context->Global();
23019 24 : global->Set(context.local(), v8_str("obj"), obj).FromJust();
23020 : Local<String> json =
23021 18 : v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
23022 12 : v8::String::Utf8Value utf8(context->GetIsolate(), json);
23023 12 : ExpectString("JSON.stringify(obj, null, '*')", *utf8);
23024 6 : }
23025 :
23026 : #if V8_OS_POSIX
23027 : class ThreadInterruptTest {
23028 : public:
23029 6 : ThreadInterruptTest() : sem_(0), sem_value_(0) { }
23030 6 : ~ThreadInterruptTest() {}
23031 :
23032 6 : void RunTest() {
23033 : InterruptThread i_thread(this);
23034 6 : i_thread.Start();
23035 :
23036 6 : sem_.Wait();
23037 6 : CHECK_EQ(kExpectedValue, sem_value_);
23038 6 : }
23039 :
23040 : private:
23041 : static const int kExpectedValue = 1;
23042 :
23043 6 : class InterruptThread : public v8::base::Thread {
23044 : public:
23045 : explicit InterruptThread(ThreadInterruptTest* test)
23046 6 : : Thread(Options("InterruptThread")), test_(test) {}
23047 :
23048 6 : virtual void Run() {
23049 : struct sigaction action;
23050 :
23051 : // Ensure that we'll enter waiting condition
23052 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
23053 :
23054 : // Setup signal handler
23055 : memset(&action, 0, sizeof(action));
23056 6 : action.sa_handler = SignalHandler;
23057 6 : sigaction(SIGCHLD, &action, nullptr);
23058 :
23059 : // Send signal
23060 6 : kill(getpid(), SIGCHLD);
23061 :
23062 : // Ensure that if wait has returned because of error
23063 6 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
23064 :
23065 : // Set value and signal semaphore
23066 6 : test_->sem_value_ = 1;
23067 6 : test_->sem_.Signal();
23068 6 : }
23069 :
23070 6 : static void SignalHandler(int signal) {
23071 6 : }
23072 :
23073 : private:
23074 : ThreadInterruptTest* test_;
23075 : };
23076 :
23077 : v8::base::Semaphore sem_;
23078 : volatile int sem_value_;
23079 : };
23080 :
23081 :
23082 23724 : THREADED_TEST(SemaphoreInterruption) {
23083 12 : ThreadInterruptTest().RunTest();
23084 6 : }
23085 :
23086 :
23087 : #endif // V8_OS_POSIX
23088 :
23089 :
23090 0 : void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23091 0 : CHECK(false);
23092 : }
23093 :
23094 :
23095 23723 : TEST(JSONStringifyAccessCheck) {
23096 5 : v8::V8::Initialize();
23097 5 : v8::Isolate* isolate = CcTest::isolate();
23098 5 : v8::HandleScope scope(isolate);
23099 :
23100 : // Create an ObjectTemplate for global objects and install access
23101 : // check callbacks that will block access.
23102 : v8::Local<v8::ObjectTemplate> global_template =
23103 5 : v8::ObjectTemplate::New(isolate);
23104 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
23105 :
23106 : // Create a context and set an x property on it's global object.
23107 10 : LocalContext context0(nullptr, global_template);
23108 5 : v8::Local<v8::Object> global0 = context0->Global();
23109 15 : global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
23110 5 : ExpectString("JSON.stringify(this)", "{\"x\":42}");
23111 :
23112 15 : for (int i = 0; i < 2; i++) {
23113 10 : if (i == 1) {
23114 : // Install a toJSON function on the second run.
23115 : v8::Local<v8::FunctionTemplate> toJSON =
23116 5 : v8::FunctionTemplate::New(isolate, UnreachableCallback);
23117 :
23118 : global0->Set(context0.local(), v8_str("toJSON"),
23119 25 : toJSON->GetFunction(context0.local()).ToLocalChecked())
23120 10 : .FromJust();
23121 : }
23122 : // Create a context with a different security token so that the
23123 : // failed access check callback will be called on each access.
23124 10 : LocalContext context1(nullptr, global_template);
23125 50 : CHECK(context1->Global()
23126 : ->Set(context1.local(), v8_str("other"), global0)
23127 : .FromJust());
23128 :
23129 10 : CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
23130 10 : CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
23131 10 : CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
23132 15 : }
23133 5 : }
23134 :
23135 :
23136 : bool access_check_fail_thrown = false;
23137 : bool catch_callback_called = false;
23138 :
23139 :
23140 : // Failed access check callback that performs a GC on each invocation.
23141 80 : void FailedAccessCheckThrows(Local<v8::Object> target,
23142 : v8::AccessType type,
23143 : Local<v8::Value> data) {
23144 80 : access_check_fail_thrown = true;
23145 80 : i::PrintF("Access check failed. Error thrown.\n");
23146 : CcTest::isolate()->ThrowException(
23147 80 : v8::Exception::Error(v8_str("cross context")));
23148 80 : }
23149 :
23150 :
23151 300 : void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23152 300 : for (int i = 0; i < args.Length(); i++) {
23153 75 : i::PrintF("%s\n", *String::Utf8Value(args.GetIsolate(), args[i]));
23154 : }
23155 75 : catch_callback_called = true;
23156 75 : }
23157 :
23158 :
23159 5 : void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
23160 5 : v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
23161 20 : CHECK(
23162 : args[0]
23163 : ->ToObject(context)
23164 : .ToLocalChecked()
23165 : ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
23166 : .IsNothing());
23167 5 : }
23168 :
23169 :
23170 75 : void CheckCorrectThrow(const char* script) {
23171 : // Test that the script, when wrapped into a try-catch, triggers the catch
23172 : // clause due to failed access check throwing an exception.
23173 : // The subsequent try-catch should run without any exception.
23174 75 : access_check_fail_thrown = false;
23175 75 : catch_callback_called = false;
23176 : i::ScopedVector<char> source(1024);
23177 75 : i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
23178 : CompileRun(source.start());
23179 75 : CHECK(access_check_fail_thrown);
23180 75 : CHECK(catch_callback_called);
23181 :
23182 75 : access_check_fail_thrown = false;
23183 75 : catch_callback_called = false;
23184 : CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
23185 75 : CHECK(!access_check_fail_thrown);
23186 75 : CHECK(!catch_callback_called);
23187 75 : }
23188 :
23189 :
23190 23723 : TEST(AccessCheckThrows) {
23191 5 : i::FLAG_allow_natives_syntax = true;
23192 5 : v8::V8::Initialize();
23193 5 : v8::Isolate* isolate = CcTest::isolate();
23194 5 : isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
23195 5 : v8::HandleScope scope(isolate);
23196 :
23197 : // Create an ObjectTemplate for global objects and install access
23198 : // check callbacks that will block access.
23199 : v8::Local<v8::ObjectTemplate> global_template =
23200 5 : v8::ObjectTemplate::New(isolate);
23201 5 : global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
23202 :
23203 : // Create a context and set an x property on it's global object.
23204 10 : LocalContext context0(nullptr, global_template);
23205 5 : v8::Local<v8::Object> global0 = context0->Global();
23206 15 : CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
23207 :
23208 : // Create a context with a different security token so that the
23209 : // failed access check callback will be called on each access.
23210 10 : LocalContext context1(nullptr, global_template);
23211 25 : CHECK(context1->Global()
23212 : ->Set(context1.local(), v8_str("other"), global0)
23213 : .FromJust());
23214 :
23215 : v8::Local<v8::FunctionTemplate> catcher_fun =
23216 5 : v8::FunctionTemplate::New(isolate, CatcherCallback);
23217 35 : CHECK(context1->Global()
23218 : ->Set(context1.local(), v8_str("catcher"),
23219 : catcher_fun->GetFunction(context1.local()).ToLocalChecked())
23220 : .FromJust());
23221 :
23222 : v8::Local<v8::FunctionTemplate> has_own_property_fun =
23223 5 : v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
23224 35 : CHECK(context1->Global()
23225 : ->Set(context1.local(), v8_str("has_own_property"),
23226 : has_own_property_fun->GetFunction(context1.local())
23227 : .ToLocalChecked())
23228 : .FromJust());
23229 :
23230 : {
23231 5 : v8::TryCatch try_catch(isolate);
23232 5 : access_check_fail_thrown = false;
23233 : CompileRun("other.x;");
23234 5 : CHECK(access_check_fail_thrown);
23235 5 : CHECK(try_catch.HasCaught());
23236 : }
23237 :
23238 5 : CheckCorrectThrow("other.x");
23239 5 : CheckCorrectThrow("other[1]");
23240 5 : CheckCorrectThrow("JSON.stringify(other)");
23241 5 : CheckCorrectThrow("has_own_property(other, 'x')");
23242 5 : CheckCorrectThrow("%GetProperty(other, 'x')");
23243 5 : CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
23244 5 : CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
23245 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kSloppy) == 0);
23246 : STATIC_ASSERT(static_cast<int>(i::LanguageMode::kStrict) == 1);
23247 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); // 0 == SLOPPY
23248 5 : CheckCorrectThrow("%DeleteProperty(other, 'x', 1)"); // 1 == STRICT
23249 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
23250 5 : CheckCorrectThrow("%DeleteProperty(other, '1', 1)");
23251 5 : CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
23252 5 : CheckCorrectThrow("%HasProperty(other, 'x')");
23253 5 : CheckCorrectThrow("Object.prototype.propertyIsEnumerable(other, 'x')");
23254 : // PROPERTY_ATTRIBUTES_NONE = 0
23255 : CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
23256 5 : "other, 'x', null, null, 1)");
23257 :
23258 : // Reset the failed access check callback so it does not influence
23259 : // the other tests.
23260 10 : isolate->SetFailedAccessCheckCallbackFunction(nullptr);
23261 5 : }
23262 :
23263 23718 : TEST(AccessCheckInIC) {
23264 0 : i::FLAG_native_code_counters = true;
23265 0 : i::FLAG_opt = false;
23266 :
23267 : v8::Isolate::CreateParams create_params;
23268 0 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
23269 0 : create_params.counter_lookup_callback = LookupCounter;
23270 0 : v8::Isolate* isolate = v8::Isolate::New(create_params);
23271 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23272 :
23273 : {
23274 : v8::Isolate::Scope isolate_scope(isolate);
23275 0 : LocalContext env(isolate);
23276 0 : v8::HandleScope scope(isolate);
23277 :
23278 : // Enforce recompilation of IC stubs that access megamorphic stub cache
23279 : // to respect enabled native code counters and stub cache test flags.
23280 : RecompileICStubs(i_isolate);
23281 :
23282 : // Create an ObjectTemplate for global objects and install access
23283 : // check callbacks that will block access.
23284 : v8::Local<v8::ObjectTemplate> global_template =
23285 0 : v8::ObjectTemplate::New(isolate);
23286 0 : global_template->SetAccessCheckCallback(AccessCounter);
23287 :
23288 : // Create a context and set an x property on its global object.
23289 0 : LocalContext context0(isolate, nullptr, global_template);
23290 0 : v8::Local<v8::Object> global0 = context0->Global();
23291 0 : CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
23292 :
23293 : // Create a context with a different security token so that the
23294 : // failed access check callback will be called on each access.
23295 0 : LocalContext context1(isolate, nullptr, global_template);
23296 0 : CHECK(context1->Global()
23297 : ->Set(context1.local(), v8_str("other"), global0)
23298 : .FromJust());
23299 :
23300 : // Set different security tokens.
23301 0 : Local<Value> token0 = v8_str("token0");
23302 0 : context0.local()->SetSecurityToken(token0);
23303 0 : context1.local()->SetSecurityToken(v8_str("token1"));
23304 :
23305 0 : int initial_probes = probes_counter;
23306 0 : int initial_misses = misses_counter;
23307 0 : int initial_updates = updates_counter;
23308 0 : access_count = 0;
23309 :
23310 : // Create megamorphic load ic with a handler for "global0.x" compiled for
23311 : // context0.
23312 : CompileRun(context0.local(),
23313 : "Number(1).__proto__.x = null;\n"
23314 : "String(1).__proto__.x = null;\n"
23315 : "function get0(o) { return o.x; };\n"
23316 : "get0({x:1});\n" // premonomorphic
23317 : "get0({x:1,a:0});\n" // monomorphic
23318 : "get0({x:1,b:0});\n" // polymorphic
23319 : "get0('str');\n"
23320 : "get0(1.1);\n"
23321 : "get0(this);\n" // megamorphic
23322 0 : "");
23323 0 : CHECK_EQ(0, probes_counter - initial_probes);
23324 0 : CHECK_EQ(0, misses_counter - initial_misses);
23325 0 : CHECK_EQ(5, updates_counter - initial_updates);
23326 :
23327 : // Create megamorphic load ic in context1.
23328 : CompileRun(context1.local(),
23329 : "function get1(o) { return o.x; };\n"
23330 : "get1({x:1});\n" // premonomorphic
23331 : "get1({x:1,a:0});\n" // monomorphic
23332 : "get1({x:1,b:0});\n" // polymorphic
23333 : "get1({x:1,c:0});\n"
23334 : "get1({x:1,d:0});\n"
23335 : "get1({x:1,e:0});\n" // megamorphic
23336 0 : "");
23337 0 : CHECK_EQ(0, access_count);
23338 0 : CHECK_EQ(0, probes_counter - initial_probes);
23339 0 : CHECK_EQ(0, misses_counter - initial_misses);
23340 0 : CHECK_EQ(10, updates_counter - initial_updates);
23341 :
23342 : // Feed the |other| to the load ic and ensure that it doesn't pick the
23343 : // handler for "global0.x" compiled for context0 from the megamorphic
23344 : // cache but create another handler for "global0.x" compiled for context1
23345 : // and ensure the access check callback is triggered.
23346 0 : CompileRun(context1.local(), "get1(other)");
23347 0 : CHECK_EQ(1, access_count); // Access check callback must be triggered.
23348 :
23349 : // Feed the primitive objects to the load ic and ensure that it doesn't
23350 : // pick handlers for primitive maps from the megamorphic stub cache even
23351 : // if the security token matches.
23352 0 : context1.local()->SetSecurityToken(token0);
23353 0 : CHECK(CompileRun(context1.local(), "get1(1.1)")
23354 : .ToLocalChecked()
23355 : ->IsUndefined());
23356 0 : CHECK(CompileRun(context1.local(), "get1('str')")
23357 : .ToLocalChecked()
23358 : ->IsUndefined());
23359 :
23360 0 : CHECK_EQ(1, access_count); // Access check callback must be triggered.
23361 0 : CHECK_EQ(3, probes_counter - initial_probes);
23362 0 : CHECK_EQ(0, misses_counter - initial_misses);
23363 0 : CHECK_EQ(13, updates_counter - initial_updates);
23364 : }
23365 0 : isolate->Dispose();
23366 0 : }
23367 :
23368 : class RequestInterruptTestBase {
23369 : public:
23370 35 : RequestInterruptTestBase()
23371 : : env_(),
23372 35 : isolate_(env_->GetIsolate()),
23373 : sem_(0),
23374 : warmup_(20000),
23375 105 : should_continue_(true) {
23376 35 : }
23377 :
23378 35 : virtual ~RequestInterruptTestBase() { }
23379 :
23380 : virtual void StartInterruptThread() = 0;
23381 :
23382 : virtual void TestBody() = 0;
23383 :
23384 70 : void RunTest() {
23385 35 : StartInterruptThread();
23386 :
23387 35 : v8::HandleScope handle_scope(isolate_);
23388 :
23389 35 : TestBody();
23390 :
23391 : // Verify we arrived here because interruptor was called
23392 : // not due to a bug causing us to exit the loop too early.
23393 35 : CHECK(!should_continue());
23394 35 : }
23395 :
23396 : void WakeUpInterruptor() {
23397 35 : sem_.Signal();
23398 : }
23399 :
23400 : bool should_continue() const { return should_continue_; }
23401 :
23402 1707246 : bool ShouldContinue() {
23403 1707246 : if (warmup_ > 0) {
23404 600000 : if (--warmup_ == 0) {
23405 : WakeUpInterruptor();
23406 : }
23407 : }
23408 :
23409 1707246 : return should_continue_;
23410 : }
23411 :
23412 1208668 : static void ShouldContinueCallback(
23413 2417336 : const v8::FunctionCallbackInfo<Value>& info) {
23414 : RequestInterruptTestBase* test =
23415 : reinterpret_cast<RequestInterruptTestBase*>(
23416 1208668 : info.Data().As<v8::External>()->Value());
23417 1208668 : info.GetReturnValue().Set(test->ShouldContinue());
23418 1208668 : }
23419 :
23420 : LocalContext env_;
23421 : v8::Isolate* isolate_;
23422 : v8::base::Semaphore sem_;
23423 : int warmup_;
23424 : bool should_continue_;
23425 : };
23426 :
23427 :
23428 60 : class RequestInterruptTestBaseWithSimpleInterrupt
23429 : : public RequestInterruptTestBase {
23430 : public:
23431 60 : RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
23432 :
23433 30 : virtual void StartInterruptThread() {
23434 30 : i_thread.Start();
23435 30 : }
23436 :
23437 : private:
23438 30 : class InterruptThread : public v8::base::Thread {
23439 : public:
23440 : explicit InterruptThread(RequestInterruptTestBase* test)
23441 30 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23442 :
23443 30 : virtual void Run() {
23444 30 : test_->sem_.Wait();
23445 30 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23446 30 : }
23447 :
23448 30 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23449 : reinterpret_cast<RequestInterruptTestBase*>(data)->
23450 30 : should_continue_ = false;
23451 30 : }
23452 :
23453 : private:
23454 : RequestInterruptTestBase* test_;
23455 : };
23456 :
23457 : InterruptThread i_thread;
23458 : };
23459 :
23460 :
23461 10 : class RequestInterruptTestWithFunctionCall
23462 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23463 : public:
23464 5 : virtual void TestBody() {
23465 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23466 15 : v8::External::New(isolate_, this))
23467 5 : .ToLocalChecked();
23468 25 : CHECK(env_->Global()
23469 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23470 : .FromJust());
23471 :
23472 : CompileRun("while (ShouldContinue()) { }");
23473 5 : }
23474 : };
23475 :
23476 :
23477 10 : class RequestInterruptTestWithMethodCall
23478 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23479 : public:
23480 5 : virtual void TestBody() {
23481 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23482 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23483 : proto->Set(v8_str("shouldContinue"),
23484 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23485 20 : v8::External::New(isolate_, this)));
23486 30 : CHECK(env_->Global()
23487 : ->Set(env_.local(), v8_str("Klass"),
23488 : t->GetFunction(env_.local()).ToLocalChecked())
23489 : .FromJust());
23490 :
23491 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23492 5 : }
23493 : };
23494 :
23495 :
23496 10 : class RequestInterruptTestWithAccessor
23497 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23498 : public:
23499 5 : virtual void TestBody() {
23500 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23501 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23502 : proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23503 15 : isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23504 30 : CHECK(env_->Global()
23505 : ->Set(env_.local(), v8_str("Klass"),
23506 : t->GetFunction(env_.local()).ToLocalChecked())
23507 : .FromJust());
23508 :
23509 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23510 5 : }
23511 : };
23512 :
23513 :
23514 10 : class RequestInterruptTestWithNativeAccessor
23515 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23516 : public:
23517 5 : virtual void TestBody() {
23518 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23519 10 : t->InstanceTemplate()->SetNativeDataProperty(
23520 : v8_str("shouldContinue"), &ShouldContinueNativeGetter, nullptr,
23521 20 : v8::External::New(isolate_, this));
23522 30 : CHECK(env_->Global()
23523 : ->Set(env_.local(), v8_str("Klass"),
23524 : t->GetFunction(env_.local()).ToLocalChecked())
23525 : .FromJust());
23526 :
23527 : CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23528 5 : }
23529 :
23530 : private:
23531 498578 : static void ShouldContinueNativeGetter(
23532 : Local<String> property,
23533 : const v8::PropertyCallbackInfo<v8::Value>& info) {
23534 : RequestInterruptTestBase* test =
23535 : reinterpret_cast<RequestInterruptTestBase*>(
23536 498578 : info.Data().As<v8::External>()->Value());
23537 498578 : info.GetReturnValue().Set(test->ShouldContinue());
23538 498578 : }
23539 : };
23540 :
23541 :
23542 10 : class RequestInterruptTestWithMethodCallAndInterceptor
23543 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23544 : public:
23545 5 : virtual void TestBody() {
23546 5 : v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23547 5 : v8::Local<v8::Template> proto = t->PrototypeTemplate();
23548 : proto->Set(v8_str("shouldContinue"),
23549 : FunctionTemplate::New(isolate_, ShouldContinueCallback,
23550 20 : v8::External::New(isolate_, this)));
23551 5 : v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23552 : instance_template->SetHandler(
23553 5 : v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23554 :
23555 30 : CHECK(env_->Global()
23556 : ->Set(env_.local(), v8_str("Klass"),
23557 : t->GetFunction(env_.local()).ToLocalChecked())
23558 : .FromJust());
23559 :
23560 : CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23561 5 : }
23562 :
23563 : private:
23564 145401 : static void EmptyInterceptor(
23565 145401 : Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23566 : };
23567 :
23568 :
23569 10 : class RequestInterruptTestWithMathAbs
23570 : : public RequestInterruptTestBaseWithSimpleInterrupt {
23571 : public:
23572 5 : virtual void TestBody() {
23573 : env_->Global()
23574 : ->Set(env_.local(), v8_str("WakeUpInterruptor"),
23575 : Function::New(env_.local(), WakeUpInterruptorCallback,
23576 15 : v8::External::New(isolate_, this))
23577 25 : .ToLocalChecked())
23578 10 : .FromJust();
23579 :
23580 : env_->Global()
23581 : ->Set(env_.local(), v8_str("ShouldContinue"),
23582 : Function::New(env_.local(), ShouldContinueCallback,
23583 15 : v8::External::New(isolate_, this))
23584 25 : .ToLocalChecked())
23585 10 : .FromJust();
23586 :
23587 5 : i::FLAG_allow_natives_syntax = true;
23588 : CompileRun("function loopish(o) {"
23589 : " var pre = 10;"
23590 : " while (o.abs(1) > 0) {"
23591 : " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23592 : " if (pre > 0) {"
23593 : " if (--pre === 0) WakeUpInterruptor(o === Math);"
23594 : " }"
23595 : " }"
23596 : "}"
23597 : "var i = 50;"
23598 : "var obj = {abs: function () { return i-- }, x: null};"
23599 : "delete obj.x;"
23600 : "loopish(obj);"
23601 : "%OptimizeFunctionOnNextCall(loopish);"
23602 : "loopish(Math);");
23603 :
23604 5 : i::FLAG_allow_natives_syntax = false;
23605 5 : }
23606 :
23607 : private:
23608 10 : static void WakeUpInterruptorCallback(
23609 15 : const v8::FunctionCallbackInfo<Value>& info) {
23610 10 : if (!info[0]
23611 10 : ->BooleanValue(info.GetIsolate()->GetCurrentContext())
23612 20 : .FromJust()) {
23613 10 : return;
23614 : }
23615 :
23616 : RequestInterruptTestBase* test =
23617 : reinterpret_cast<RequestInterruptTestBase*>(
23618 5 : info.Data().As<v8::External>()->Value());
23619 : test->WakeUpInterruptor();
23620 : }
23621 :
23622 140258 : static void ShouldContinueCallback(
23623 280516 : const v8::FunctionCallbackInfo<Value>& info) {
23624 140258 : RequestInterruptTestBase* test =
23625 : reinterpret_cast<RequestInterruptTestBase*>(
23626 140258 : info.Data().As<v8::External>()->Value());
23627 : info.GetReturnValue().Set(test->should_continue());
23628 140258 : }
23629 : };
23630 :
23631 :
23632 23723 : TEST(RequestInterruptTestWithFunctionCall) {
23633 15 : RequestInterruptTestWithFunctionCall().RunTest();
23634 5 : }
23635 :
23636 :
23637 23723 : TEST(RequestInterruptTestWithMethodCall) {
23638 15 : RequestInterruptTestWithMethodCall().RunTest();
23639 5 : }
23640 :
23641 :
23642 23723 : TEST(RequestInterruptTestWithAccessor) {
23643 15 : RequestInterruptTestWithAccessor().RunTest();
23644 5 : }
23645 :
23646 :
23647 23723 : TEST(RequestInterruptTestWithNativeAccessor) {
23648 15 : RequestInterruptTestWithNativeAccessor().RunTest();
23649 5 : }
23650 :
23651 :
23652 23723 : TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23653 15 : RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23654 5 : }
23655 :
23656 :
23657 23723 : TEST(RequestInterruptTestWithMathAbs) {
23658 15 : RequestInterruptTestWithMathAbs().RunTest();
23659 5 : }
23660 :
23661 :
23662 10 : class RequestMultipleInterrupts : public RequestInterruptTestBase {
23663 : public:
23664 10 : RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23665 :
23666 5 : virtual void StartInterruptThread() {
23667 5 : i_thread.Start();
23668 5 : }
23669 :
23670 5 : virtual void TestBody() {
23671 : Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23672 15 : v8::External::New(isolate_, this))
23673 5 : .ToLocalChecked();
23674 25 : CHECK(env_->Global()
23675 : ->Set(env_.local(), v8_str("ShouldContinue"), func)
23676 : .FromJust());
23677 :
23678 : CompileRun("while (ShouldContinue()) { }");
23679 5 : }
23680 :
23681 : private:
23682 5 : class InterruptThread : public v8::base::Thread {
23683 : public:
23684 : enum { NUM_INTERRUPTS = 10 };
23685 : explicit InterruptThread(RequestMultipleInterrupts* test)
23686 5 : : Thread(Options("RequestInterruptTest")), test_(test) {}
23687 :
23688 5 : virtual void Run() {
23689 5 : test_->sem_.Wait();
23690 55 : for (int i = 0; i < NUM_INTERRUPTS; i++) {
23691 50 : test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23692 : }
23693 5 : }
23694 :
23695 50 : static void OnInterrupt(v8::Isolate* isolate, void* data) {
23696 : RequestMultipleInterrupts* test =
23697 : reinterpret_cast<RequestMultipleInterrupts*>(data);
23698 50 : test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23699 50 : }
23700 :
23701 : private:
23702 : RequestMultipleInterrupts* test_;
23703 : };
23704 :
23705 : InterruptThread i_thread;
23706 : int counter_;
23707 : };
23708 :
23709 :
23710 23723 : TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23711 :
23712 :
23713 : static bool interrupt_was_called = false;
23714 :
23715 :
23716 5 : void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
23717 5 : interrupt_was_called = true;
23718 5 : }
23719 :
23720 :
23721 23723 : TEST(RequestInterruptSmallScripts) {
23722 5 : LocalContext env;
23723 5 : v8::Isolate* isolate = CcTest::isolate();
23724 10 : v8::HandleScope scope(isolate);
23725 :
23726 5 : interrupt_was_called = false;
23727 5 : isolate->RequestInterrupt(&SmallScriptsInterruptCallback, nullptr);
23728 : CompileRun("(function(x){return x;})(1);");
23729 10 : CHECK(interrupt_was_called);
23730 5 : }
23731 :
23732 :
23733 : static Local<Value> function_new_expected_env;
23734 24 : static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23735 36 : CHECK(
23736 : function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
23737 : info.Data())
23738 : .FromJust());
23739 : info.GetReturnValue().Set(17);
23740 12 : }
23741 :
23742 :
23743 23724 : THREADED_TEST(FunctionNew) {
23744 6 : LocalContext env;
23745 6 : v8::Isolate* isolate = env->GetIsolate();
23746 12 : v8::HandleScope scope(isolate);
23747 6 : Local<Object> data = v8::Object::New(isolate);
23748 6 : function_new_expected_env = data;
23749 : Local<Function> func =
23750 12 : Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
23751 30 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
23752 6 : Local<Value> result = CompileRun("func();");
23753 18 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
23754 : // Serial number should be invalid => should not be cached.
23755 : auto serial_number =
23756 : i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
23757 : ->shared()
23758 : ->get_api_func_data()
23759 : ->serial_number())
23760 : ->value();
23761 6 : CHECK_EQ(i::FunctionTemplateInfo::kInvalidSerialNumber, serial_number);
23762 :
23763 : // Verify that each Function::New creates a new function instance
23764 6 : Local<Object> data2 = v8::Object::New(isolate);
23765 6 : function_new_expected_env = data2;
23766 : Local<Function> func2 =
23767 12 : Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
23768 6 : CHECK(!func2->IsNull());
23769 12 : CHECK(!func->Equals(env.local(), func2).FromJust());
23770 30 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
23771 6 : Local<Value> result2 = CompileRun("func2();");
23772 24 : CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
23773 6 : }
23774 :
23775 :
23776 23723 : TEST(EscapeableHandleScope) {
23777 5 : HandleScope outer_scope(CcTest::isolate());
23778 10 : LocalContext context;
23779 : const int runs = 10;
23780 55 : Local<String> values[runs];
23781 50 : for (int i = 0; i < runs; i++) {
23782 50 : v8::EscapableHandleScope inner_scope(CcTest::isolate());
23783 : Local<String> value;
23784 50 : if (i != 0) value = v8_str("escape value");
23785 50 : values[i] = inner_scope.Escape(value);
23786 : }
23787 50 : for (int i = 0; i < runs; i++) {
23788 : Local<String> expected;
23789 50 : if (i != 0) {
23790 135 : CHECK(v8_str("escape value")
23791 : ->Equals(context.local(), values[i])
23792 : .FromJust());
23793 : } else {
23794 10 : CHECK(values[i].IsEmpty());
23795 : }
23796 5 : }
23797 5 : }
23798 :
23799 :
23800 20 : static void SetterWhichExpectsThisAndHolderToDiffer(
23801 : Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23802 20 : CHECK(info.Holder() != info.This());
23803 20 : }
23804 :
23805 :
23806 23723 : TEST(Regress239669) {
23807 5 : LocalContext context;
23808 5 : v8::Isolate* isolate = context->GetIsolate();
23809 10 : v8::HandleScope scope(isolate);
23810 5 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23811 5 : templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23812 30 : CHECK(context->Global()
23813 : ->Set(context.local(), v8_str("P"),
23814 : templ->NewInstance(context.local()).ToLocalChecked())
23815 : .FromJust());
23816 : CompileRun(
23817 : "function C1() {"
23818 : " this.x = 23;"
23819 : "};"
23820 : "C1.prototype = P;"
23821 : "for (var i = 0; i < 4; i++ ) {"
23822 : " new C1();"
23823 5 : "}");
23824 5 : }
23825 :
23826 :
23827 : class ApiCallOptimizationChecker {
23828 : private:
23829 : static Local<Object> data;
23830 : static Local<Object> receiver;
23831 : static Local<Object> holder;
23832 : static Local<Object> callee;
23833 : static int count;
23834 :
23835 270 : static void OptimizationCallback(
23836 1350 : const v8::FunctionCallbackInfo<v8::Value>& info) {
23837 270 : CHECK(data == info.Data());
23838 270 : CHECK(receiver == info.This());
23839 270 : if (info.Length() == 1) {
23840 270 : CHECK(v8_num(1)
23841 : ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
23842 : .FromJust());
23843 : }
23844 270 : CHECK(holder == info.Holder());
23845 270 : count++;
23846 270 : info.GetReturnValue().Set(v8_str("returned"));
23847 270 : }
23848 :
23849 : public:
23850 : enum SignatureType {
23851 : kNoSignature,
23852 : kSignatureOnReceiver,
23853 : kSignatureOnPrototype
23854 : };
23855 :
23856 5 : void RunAll() {
23857 : SignatureType signature_types[] =
23858 5 : {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23859 20 : for (unsigned i = 0; i < arraysize(signature_types); i++) {
23860 15 : SignatureType signature_type = signature_types[i];
23861 45 : for (int j = 0; j < 2; j++) {
23862 30 : bool global = j == 0;
23863 : int key = signature_type +
23864 30 : arraysize(signature_types) * (global ? 1 : 0);
23865 30 : Run(signature_type, global, key);
23866 : }
23867 : }
23868 5 : }
23869 :
23870 30 : void Run(SignatureType signature_type, bool global, int key) {
23871 30 : v8::Isolate* isolate = CcTest::isolate();
23872 30 : v8::HandleScope scope(isolate);
23873 : // Build a template for signature checks.
23874 : Local<v8::ObjectTemplate> signature_template;
23875 : Local<v8::Signature> signature;
23876 : {
23877 : Local<v8::FunctionTemplate> parent_template =
23878 30 : FunctionTemplate::New(isolate);
23879 30 : parent_template->SetHiddenPrototype(true);
23880 : Local<v8::FunctionTemplate> function_template
23881 30 : = FunctionTemplate::New(isolate);
23882 30 : function_template->Inherit(parent_template);
23883 30 : switch (signature_type) {
23884 : case kNoSignature:
23885 : break;
23886 : case kSignatureOnReceiver:
23887 10 : signature = v8::Signature::New(isolate, function_template);
23888 10 : break;
23889 : case kSignatureOnPrototype:
23890 10 : signature = v8::Signature::New(isolate, parent_template);
23891 10 : break;
23892 : }
23893 30 : signature_template = function_template->InstanceTemplate();
23894 : }
23895 : // Global object must pass checks.
23896 : Local<v8::Context> context =
23897 30 : v8::Context::New(isolate, nullptr, signature_template);
23898 : v8::Context::Scope context_scope(context);
23899 : // Install regular object that can pass signature checks.
23900 : Local<Object> function_receiver =
23901 30 : signature_template->NewInstance(context).ToLocalChecked();
23902 120 : CHECK(context->Global()
23903 : ->Set(context, v8_str("function_receiver"), function_receiver)
23904 : .FromJust());
23905 : // Get the holder objects.
23906 : Local<Object> inner_global =
23907 60 : Local<Object>::Cast(context->Global()->GetPrototype());
23908 : // Install functions on hidden prototype object if there is one.
23909 30 : data = Object::New(isolate);
23910 : Local<FunctionTemplate> function_template = FunctionTemplate::New(
23911 30 : isolate, OptimizationCallback, data, signature);
23912 : Local<Function> function =
23913 30 : function_template->GetFunction(context).ToLocalChecked();
23914 : Local<Object> global_holder = inner_global;
23915 : Local<Object> function_holder = function_receiver;
23916 30 : if (signature_type == kSignatureOnPrototype) {
23917 10 : function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23918 10 : global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23919 : }
23920 90 : global_holder->Set(context, v8_str("g_f"), function).FromJust();
23921 60 : global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23922 90 : function_holder->Set(context, v8_str("f"), function).FromJust();
23923 60 : function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23924 : // Initialize expected values.
23925 30 : callee = function;
23926 30 : count = 0;
23927 30 : if (global) {
23928 15 : receiver = context->Global();
23929 15 : holder = inner_global;
23930 : } else {
23931 15 : holder = function_receiver;
23932 : // If not using a signature, add something else to the prototype chain
23933 : // to test the case that holder != receiver
23934 15 : if (signature_type == kNoSignature) {
23935 : receiver = Local<Object>::Cast(CompileRun(
23936 : "var receiver_subclass = {};\n"
23937 : "receiver_subclass.__proto__ = function_receiver;\n"
23938 5 : "receiver_subclass"));
23939 : } else {
23940 : receiver = Local<Object>::Cast(CompileRun(
23941 : "var receiver_subclass = function_receiver;\n"
23942 10 : "receiver_subclass"));
23943 : }
23944 : }
23945 : // With no signature, the holder is not set.
23946 30 : if (signature_type == kNoSignature) holder = receiver;
23947 : // build wrap_function
23948 : i::ScopedVector<char> wrap_function(200);
23949 30 : if (global) {
23950 : i::SNPrintF(
23951 : wrap_function,
23952 : "function wrap_f_%d() { var f = g_f; return f(); }\n"
23953 : "function wrap_get_%d() { return this.g_acc; }\n"
23954 : "function wrap_set_%d() { return this.g_acc = 1; }\n",
23955 15 : key, key, key);
23956 : } else {
23957 : i::SNPrintF(
23958 : wrap_function,
23959 : "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23960 : "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23961 : "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23962 15 : key, key, key);
23963 : }
23964 : // build source string
23965 : i::ScopedVector<char> source(1000);
23966 : i::SNPrintF(
23967 : source,
23968 : "%s\n" // wrap functions
23969 : "function wrap_f() { return wrap_f_%d(); }\n"
23970 : "function wrap_get() { return wrap_get_%d(); }\n"
23971 : "function wrap_set() { return wrap_set_%d(); }\n"
23972 : "check = function(returned) {\n"
23973 : " if (returned !== 'returned') { throw returned; }\n"
23974 : "}\n"
23975 : "\n"
23976 : "check(wrap_f());\n"
23977 : "check(wrap_f());\n"
23978 : "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23979 : "check(wrap_f());\n"
23980 : "\n"
23981 : "check(wrap_get());\n"
23982 : "check(wrap_get());\n"
23983 : "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23984 : "check(wrap_get());\n"
23985 : "\n"
23986 : "check = function(returned) {\n"
23987 : " if (returned !== 1) { throw returned; }\n"
23988 : "}\n"
23989 : "check(wrap_set());\n"
23990 : "check(wrap_set());\n"
23991 : "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23992 : "check(wrap_set());\n",
23993 30 : wrap_function.start(), key, key, key, key, key, key);
23994 60 : v8::TryCatch try_catch(isolate);
23995 : CompileRun(source.start());
23996 30 : CHECK(!try_catch.HasCaught());
23997 60 : CHECK_EQ(9, count);
23998 30 : }
23999 : };
24000 :
24001 :
24002 : Local<Object> ApiCallOptimizationChecker::data;
24003 : Local<Object> ApiCallOptimizationChecker::receiver;
24004 : Local<Object> ApiCallOptimizationChecker::holder;
24005 : Local<Object> ApiCallOptimizationChecker::callee;
24006 : int ApiCallOptimizationChecker::count = 0;
24007 :
24008 :
24009 23723 : TEST(FunctionCallOptimization) {
24010 5 : i::FLAG_allow_natives_syntax = true;
24011 : ApiCallOptimizationChecker checker;
24012 5 : checker.RunAll();
24013 5 : }
24014 :
24015 :
24016 23723 : TEST(FunctionCallOptimizationMultipleArgs) {
24017 5 : i::FLAG_allow_natives_syntax = true;
24018 5 : LocalContext context;
24019 5 : v8::Isolate* isolate = context->GetIsolate();
24020 10 : v8::HandleScope scope(isolate);
24021 5 : Local<Object> global = context->Global();
24022 : Local<v8::Function> function =
24023 10 : Function::New(context.local(), Returns42).ToLocalChecked();
24024 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24025 : CompileRun(
24026 : "function x_wrap() {\n"
24027 : " for (var i = 0; i < 5; i++) {\n"
24028 : " x(1,2,3);\n"
24029 : " }\n"
24030 : "}\n"
24031 : "x_wrap();\n"
24032 : "%OptimizeFunctionOnNextCall(x_wrap);"
24033 5 : "x_wrap();\n");
24034 5 : }
24035 :
24036 :
24037 50 : static void ReturnsSymbolCallback(
24038 100 : const v8::FunctionCallbackInfo<v8::Value>& info) {
24039 100 : info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
24040 50 : }
24041 :
24042 :
24043 23723 : TEST(ApiCallbackCanReturnSymbols) {
24044 5 : i::FLAG_allow_natives_syntax = true;
24045 5 : LocalContext context;
24046 5 : v8::Isolate* isolate = context->GetIsolate();
24047 10 : v8::HandleScope scope(isolate);
24048 5 : Local<Object> global = context->Global();
24049 : Local<v8::Function> function =
24050 10 : Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
24051 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24052 : CompileRun(
24053 : "function x_wrap() {\n"
24054 : " for (var i = 0; i < 5; i++) {\n"
24055 : " x();\n"
24056 : " }\n"
24057 : "}\n"
24058 : "x_wrap();\n"
24059 : "%OptimizeFunctionOnNextCall(x_wrap);"
24060 5 : "x_wrap();\n");
24061 5 : }
24062 :
24063 :
24064 23723 : TEST(EmptyApiCallback) {
24065 5 : LocalContext context;
24066 5 : auto isolate = context->GetIsolate();
24067 10 : v8::HandleScope scope(isolate);
24068 5 : auto global = context->Global();
24069 5 : auto function = FunctionTemplate::New(isolate)
24070 15 : ->GetFunction(context.local())
24071 5 : .ToLocalChecked();
24072 20 : global->Set(context.local(), v8_str("x"), function).FromJust();
24073 :
24074 : auto result = CompileRun("x()");
24075 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24076 :
24077 : result = CompileRun("x(1,2,3)");
24078 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24079 :
24080 : result = CompileRun("x.call(undefined)");
24081 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24082 :
24083 : result = CompileRun("x.call(null)");
24084 5 : CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
24085 :
24086 : result = CompileRun("7 + x.call(3) + 11");
24087 5 : CHECK(result->IsInt32());
24088 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
24089 :
24090 : result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
24091 5 : CHECK(result->IsInt32());
24092 10 : CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
24093 :
24094 : result = CompileRun("var y = []; x.call(y)");
24095 5 : CHECK(result->IsArray());
24096 :
24097 : result = CompileRun("x.call(y, 1, 2, 3, 4)");
24098 10 : CHECK(result->IsArray());
24099 5 : }
24100 :
24101 :
24102 23723 : TEST(SimpleSignatureCheck) {
24103 5 : LocalContext context;
24104 5 : auto isolate = context->GetIsolate();
24105 10 : v8::HandleScope scope(isolate);
24106 5 : auto global = context->Global();
24107 5 : auto sig_obj = FunctionTemplate::New(isolate);
24108 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24109 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24110 : global->Set(context.local(), v8_str("sig_obj"),
24111 25 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24112 10 : .FromJust();
24113 : global->Set(context.local(), v8_str("x"),
24114 25 : x->GetFunction(context.local()).ToLocalChecked())
24115 10 : .FromJust();
24116 : CompileRun("var s = new sig_obj();");
24117 : {
24118 5 : TryCatch try_catch(isolate);
24119 : CompileRun("x()");
24120 5 : CHECK(try_catch.HasCaught());
24121 : }
24122 : {
24123 5 : TryCatch try_catch(isolate);
24124 : CompileRun("x.call(1)");
24125 5 : CHECK(try_catch.HasCaught());
24126 : }
24127 : {
24128 5 : TryCatch try_catch(isolate);
24129 : auto result = CompileRun("s.x = x; s.x()");
24130 5 : CHECK(!try_catch.HasCaught());
24131 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24132 : }
24133 : {
24134 5 : TryCatch try_catch(isolate);
24135 : auto result = CompileRun("x.call(s)");
24136 5 : CHECK(!try_catch.HasCaught());
24137 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24138 5 : }
24139 5 : }
24140 :
24141 :
24142 23723 : TEST(ChainSignatureCheck) {
24143 5 : LocalContext context;
24144 5 : auto isolate = context->GetIsolate();
24145 10 : v8::HandleScope scope(isolate);
24146 5 : auto global = context->Global();
24147 5 : auto sig_obj = FunctionTemplate::New(isolate);
24148 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24149 25 : for (int i = 0; i < 4; ++i) {
24150 20 : auto temp = FunctionTemplate::New(isolate);
24151 20 : temp->Inherit(sig_obj);
24152 : sig_obj = temp;
24153 : }
24154 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24155 : global->Set(context.local(), v8_str("sig_obj"),
24156 20 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24157 10 : .FromJust();
24158 : global->Set(context.local(), v8_str("x"),
24159 25 : x->GetFunction(context.local()).ToLocalChecked())
24160 10 : .FromJust();
24161 : CompileRun("var s = new sig_obj();");
24162 : {
24163 5 : TryCatch try_catch(isolate);
24164 : CompileRun("x()");
24165 5 : CHECK(try_catch.HasCaught());
24166 : }
24167 : {
24168 5 : TryCatch try_catch(isolate);
24169 : CompileRun("x.call(1)");
24170 5 : CHECK(try_catch.HasCaught());
24171 : }
24172 : {
24173 5 : TryCatch try_catch(isolate);
24174 : auto result = CompileRun("s.x = x; s.x()");
24175 5 : CHECK(!try_catch.HasCaught());
24176 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24177 : }
24178 : {
24179 5 : TryCatch try_catch(isolate);
24180 : auto result = CompileRun("x.call(s)");
24181 5 : CHECK(!try_catch.HasCaught());
24182 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24183 5 : }
24184 5 : }
24185 :
24186 :
24187 23723 : TEST(PrototypeSignatureCheck) {
24188 5 : LocalContext context;
24189 5 : auto isolate = context->GetIsolate();
24190 10 : v8::HandleScope scope(isolate);
24191 5 : auto global = context->Global();
24192 5 : auto sig_obj = FunctionTemplate::New(isolate);
24193 5 : sig_obj->SetHiddenPrototype(true);
24194 5 : auto sig = v8::Signature::New(isolate, sig_obj);
24195 5 : auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
24196 : global->Set(context.local(), v8_str("sig_obj"),
24197 20 : sig_obj->GetFunction(context.local()).ToLocalChecked())
24198 10 : .FromJust();
24199 : global->Set(context.local(), v8_str("x"),
24200 25 : x->GetFunction(context.local()).ToLocalChecked())
24201 10 : .FromJust();
24202 : CompileRun("s = {}; s.__proto__ = new sig_obj();");
24203 : {
24204 5 : TryCatch try_catch(isolate);
24205 : CompileRun("x()");
24206 5 : CHECK(try_catch.HasCaught());
24207 : }
24208 : {
24209 5 : TryCatch try_catch(isolate);
24210 : CompileRun("x.call(1)");
24211 5 : CHECK(try_catch.HasCaught());
24212 : }
24213 : {
24214 5 : TryCatch try_catch(isolate);
24215 : auto result = CompileRun("s.x = x; s.x()");
24216 5 : CHECK(!try_catch.HasCaught());
24217 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24218 : }
24219 : {
24220 5 : TryCatch try_catch(isolate);
24221 : auto result = CompileRun("x.call(s)");
24222 5 : CHECK(!try_catch.HasCaught());
24223 10 : CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
24224 5 : }
24225 5 : }
24226 :
24227 :
24228 : static const char* last_event_message;
24229 : static int last_event_status;
24230 10 : void StoringEventLoggerCallback(const char* message, int status) {
24231 10 : last_event_message = message;
24232 10 : last_event_status = status;
24233 10 : }
24234 :
24235 :
24236 23723 : TEST(EventLogging) {
24237 5 : v8::Isolate* isolate = CcTest::isolate();
24238 5 : isolate->SetEventLogger(StoringEventLoggerCallback);
24239 : v8::internal::HistogramTimer histogramTimer(
24240 : "V8.Test", 0, 10000, v8::internal::HistogramTimerResolution::MILLISECOND,
24241 : 50, reinterpret_cast<v8::internal::Isolate*>(isolate)->counters());
24242 : histogramTimer.Start();
24243 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
24244 5 : CHECK_EQ(0, last_event_status);
24245 : histogramTimer.Stop();
24246 5 : CHECK_EQ(0, strcmp("V8.Test", last_event_message));
24247 5 : CHECK_EQ(1, last_event_status);
24248 5 : }
24249 :
24250 23723 : TEST(PropertyDescriptor) {
24251 5 : LocalContext context;
24252 5 : v8::Isolate* isolate = context->GetIsolate();
24253 10 : v8::HandleScope scope(isolate);
24254 :
24255 : { // empty descriptor
24256 5 : v8::PropertyDescriptor desc;
24257 5 : CHECK(!desc.has_value());
24258 5 : CHECK(!desc.has_set());
24259 5 : CHECK(!desc.has_get());
24260 5 : CHECK(!desc.has_enumerable());
24261 5 : CHECK(!desc.has_configurable());
24262 5 : CHECK(!desc.has_writable());
24263 : }
24264 : {
24265 : // data descriptor
24266 5 : v8::PropertyDescriptor desc(v8_num(42));
24267 5 : desc.set_enumerable(false);
24268 10 : CHECK(desc.value() == v8_num(42));
24269 5 : CHECK(desc.has_value());
24270 5 : CHECK(!desc.has_set());
24271 5 : CHECK(!desc.has_get());
24272 5 : CHECK(desc.has_enumerable());
24273 5 : CHECK(!desc.enumerable());
24274 5 : CHECK(!desc.has_configurable());
24275 5 : CHECK(!desc.has_writable());
24276 : }
24277 : {
24278 : // data descriptor
24279 5 : v8::PropertyDescriptor desc(v8_num(42));
24280 5 : desc.set_configurable(true);
24281 10 : CHECK(desc.value() == v8_num(42));
24282 5 : CHECK(desc.has_value());
24283 5 : CHECK(!desc.has_set());
24284 5 : CHECK(!desc.has_get());
24285 5 : CHECK(desc.has_configurable());
24286 5 : CHECK(desc.configurable());
24287 5 : CHECK(!desc.has_enumerable());
24288 5 : CHECK(!desc.has_writable());
24289 : }
24290 : {
24291 : // data descriptor
24292 5 : v8::PropertyDescriptor desc(v8_num(42));
24293 5 : desc.set_configurable(false);
24294 10 : CHECK(desc.value() == v8_num(42));
24295 5 : CHECK(desc.has_value());
24296 5 : CHECK(!desc.has_set());
24297 5 : CHECK(!desc.has_get());
24298 5 : CHECK(desc.has_configurable());
24299 5 : CHECK(!desc.configurable());
24300 5 : CHECK(!desc.has_enumerable());
24301 5 : CHECK(!desc.has_writable());
24302 : }
24303 : {
24304 : // data descriptor
24305 5 : v8::PropertyDescriptor desc(v8_num(42), false);
24306 10 : CHECK(desc.value() == v8_num(42));
24307 5 : CHECK(desc.has_value());
24308 5 : CHECK(!desc.has_set());
24309 5 : CHECK(!desc.has_get());
24310 5 : CHECK(!desc.has_enumerable());
24311 5 : CHECK(!desc.has_configurable());
24312 5 : CHECK(desc.has_writable());
24313 5 : CHECK(!desc.writable());
24314 : }
24315 : {
24316 : // data descriptor
24317 5 : v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true);
24318 5 : CHECK(!desc.has_value());
24319 5 : CHECK(!desc.has_set());
24320 5 : CHECK(!desc.has_get());
24321 5 : CHECK(!desc.has_enumerable());
24322 5 : CHECK(!desc.has_configurable());
24323 5 : CHECK(desc.has_writable());
24324 5 : CHECK(desc.writable());
24325 : }
24326 : {
24327 : // accessor descriptor
24328 : CompileRun("var set = function() {return 43;};");
24329 :
24330 : v8::Local<v8::Function> set =
24331 : v8::Local<v8::Function>::Cast(context->Global()
24332 20 : ->Get(context.local(), v8_str("set"))
24333 5 : .ToLocalChecked());
24334 5 : v8::PropertyDescriptor desc(v8::Undefined(isolate), set);
24335 5 : desc.set_configurable(false);
24336 5 : CHECK(!desc.has_value());
24337 5 : CHECK(desc.has_get());
24338 10 : CHECK(desc.get() == v8::Undefined(isolate));
24339 5 : CHECK(desc.has_set());
24340 10 : CHECK(desc.set() == set);
24341 5 : CHECK(!desc.has_enumerable());
24342 5 : CHECK(desc.has_configurable());
24343 5 : CHECK(!desc.configurable());
24344 5 : CHECK(!desc.has_writable());
24345 : }
24346 : {
24347 : // accessor descriptor with Proxy
24348 : CompileRun(
24349 : "var set = new Proxy(function() {}, {});"
24350 : "var get = undefined;");
24351 :
24352 : v8::Local<v8::Value> get =
24353 : v8::Local<v8::Value>::Cast(context->Global()
24354 20 : ->Get(context.local(), v8_str("get"))
24355 10 : .ToLocalChecked());
24356 : v8::Local<v8::Function> set =
24357 : v8::Local<v8::Function>::Cast(context->Global()
24358 20 : ->Get(context.local(), v8_str("set"))
24359 5 : .ToLocalChecked());
24360 5 : v8::PropertyDescriptor desc(get, set);
24361 5 : desc.set_configurable(false);
24362 5 : CHECK(!desc.has_value());
24363 10 : CHECK(desc.get() == v8::Undefined(isolate));
24364 5 : CHECK(desc.has_get());
24365 10 : CHECK(desc.set() == set);
24366 5 : CHECK(desc.has_set());
24367 5 : CHECK(!desc.has_enumerable());
24368 5 : CHECK(desc.has_configurable());
24369 5 : CHECK(!desc.configurable());
24370 5 : CHECK(!desc.has_writable());
24371 : }
24372 : {
24373 : // accessor descriptor with empty function handle
24374 : v8::Local<v8::Function> get = v8::Local<v8::Function>();
24375 5 : v8::PropertyDescriptor desc(get, get);
24376 5 : CHECK(!desc.has_value());
24377 5 : CHECK(!desc.has_get());
24378 5 : CHECK(!desc.has_set());
24379 5 : CHECK(!desc.has_enumerable());
24380 5 : CHECK(!desc.has_configurable());
24381 5 : CHECK(!desc.has_writable());
24382 5 : }
24383 5 : }
24384 :
24385 23723 : TEST(Promises) {
24386 5 : LocalContext context;
24387 5 : v8::Isolate* isolate = context->GetIsolate();
24388 10 : v8::HandleScope scope(isolate);
24389 :
24390 : // Creation.
24391 : Local<v8::Promise::Resolver> pr =
24392 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24393 : Local<v8::Promise::Resolver> rr =
24394 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24395 5 : Local<v8::Promise> p = pr->GetPromise();
24396 5 : Local<v8::Promise> r = rr->GetPromise();
24397 :
24398 : // IsPromise predicate.
24399 5 : CHECK(p->IsPromise());
24400 5 : CHECK(r->IsPromise());
24401 5 : Local<Value> o = v8::Object::New(isolate);
24402 5 : CHECK(!o->IsPromise());
24403 :
24404 : // Resolution and rejection.
24405 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24406 5 : CHECK(p->IsPromise());
24407 15 : rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
24408 10 : CHECK(r->IsPromise());
24409 5 : }
24410 :
24411 :
24412 23723 : TEST(PromiseThen) {
24413 5 : LocalContext context;
24414 5 : v8::Isolate* isolate = context->GetIsolate();
24415 5 : isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24416 10 : v8::HandleScope scope(isolate);
24417 5 : Local<Object> global = context->Global();
24418 :
24419 : // Creation.
24420 : Local<v8::Promise::Resolver> pr =
24421 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24422 : Local<v8::Promise::Resolver> qr =
24423 5 : v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24424 5 : Local<v8::Promise> p = pr->GetPromise();
24425 5 : Local<v8::Promise> q = qr->GetPromise();
24426 :
24427 5 : CHECK(p->IsPromise());
24428 5 : CHECK(q->IsPromise());
24429 :
24430 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24431 10 : qr->Resolve(context.local(), p).FromJust();
24432 :
24433 : // Chaining non-pending promises.
24434 : CompileRun(
24435 : "var x1 = 0;\n"
24436 : "var x2 = 0;\n"
24437 : "function f1(x) { x1 = x; return x+1 };\n"
24438 : "function f2(x) { x2 = x; return x+1 };\n");
24439 : Local<Function> f1 = Local<Function>::Cast(
24440 15 : global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24441 : Local<Function> f2 = Local<Function>::Cast(
24442 15 : global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24443 :
24444 : // Then
24445 : CompileRun("x1 = x2 = 0;");
24446 5 : q->Then(context.local(), f1).ToLocalChecked();
24447 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24448 : .ToLocalChecked()
24449 : ->Int32Value(context.local())
24450 : .FromJust());
24451 5 : isolate->RunMicrotasks();
24452 20 : CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24453 : .ToLocalChecked()
24454 : ->Int32Value(context.local())
24455 : .FromJust());
24456 :
24457 : // Then
24458 : CompileRun("x1 = x2 = 0;");
24459 5 : pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24460 5 : qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24461 :
24462 10 : qr->Resolve(context.local(), pr).FromJust();
24463 : qr->GetPromise()
24464 10 : ->Then(context.local(), f1)
24465 5 : .ToLocalChecked()
24466 5 : ->Then(context.local(), f2)
24467 5 : .ToLocalChecked();
24468 :
24469 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24470 : .ToLocalChecked()
24471 : ->Int32Value(context.local())
24472 : .FromJust());
24473 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24474 : .ToLocalChecked()
24475 : ->Int32Value(context.local())
24476 : .FromJust());
24477 5 : isolate->RunMicrotasks();
24478 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24479 : .ToLocalChecked()
24480 : ->Int32Value(context.local())
24481 : .FromJust());
24482 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24483 : .ToLocalChecked()
24484 : ->Int32Value(context.local())
24485 : .FromJust());
24486 :
24487 15 : pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
24488 :
24489 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24490 : .ToLocalChecked()
24491 : ->Int32Value(context.local())
24492 : .FromJust());
24493 20 : CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24494 : .ToLocalChecked()
24495 : ->Int32Value(context.local())
24496 : .FromJust());
24497 5 : isolate->RunMicrotasks();
24498 20 : CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
24499 : .ToLocalChecked()
24500 : ->Int32Value(context.local())
24501 : .FromJust());
24502 20 : CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
24503 : .ToLocalChecked()
24504 : ->Int32Value(context.local())
24505 5 : .FromJust());
24506 5 : }
24507 :
24508 23723 : TEST(PromiseStateAndValue) {
24509 5 : LocalContext context;
24510 5 : v8::Isolate* isolate = context->GetIsolate();
24511 10 : v8::HandleScope scope(isolate);
24512 : v8::Local<v8::Value> result = CompileRun(
24513 : "var resolver;"
24514 : "new Promise((res, rej) => { resolver = res; })");
24515 : v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24516 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24517 :
24518 : CompileRun("resolver('fulfilled')");
24519 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24520 10 : CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24521 :
24522 : result = CompileRun("Promise.reject('rejected')");
24523 : promise = v8::Local<v8::Promise>::Cast(result);
24524 5 : CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24525 15 : CHECK(v8_str("rejected")->SameValue(promise->Result()));
24526 5 : }
24527 :
24528 23718 : TEST(DisallowJavascriptExecutionScope) {
24529 0 : LocalContext context;
24530 0 : v8::Isolate* isolate = context->GetIsolate();
24531 0 : v8::HandleScope scope(isolate);
24532 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24533 0 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24534 0 : CompileRun("2+2");
24535 0 : }
24536 :
24537 :
24538 23723 : TEST(AllowJavascriptExecutionScope) {
24539 5 : LocalContext context;
24540 5 : v8::Isolate* isolate = context->GetIsolate();
24541 10 : v8::HandleScope scope(isolate);
24542 : v8::Isolate::DisallowJavascriptExecutionScope no_js(
24543 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24544 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24545 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24546 5 : { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
24547 5 : CompileRun("1+1");
24548 5 : }
24549 5 : }
24550 :
24551 :
24552 23723 : TEST(ThrowOnJavascriptExecution) {
24553 5 : LocalContext context;
24554 5 : v8::Isolate* isolate = context->GetIsolate();
24555 10 : v8::HandleScope scope(isolate);
24556 10 : v8::TryCatch try_catch(isolate);
24557 : v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24558 10 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24559 : CompileRun("1+1");
24560 10 : CHECK(try_catch.HasCaught());
24561 5 : }
24562 :
24563 :
24564 23723 : TEST(Regress354123) {
24565 5 : LocalContext current;
24566 5 : v8::Isolate* isolate = current->GetIsolate();
24567 10 : v8::HandleScope scope(isolate);
24568 :
24569 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
24570 5 : templ->SetAccessCheckCallback(AccessCounter);
24571 30 : CHECK(current->Global()
24572 : ->Set(current.local(), v8_str("friend"),
24573 : templ->NewInstance(current.local()).ToLocalChecked())
24574 : .FromJust());
24575 :
24576 : // Test access using __proto__ from the prototype chain.
24577 5 : access_count = 0;
24578 : CompileRun("friend.__proto__ = {};");
24579 5 : CHECK_EQ(2, access_count);
24580 : CompileRun("friend.__proto__;");
24581 5 : CHECK_EQ(4, access_count);
24582 :
24583 : // Test access using __proto__ as a hijacked function (A).
24584 5 : access_count = 0;
24585 : CompileRun("var p = Object.prototype;"
24586 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
24587 : "f.call(friend, {});");
24588 5 : CHECK_EQ(1, access_count);
24589 : CompileRun("var p = Object.prototype;"
24590 : "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
24591 : "f.call(friend);");
24592 5 : CHECK_EQ(2, access_count);
24593 :
24594 : // Test access using __proto__ as a hijacked function (B).
24595 5 : access_count = 0;
24596 : CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
24597 : "f.call(friend, {});");
24598 5 : CHECK_EQ(1, access_count);
24599 : CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
24600 : "f.call(friend);");
24601 5 : CHECK_EQ(2, access_count);
24602 :
24603 : // Test access using Object.setPrototypeOf reflective method.
24604 5 : access_count = 0;
24605 : CompileRun("Object.setPrototypeOf(friend, {});");
24606 5 : CHECK_EQ(1, access_count);
24607 : CompileRun("Object.getPrototypeOf(friend);");
24608 10 : CHECK_EQ(2, access_count);
24609 5 : }
24610 :
24611 :
24612 23723 : TEST(CaptureStackTraceForStackOverflow) {
24613 5 : v8::internal::FLAG_stack_size = 150;
24614 5 : LocalContext current;
24615 5 : v8::Isolate* isolate = current->GetIsolate();
24616 10 : v8::HandleScope scope(isolate);
24617 : isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
24618 5 : v8::StackTrace::kDetailed);
24619 10 : v8::TryCatch try_catch(isolate);
24620 : CompileRun("(function f(x) { f(x+1); })(0)");
24621 10 : CHECK(try_catch.HasCaught());
24622 5 : }
24623 :
24624 :
24625 23723 : TEST(ScriptNameAndLineNumber) {
24626 5 : LocalContext env;
24627 5 : v8::Isolate* isolate = env->GetIsolate();
24628 10 : v8::HandleScope scope(isolate);
24629 : const char* url = "http://www.foo.com/foo.js";
24630 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24631 5 : v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
24632 : Local<Script> script =
24633 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24634 10 : Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
24635 5 : CHECK(!script_name.IsEmpty());
24636 5 : CHECK(script_name->IsString());
24637 10 : String::Utf8Value utf8_name(env->GetIsolate(), script_name);
24638 5 : CHECK_EQ(0, strcmp(url, *utf8_name));
24639 10 : int line_number = script->GetUnboundScript()->GetLineNumber(0);
24640 10 : CHECK_EQ(13, line_number);
24641 5 : }
24642 :
24643 23723 : TEST(ScriptPositionInfo) {
24644 5 : LocalContext env;
24645 5 : v8::Isolate* isolate = env->GetIsolate();
24646 10 : v8::HandleScope scope(isolate);
24647 : const char* url = "http://www.foo.com/foo.js";
24648 5 : v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24649 : v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
24650 : "var bar;\n"
24651 : "var fisk = foo + bar;\n"),
24652 5 : origin);
24653 : Local<Script> script =
24654 5 : v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24655 :
24656 : i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
24657 10 : v8::Utils::OpenHandle(*script->GetUnboundScript()));
24658 5 : CHECK(obj->script()->IsScript());
24659 :
24660 : i::Handle<i::Script> script1(i::Script::cast(obj->script()));
24661 :
24662 : v8::internal::Script::PositionInfo info;
24663 :
24664 15 : for (int i = 0; i < 2; ++i) {
24665 : // With offset.
24666 :
24667 : // Behave as if 0 was passed if position is negative.
24668 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
24669 10 : CHECK_EQ(13, info.line);
24670 10 : CHECK_EQ(0, info.column);
24671 10 : CHECK_EQ(0, info.line_start);
24672 10 : CHECK_EQ(8, info.line_end);
24673 :
24674 10 : CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
24675 10 : CHECK_EQ(13, info.line);
24676 10 : CHECK_EQ(0, info.column);
24677 10 : CHECK_EQ(0, info.line_start);
24678 10 : CHECK_EQ(8, info.line_end);
24679 :
24680 10 : CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
24681 10 : CHECK_EQ(13, info.line);
24682 10 : CHECK_EQ(8, info.column);
24683 10 : CHECK_EQ(0, info.line_start);
24684 10 : CHECK_EQ(8, info.line_end);
24685 :
24686 10 : CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
24687 10 : CHECK_EQ(14, info.line);
24688 10 : CHECK_EQ(0, info.column);
24689 10 : CHECK_EQ(9, info.line_start);
24690 10 : CHECK_EQ(17, info.line_end);
24691 :
24692 : // Fail when position is larger than script size.
24693 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
24694 :
24695 : // Without offset.
24696 :
24697 : // Behave as if 0 was passed if position is negative.
24698 10 : CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
24699 10 : CHECK_EQ(0, info.line);
24700 10 : CHECK_EQ(0, info.column);
24701 10 : CHECK_EQ(0, info.line_start);
24702 10 : CHECK_EQ(8, info.line_end);
24703 :
24704 10 : CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
24705 10 : CHECK_EQ(0, info.line);
24706 10 : CHECK_EQ(0, info.column);
24707 10 : CHECK_EQ(0, info.line_start);
24708 10 : CHECK_EQ(8, info.line_end);
24709 :
24710 10 : CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
24711 10 : CHECK_EQ(0, info.line);
24712 10 : CHECK_EQ(8, info.column);
24713 10 : CHECK_EQ(0, info.line_start);
24714 10 : CHECK_EQ(8, info.line_end);
24715 :
24716 10 : CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
24717 10 : CHECK_EQ(1, info.line);
24718 10 : CHECK_EQ(0, info.column);
24719 10 : CHECK_EQ(9, info.line_start);
24720 10 : CHECK_EQ(17, info.line_end);
24721 :
24722 : // Fail when position is larger than script size.
24723 10 : CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
24724 :
24725 10 : i::Script::InitLineEnds(script1);
24726 5 : }
24727 5 : }
24728 :
24729 155 : void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
24730 : const char* expected_source_url,
24731 : const char* expected_source_mapping_url) {
24732 155 : if (expected_source_url != nullptr) {
24733 : v8::String::Utf8Value url(isolate,
24734 70 : script->GetUnboundScript()->GetSourceURL());
24735 35 : CHECK_EQ(0, strcmp(expected_source_url, *url));
24736 : } else {
24737 360 : CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24738 : }
24739 155 : if (expected_source_mapping_url != nullptr) {
24740 : v8::String::Utf8Value url(
24741 60 : isolate, script->GetUnboundScript()->GetSourceMappingURL());
24742 30 : CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
24743 : } else {
24744 375 : CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24745 : }
24746 155 : }
24747 :
24748 70 : void SourceURLHelper(v8::Isolate* isolate, const char* source,
24749 : const char* expected_source_url,
24750 : const char* expected_source_mapping_url) {
24751 70 : Local<Script> script = v8_compile(source);
24752 : CheckMagicComments(isolate, script, expected_source_url,
24753 70 : expected_source_mapping_url);
24754 70 : }
24755 :
24756 :
24757 23723 : TEST(ScriptSourceURLAndSourceMappingURL) {
24758 5 : LocalContext env;
24759 5 : v8::Isolate* isolate = env->GetIsolate();
24760 10 : v8::HandleScope scope(isolate);
24761 : SourceURLHelper(isolate,
24762 : "function foo() {}\n"
24763 : "//# sourceURL=bar1.js\n",
24764 5 : "bar1.js", nullptr);
24765 : SourceURLHelper(isolate,
24766 : "function foo() {}\n"
24767 : "//# sourceMappingURL=bar2.js\n",
24768 5 : nullptr, "bar2.js");
24769 :
24770 : // Both sourceURL and sourceMappingURL.
24771 : SourceURLHelper(isolate,
24772 : "function foo() {}\n"
24773 : "//# sourceURL=bar3.js\n"
24774 : "//# sourceMappingURL=bar4.js\n",
24775 5 : "bar3.js", "bar4.js");
24776 :
24777 : // Two source URLs; the first one is ignored.
24778 : SourceURLHelper(isolate,
24779 : "function foo() {}\n"
24780 : "//# sourceURL=ignoreme.js\n"
24781 : "//# sourceURL=bar5.js\n",
24782 5 : "bar5.js", nullptr);
24783 : SourceURLHelper(isolate,
24784 : "function foo() {}\n"
24785 : "//# sourceMappingURL=ignoreme.js\n"
24786 : "//# sourceMappingURL=bar6.js\n",
24787 5 : nullptr, "bar6.js");
24788 :
24789 : // SourceURL or sourceMappingURL in the middle of the script.
24790 : SourceURLHelper(isolate,
24791 : "function foo() {}\n"
24792 : "//# sourceURL=bar7.js\n"
24793 : "function baz() {}\n",
24794 5 : "bar7.js", nullptr);
24795 : SourceURLHelper(isolate,
24796 : "function foo() {}\n"
24797 : "//# sourceMappingURL=bar8.js\n"
24798 : "function baz() {}\n",
24799 5 : nullptr, "bar8.js");
24800 :
24801 : // Too much whitespace.
24802 : SourceURLHelper(isolate,
24803 : "function foo() {}\n"
24804 : "//# sourceURL=bar9.js\n"
24805 : "//# sourceMappingURL=bar10.js\n",
24806 5 : nullptr, nullptr);
24807 : SourceURLHelper(isolate,
24808 : "function foo() {}\n"
24809 : "//# sourceURL =bar11.js\n"
24810 : "//# sourceMappingURL =bar12.js\n",
24811 5 : nullptr, nullptr);
24812 :
24813 : // Disallowed characters in value.
24814 : SourceURLHelper(isolate,
24815 : "function foo() {}\n"
24816 : "//# sourceURL=bar13 .js \n"
24817 : "//# sourceMappingURL=bar14 .js \n",
24818 5 : nullptr, nullptr);
24819 : SourceURLHelper(isolate,
24820 : "function foo() {}\n"
24821 : "//# sourceURL=bar15\t.js \n"
24822 : "//# sourceMappingURL=bar16\t.js \n",
24823 5 : nullptr, nullptr);
24824 : SourceURLHelper(isolate,
24825 : "function foo() {}\n"
24826 : "//# sourceURL=bar17'.js \n"
24827 : "//# sourceMappingURL=bar18'.js \n",
24828 5 : nullptr, nullptr);
24829 : SourceURLHelper(isolate,
24830 : "function foo() {}\n"
24831 : "//# sourceURL=bar19\".js \n"
24832 : "//# sourceMappingURL=bar20\".js \n",
24833 5 : nullptr, nullptr);
24834 :
24835 : // Not too much whitespace.
24836 : SourceURLHelper(isolate,
24837 : "function foo() {}\n"
24838 : "//# sourceURL= bar21.js \n"
24839 : "//# sourceMappingURL= bar22.js \n",
24840 10 : "bar21.js", "bar22.js");
24841 5 : }
24842 :
24843 :
24844 23723 : TEST(GetOwnPropertyDescriptor) {
24845 5 : LocalContext env;
24846 5 : v8::Isolate* isolate = env->GetIsolate();
24847 10 : v8::HandleScope scope(isolate);
24848 : CompileRun(
24849 : "var x = { value : 13};"
24850 : "Object.defineProperty(x, 'p0', {value : 12});"
24851 : "Object.defineProperty(x, Symbol.toStringTag, {value: 'foo'});"
24852 : "Object.defineProperty(x, 'p1', {"
24853 : " set : function(value) { this.value = value; },"
24854 : " get : function() { return this.value; },"
24855 : "});");
24856 : Local<Object> x = Local<Object>::Cast(
24857 25 : env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
24858 : Local<Value> desc =
24859 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
24860 5 : .ToLocalChecked();
24861 5 : CHECK(desc->IsUndefined());
24862 : desc =
24863 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
24864 25 : CHECK(v8_num(12)
24865 : ->Equals(env.local(), Local<Object>::Cast(desc)
24866 : ->Get(env.local(), v8_str("value"))
24867 : .ToLocalChecked())
24868 : .FromJust());
24869 : desc =
24870 15 : x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
24871 : Local<Function> set =
24872 : Local<Function>::Cast(Local<Object>::Cast(desc)
24873 15 : ->Get(env.local(), v8_str("set"))
24874 5 : .ToLocalChecked());
24875 : Local<Function> get =
24876 : Local<Function>::Cast(Local<Object>::Cast(desc)
24877 15 : ->Get(env.local(), v8_str("get"))
24878 5 : .ToLocalChecked());
24879 20 : CHECK(v8_num(13)
24880 : ->Equals(env.local(),
24881 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24882 : .FromJust());
24883 5 : Local<Value> args[] = {v8_num(14)};
24884 10 : set->Call(env.local(), x, 1, args).ToLocalChecked();
24885 20 : CHECK(v8_num(14)
24886 : ->Equals(env.local(),
24887 : get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24888 : .FromJust());
24889 : desc =
24890 15 : x->GetOwnPropertyDescriptor(env.local(), Symbol::GetToStringTag(isolate))
24891 5 : .ToLocalChecked();
24892 25 : CHECK(v8_str("foo")
24893 : ->Equals(env.local(), Local<Object>::Cast(desc)
24894 : ->Get(env.local(), v8_str("value"))
24895 : .ToLocalChecked())
24896 5 : .FromJust());
24897 5 : }
24898 :
24899 :
24900 23723 : TEST(Regress411877) {
24901 5 : v8::Isolate* isolate = CcTest::isolate();
24902 5 : v8::HandleScope handle_scope(isolate);
24903 : v8::Local<v8::ObjectTemplate> object_template =
24904 5 : v8::ObjectTemplate::New(isolate);
24905 5 : object_template->SetAccessCheckCallback(AccessCounter);
24906 :
24907 5 : v8::Local<Context> context = Context::New(isolate);
24908 : v8::Context::Scope context_scope(context);
24909 :
24910 25 : CHECK(context->Global()
24911 : ->Set(context, v8_str("o"),
24912 : object_template->NewInstance(context).ToLocalChecked())
24913 : .FromJust());
24914 5 : CompileRun("Object.getOwnPropertyNames(o)");
24915 5 : }
24916 :
24917 :
24918 23723 : TEST(GetHiddenPropertyTableAfterAccessCheck) {
24919 5 : v8::Isolate* isolate = CcTest::isolate();
24920 5 : v8::HandleScope handle_scope(isolate);
24921 : v8::Local<v8::ObjectTemplate> object_template =
24922 5 : v8::ObjectTemplate::New(isolate);
24923 5 : object_template->SetAccessCheckCallback(AccessCounter);
24924 :
24925 5 : v8::Local<Context> context = Context::New(isolate);
24926 : v8::Context::Scope context_scope(context);
24927 :
24928 : v8::Local<v8::Object> obj =
24929 5 : object_template->NewInstance(context).ToLocalChecked();
24930 20 : obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
24931 15 : obj->Delete(context, v8_str("key")).FromJust();
24932 :
24933 : obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
24934 15 : v8_str("hidden value 2"))
24935 15 : .FromJust();
24936 5 : }
24937 :
24938 :
24939 23723 : TEST(Regress411793) {
24940 5 : v8::Isolate* isolate = CcTest::isolate();
24941 5 : v8::HandleScope handle_scope(isolate);
24942 : v8::Local<v8::ObjectTemplate> object_template =
24943 5 : v8::ObjectTemplate::New(isolate);
24944 5 : object_template->SetAccessCheckCallback(AccessCounter);
24945 :
24946 5 : v8::Local<Context> context = Context::New(isolate);
24947 : v8::Context::Scope context_scope(context);
24948 :
24949 25 : CHECK(context->Global()
24950 : ->Set(context, v8_str("o"),
24951 : object_template->NewInstance(context).ToLocalChecked())
24952 : .FromJust());
24953 : CompileRun(
24954 : "Object.defineProperty(o, 'key', "
24955 5 : " { get: function() {}, set: function() {} });");
24956 5 : }
24957 :
24958 220 : class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24959 : public:
24960 110 : explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24961 :
24962 430 : virtual size_t GetMoreData(const uint8_t** src) {
24963 : // Unlike in real use cases, this function will never block.
24964 430 : if (chunks_[index_] == nullptr) {
24965 : return 0;
24966 : }
24967 : // Copy the data, since the caller takes ownership of it.
24968 330 : size_t len = strlen(chunks_[index_]);
24969 : // We don't need to zero-terminate since we return the length.
24970 330 : uint8_t* copy = new uint8_t[len];
24971 330 : memcpy(copy, chunks_[index_], len);
24972 330 : *src = copy;
24973 330 : ++index_;
24974 330 : return len;
24975 : }
24976 :
24977 : // Helper for constructing a string from chunks (the compilation needs it
24978 : // too).
24979 105 : static char* FullSourceString(const char** chunks) {
24980 : size_t total_len = 0;
24981 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24982 330 : total_len += strlen(chunks[i]);
24983 : }
24984 105 : char* full_string = new char[total_len + 1];
24985 : size_t offset = 0;
24986 435 : for (size_t i = 0; chunks[i] != nullptr; ++i) {
24987 330 : size_t len = strlen(chunks[i]);
24988 330 : memcpy(full_string + offset, chunks[i], len);
24989 330 : offset += len;
24990 : }
24991 105 : full_string[total_len] = 0;
24992 105 : return full_string;
24993 : }
24994 :
24995 : private:
24996 : const char** chunks_;
24997 : unsigned index_;
24998 : };
24999 :
25000 :
25001 : // Helper function for running streaming tests.
25002 95 : void RunStreamingTest(const char** chunks,
25003 : v8::ScriptCompiler::StreamedSource::Encoding encoding =
25004 : v8::ScriptCompiler::StreamedSource::ONE_BYTE,
25005 : bool expected_success = true,
25006 : const char* expected_source_url = nullptr,
25007 : const char* expected_source_mapping_url = nullptr) {
25008 95 : LocalContext env;
25009 95 : v8::Isolate* isolate = env->GetIsolate();
25010 190 : v8::HandleScope scope(isolate);
25011 190 : v8::TryCatch try_catch(isolate);
25012 :
25013 : v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
25014 285 : encoding);
25015 : v8::ScriptCompiler::ScriptStreamingTask* task =
25016 95 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25017 :
25018 : // TestSourceStream::GetMoreData won't block, so it's OK to just run the
25019 : // task here in the main thread.
25020 95 : task->Run();
25021 95 : delete task;
25022 :
25023 : // Possible errors are only produced while compiling.
25024 95 : CHECK(!try_catch.HasCaught());
25025 :
25026 95 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25027 95 : char* full_source = TestSourceStream::FullSourceString(chunks);
25028 : v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
25029 95 : env.local(), &source, v8_str(full_source), origin);
25030 95 : if (expected_success) {
25031 85 : CHECK(!script.IsEmpty());
25032 : v8::Local<Value> result(
25033 170 : script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
25034 : // All scripts are supposed to return the fixed value 13 when ran.
25035 170 : CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
25036 : CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
25037 85 : expected_source_mapping_url);
25038 : } else {
25039 10 : CHECK(script.IsEmpty());
25040 10 : CHECK(try_catch.HasCaught());
25041 : }
25042 190 : delete[] full_source;
25043 95 : }
25044 :
25045 23723 : TEST(StreamingSimpleScript) {
25046 : // This script is unrealistically small, since no one chunk is enough to fill
25047 : // the backing buffer of Scanner, let alone overflow it.
25048 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
25049 5 : nullptr};
25050 5 : RunStreamingTest(chunks);
25051 5 : }
25052 :
25053 23723 : TEST(StreamingScriptConstantArray) {
25054 : // When run with Ignition, tests that the streaming parser canonicalizes
25055 : // handles so that they are only added to the constant pool array once.
25056 : const char* chunks[] = {
25057 : "var a = {};", "var b = {};", "var c = 'testing';",
25058 5 : "var d = 'testing';", "13;", nullptr};
25059 5 : RunStreamingTest(chunks);
25060 5 : }
25061 :
25062 23723 : TEST(StreamingScriptEvalShadowing) {
25063 : // When run with Ignition, tests that the streaming parser canonicalizes
25064 : // handles so the Variable::is_possibly_eval() is correct.
25065 : const char* chunk1 =
25066 : "(function() {\n"
25067 : " var y = 2;\n"
25068 : " return (function() {\n"
25069 : " eval('var y = 13;');\n"
25070 : " function g() {\n"
25071 : " return y\n"
25072 : " }\n"
25073 : " return g();\n"
25074 : " })()\n"
25075 : "})()\n";
25076 5 : const char* chunks[] = {chunk1, nullptr};
25077 5 : RunStreamingTest(chunks);
25078 5 : }
25079 :
25080 23723 : TEST(StreamingBiggerScript) {
25081 : const char* chunk1 =
25082 : "function foo() {\n"
25083 : " // Make this chunk sufficiently long so that it will overflow the\n"
25084 : " // backing buffer of the Scanner.\n"
25085 : " var i = 0;\n"
25086 : " var result = 0;\n"
25087 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25088 : " result = 0;\n"
25089 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25090 : " result = 0;\n"
25091 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25092 : " result = 0;\n"
25093 : " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
25094 : " return result;\n"
25095 : "}\n";
25096 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
25097 5 : RunStreamingTest(chunks);
25098 5 : }
25099 :
25100 :
25101 23723 : TEST(StreamingScriptWithParseError) {
25102 : // Test that parse errors from streamed scripts are propagated correctly.
25103 : {
25104 : char chunk1[] =
25105 : " // This will result in a parse error.\n"
25106 5 : " var if else then foo";
25107 5 : char chunk2[] = " 13\n";
25108 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25109 :
25110 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
25111 5 : false);
25112 : }
25113 : // Test that the next script succeeds normally.
25114 : {
25115 : char chunk1[] =
25116 : " // This will be parsed successfully.\n"
25117 5 : " function foo() { return ";
25118 5 : char chunk2[] = " 13; }\n";
25119 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25120 :
25121 5 : RunStreamingTest(chunks);
25122 : }
25123 5 : }
25124 :
25125 :
25126 23723 : TEST(StreamingUtf8Script) {
25127 : // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
25128 : // don't like it.
25129 : const char* chunk1 =
25130 : "function foo() {\n"
25131 : " // This function will contain an UTF-8 character which is not in\n"
25132 : " // ASCII.\n"
25133 : " var foob\xec\x92\x81r = 13;\n"
25134 : " return foob\xec\x92\x81r;\n"
25135 : "}\n";
25136 5 : const char* chunks[] = {chunk1, "foo(); ", nullptr};
25137 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25138 5 : }
25139 :
25140 :
25141 23723 : TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
25142 : // A sanity check to prove that the approach of splitting UTF-8
25143 : // characters is correct. Here is an UTF-8 character which will take three
25144 : // bytes.
25145 : const char* reference = "\xec\x92\x81";
25146 : CHECK_EQ(3, strlen(reference));
25147 :
25148 : char chunk1[] =
25149 : "function foo() {\n"
25150 : " // This function will contain an UTF-8 character which is not in\n"
25151 : " // ASCII.\n"
25152 5 : " var foob";
25153 : char chunk2[] =
25154 : "XXXr = 13;\n"
25155 : " return foob\xec\x92\x81r;\n"
25156 5 : "}\n";
25157 20 : for (int i = 0; i < 3; ++i) {
25158 15 : chunk2[i] = reference[i];
25159 : }
25160 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25161 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25162 5 : }
25163 :
25164 :
25165 23723 : TEST(StreamingUtf8ScriptWithSplitCharacters) {
25166 : // Stream data where a multi-byte UTF-8 character is split between two data
25167 : // chunks.
25168 : const char* reference = "\xec\x92\x81";
25169 : char chunk1[] =
25170 : "function foo() {\n"
25171 : " // This function will contain an UTF-8 character which is not in\n"
25172 : " // ASCII.\n"
25173 5 : " var foobX";
25174 : char chunk2[] =
25175 : "XXr = 13;\n"
25176 : " return foob\xec\x92\x81r;\n"
25177 5 : "}\n";
25178 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25179 5 : chunk2[0] = reference[1];
25180 5 : chunk2[1] = reference[2];
25181 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25182 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25183 5 : }
25184 :
25185 :
25186 23723 : TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
25187 : // Tests edge cases which should still be decoded correctly.
25188 :
25189 : // Case 1: a chunk contains only bytes for a split character (and no other
25190 : // data). This kind of a chunk would be exceptionally small, but we should
25191 : // still decode it correctly.
25192 : const char* reference = "\xec\x92\x81";
25193 : // The small chunk is at the beginning of the split character
25194 : {
25195 : char chunk1[] =
25196 : "function foo() {\n"
25197 : " // This function will contain an UTF-8 character which is not in\n"
25198 : " // ASCII.\n"
25199 5 : " var foob";
25200 5 : char chunk2[] = "XX";
25201 : char chunk3[] =
25202 : "Xr = 13;\n"
25203 : " return foob\xec\x92\x81r;\n"
25204 5 : "}\n";
25205 5 : chunk2[0] = reference[0];
25206 5 : chunk2[1] = reference[1];
25207 5 : chunk3[0] = reference[2];
25208 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25209 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25210 : }
25211 : // The small chunk is at the end of a character
25212 : {
25213 : char chunk1[] =
25214 : "function foo() {\n"
25215 : " // This function will contain an UTF-8 character which is not in\n"
25216 : " // ASCII.\n"
25217 5 : " var foobX";
25218 5 : char chunk2[] = "XX";
25219 : char chunk3[] =
25220 : "r = 13;\n"
25221 : " return foob\xec\x92\x81r;\n"
25222 5 : "}\n";
25223 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25224 5 : chunk2[0] = reference[1];
25225 5 : chunk2[1] = reference[2];
25226 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25227 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25228 : }
25229 : // Case 2: the script ends with a multi-byte character. Make sure that it's
25230 : // decoded correctly and not just ignored.
25231 : {
25232 : char chunk1[] =
25233 : "var foob\xec\x92\x81 = 13;\n"
25234 5 : "foob\xec\x92\x81";
25235 5 : const char* chunks[] = {chunk1, nullptr};
25236 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25237 : }
25238 5 : }
25239 :
25240 :
25241 23723 : TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
25242 : // Test cases where a UTF-8 character is split over several chunks. Those
25243 : // cases are not supported (the embedder should give the data in big enough
25244 : // chunks), but we shouldn't crash and parse this just fine.
25245 : const char* reference = "\xec\x92\x81";
25246 : char chunk1[] =
25247 : "function foo() {\n"
25248 : " // This function will contain an UTF-8 character which is not in\n"
25249 : " // ASCII.\n"
25250 5 : " var foobX";
25251 5 : char chunk2[] = "X";
25252 : char chunk3[] =
25253 : "Xr = 13;\n"
25254 : " return foob\xec\x92\x81r;\n"
25255 5 : "}\n";
25256 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25257 5 : chunk2[0] = reference[1];
25258 5 : chunk3[0] = reference[2];
25259 5 : const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25260 :
25261 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25262 5 : }
25263 :
25264 :
25265 23723 : TEST(StreamingProducesParserCache) {
25266 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
25267 5 : nullptr};
25268 :
25269 5 : LocalContext env;
25270 5 : v8::Isolate* isolate = env->GetIsolate();
25271 10 : v8::HandleScope scope(isolate);
25272 :
25273 : v8::ScriptCompiler::StreamedSource source(
25274 : new TestSourceStream(chunks),
25275 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25276 : v8::ScriptCompiler::ScriptStreamingTask* task =
25277 : v8::ScriptCompiler::StartStreamingScript(
25278 5 : isolate, &source, v8::ScriptCompiler::kProduceParserCache);
25279 :
25280 : // TestSourceStream::GetMoreData won't block, so it's OK to just run the
25281 : // task here in the main thread.
25282 5 : task->Run();
25283 5 : delete task;
25284 :
25285 5 : const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
25286 5 : CHECK_NOT_NULL(cached_data);
25287 5 : CHECK_NOT_NULL(cached_data->data);
25288 5 : CHECK(!cached_data->rejected);
25289 10 : CHECK_GT(cached_data->length, 0);
25290 5 : }
25291 :
25292 :
25293 23723 : TEST(StreamingWithDebuggingEnabledLate) {
25294 : // The streaming parser can only parse lazily, i.e. inner functions are not
25295 : // fully parsed. However, we may compile inner functions eagerly when
25296 : // debugging. Make sure that we can deal with this when turning on debugging
25297 : // after streaming parser has already finished parsing.
25298 : const char* chunks[] = {"with({x:1}) {",
25299 : " var foo = function foo(y) {",
25300 : " return x + y;",
25301 : " };",
25302 : " foo(2);",
25303 : "}",
25304 5 : nullptr};
25305 :
25306 5 : LocalContext env;
25307 5 : v8::Isolate* isolate = env->GetIsolate();
25308 10 : v8::HandleScope scope(isolate);
25309 10 : v8::TryCatch try_catch(isolate);
25310 :
25311 : v8::ScriptCompiler::StreamedSource source(
25312 : new TestSourceStream(chunks),
25313 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25314 : v8::ScriptCompiler::ScriptStreamingTask* task =
25315 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25316 :
25317 5 : task->Run();
25318 5 : delete task;
25319 :
25320 5 : CHECK(!try_catch.HasCaught());
25321 :
25322 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25323 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25324 :
25325 : EnableDebugger(isolate);
25326 :
25327 : v8::Local<Script> script =
25328 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25329 5 : origin)
25330 5 : .ToLocalChecked();
25331 :
25332 : Maybe<uint32_t> result =
25333 10 : script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
25334 5 : CHECK_EQ(3U, result.FromMaybe(0));
25335 :
25336 5 : delete[] full_source;
25337 :
25338 5 : DisableDebugger(isolate);
25339 5 : }
25340 :
25341 :
25342 23723 : TEST(StreamingScriptWithInvalidUtf8) {
25343 : // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
25344 : // chunk don't produce a crash.
25345 : const char* reference = "\xec\x92\x81\x80\x80";
25346 : char chunk1[] =
25347 : "function foo() {\n"
25348 : " // This function will contain an UTF-8 character which is not in\n"
25349 : " // ASCII.\n"
25350 5 : " var foobXXXXX"; // Too many bytes which look like incomplete chars!
25351 : char chunk2[] =
25352 : "r = 13;\n"
25353 : " return foob\xec\x92\x81\x80\x80r;\n"
25354 5 : "}\n";
25355 5 : for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
25356 :
25357 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25358 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
25359 5 : }
25360 :
25361 :
25362 23723 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
25363 : // Regression test: Stream data where there are several multi-byte UTF-8
25364 : // characters in a sequence and one of them is split between two data chunks.
25365 : const char* reference = "\xec\x92\x81";
25366 : char chunk1[] =
25367 : "function foo() {\n"
25368 : " // This function will contain an UTF-8 character which is not in\n"
25369 : " // ASCII.\n"
25370 5 : " var foob\xec\x92\x81X";
25371 : char chunk2[] =
25372 : "XXr = 13;\n"
25373 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25374 5 : "}\n";
25375 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25376 5 : chunk2[0] = reference[1];
25377 5 : chunk2[1] = reference[2];
25378 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25379 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25380 5 : }
25381 :
25382 :
25383 23723 : TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
25384 : // Another regression test, similar to the previous one. The difference is
25385 : // that the split character is not the last one in the sequence.
25386 : const char* reference = "\xec\x92\x81";
25387 : char chunk1[] =
25388 : "function foo() {\n"
25389 : " // This function will contain an UTF-8 character which is not in\n"
25390 : " // ASCII.\n"
25391 5 : " var foobX";
25392 : char chunk2[] =
25393 : "XX\xec\x92\x81r = 13;\n"
25394 : " return foob\xec\x92\x81\xec\x92\x81r;\n"
25395 5 : "}\n";
25396 5 : chunk1[strlen(chunk1) - 1] = reference[0];
25397 5 : chunk2[0] = reference[1];
25398 5 : chunk2[1] = reference[2];
25399 5 : const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25400 5 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25401 5 : }
25402 :
25403 :
25404 23723 : TEST(StreamingWithHarmonyScopes) {
25405 : // Don't use RunStreamingTest here so that both scripts get to use the same
25406 : // LocalContext and HandleScope.
25407 5 : LocalContext env;
25408 5 : v8::Isolate* isolate = env->GetIsolate();
25409 10 : v8::HandleScope scope(isolate);
25410 :
25411 : // First, run a script with a let variable.
25412 : CompileRun("\"use strict\"; let x = 1;");
25413 :
25414 : // Then stream a script which (erroneously) tries to introduce the same
25415 : // variable again.
25416 5 : const char* chunks[] = {"\"use strict\"; let x = 2;", nullptr};
25417 :
25418 10 : v8::TryCatch try_catch(isolate);
25419 : v8::ScriptCompiler::StreamedSource source(
25420 : new TestSourceStream(chunks),
25421 15 : v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25422 : v8::ScriptCompiler::ScriptStreamingTask* task =
25423 5 : v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25424 5 : task->Run();
25425 5 : delete task;
25426 :
25427 : // Parsing should succeed (the script will be parsed and compiled in a context
25428 : // independent way, so the error is not detected).
25429 5 : CHECK(!try_catch.HasCaught());
25430 :
25431 5 : v8::ScriptOrigin origin(v8_str("http://foo.com"));
25432 5 : char* full_source = TestSourceStream::FullSourceString(chunks);
25433 : v8::Local<Script> script =
25434 : v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25435 5 : origin)
25436 5 : .ToLocalChecked();
25437 5 : CHECK(!script.IsEmpty());
25438 5 : CHECK(!try_catch.HasCaught());
25439 :
25440 : // Running the script exposes the error.
25441 10 : CHECK(script->Run(env.local()).IsEmpty());
25442 5 : CHECK(try_catch.HasCaught());
25443 10 : delete[] full_source;
25444 5 : }
25445 :
25446 :
25447 23723 : TEST(CodeCache) {
25448 : v8::Isolate::CreateParams create_params;
25449 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25450 :
25451 : const char* source = "Math.sqrt(4)";
25452 : const char* origin = "code cache test";
25453 : v8::ScriptCompiler::CachedData* cache;
25454 :
25455 5 : v8::Isolate* isolate1 = v8::Isolate::New(create_params);
25456 : {
25457 : v8::Isolate::Scope iscope(isolate1);
25458 10 : v8::HandleScope scope(isolate1);
25459 5 : v8::Local<v8::Context> context = v8::Context::New(isolate1);
25460 : v8::Context::Scope cscope(context);
25461 5 : v8::Local<v8::String> source_string = v8_str(source);
25462 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25463 : v8::ScriptCompiler::Source source(source_string, script_origin);
25464 : v8::ScriptCompiler::CompileOptions option =
25465 : v8::ScriptCompiler::kProduceCodeCache;
25466 5 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25467 5 : int length = source.GetCachedData()->length;
25468 5 : uint8_t* cache_data = new uint8_t[length];
25469 5 : memcpy(cache_data, source.GetCachedData()->data, length);
25470 : cache = new v8::ScriptCompiler::CachedData(
25471 5 : cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
25472 : }
25473 5 : isolate1->Dispose();
25474 :
25475 5 : v8::Isolate* isolate2 = v8::Isolate::New(create_params);
25476 : {
25477 : v8::Isolate::Scope iscope(isolate2);
25478 10 : v8::HandleScope scope(isolate2);
25479 5 : v8::Local<v8::Context> context = v8::Context::New(isolate2);
25480 : v8::Context::Scope cscope(context);
25481 5 : v8::Local<v8::String> source_string = v8_str(source);
25482 5 : v8::ScriptOrigin script_origin(v8_str(origin));
25483 : v8::ScriptCompiler::Source source(source_string, script_origin, cache);
25484 : v8::ScriptCompiler::CompileOptions option =
25485 : v8::ScriptCompiler::kConsumeCodeCache;
25486 : v8::Local<v8::Script> script;
25487 : {
25488 : i::DisallowCompilation no_compile(
25489 : reinterpret_cast<i::Isolate*>(isolate2));
25490 : script = v8::ScriptCompiler::Compile(context, &source, option)
25491 5 : .ToLocalChecked();
25492 : }
25493 20 : CHECK_EQ(2, script->Run(context)
25494 : .ToLocalChecked()
25495 : ->ToInt32(context)
25496 : .ToLocalChecked()
25497 : ->Int32Value(context)
25498 : .FromJust());
25499 : }
25500 5 : isolate2->Dispose();
25501 5 : }
25502 :
25503 :
25504 10 : void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
25505 : const char* garbage = "garbage garbage garbage garbage garbage garbage";
25506 : const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25507 : int length = 16;
25508 : v8::ScriptCompiler::CachedData* cached_data =
25509 10 : new v8::ScriptCompiler::CachedData(data, length);
25510 10 : CHECK(!cached_data->rejected);
25511 10 : v8::ScriptOrigin origin(v8_str("origin"));
25512 10 : v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
25513 10 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25514 : v8::Local<v8::Script> script =
25515 10 : v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25516 10 : CHECK(cached_data->rejected);
25517 30 : CHECK_EQ(
25518 : 42,
25519 : script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
25520 10 : }
25521 :
25522 23723 : TEST(InvalidParserCacheData) {
25523 5 : v8::V8::Initialize();
25524 5 : v8::HandleScope scope(CcTest::isolate());
25525 10 : LocalContext context;
25526 5 : if (i::FLAG_lazy) {
25527 : // Cached parser data is not consumed while parsing eagerly.
25528 5 : TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
25529 5 : }
25530 5 : }
25531 :
25532 23723 : TEST(InvalidCodeCacheData) {
25533 5 : v8::V8::Initialize();
25534 5 : v8::HandleScope scope(CcTest::isolate());
25535 10 : LocalContext context;
25536 10 : TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
25537 5 : }
25538 :
25539 :
25540 23723 : TEST(ParserCacheRejectedGracefully) {
25541 : // Producing cached parser data while parsing eagerly is not supported.
25542 5 : if (!i::FLAG_lazy) return;
25543 :
25544 5 : v8::V8::Initialize();
25545 5 : v8::HandleScope scope(CcTest::isolate());
25546 10 : LocalContext context;
25547 : // Produce valid cached data.
25548 5 : v8::ScriptOrigin origin(v8_str("origin"));
25549 5 : v8::Local<v8::String> source_str = v8_str("function foo() {}");
25550 : v8::ScriptCompiler::Source source(source_str, origin);
25551 : v8::Local<v8::Script> script =
25552 : v8::ScriptCompiler::Compile(context.local(), &source,
25553 5 : v8::ScriptCompiler::kProduceParserCache)
25554 5 : .ToLocalChecked();
25555 : USE(script);
25556 : const v8::ScriptCompiler::CachedData* original_cached_data =
25557 5 : source.GetCachedData();
25558 5 : CHECK_NOT_NULL(original_cached_data);
25559 5 : CHECK_NOT_NULL(original_cached_data->data);
25560 5 : CHECK(!original_cached_data->rejected);
25561 5 : CHECK_GT(original_cached_data->length, 0);
25562 : // Recompiling the same script with it won't reject the data.
25563 : {
25564 : v8::ScriptCompiler::Source source_with_cached_data(
25565 : source_str, origin,
25566 : new v8::ScriptCompiler::CachedData(original_cached_data->data,
25567 5 : original_cached_data->length));
25568 : v8::Local<v8::Script> script =
25569 : v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
25570 5 : v8::ScriptCompiler::kConsumeParserCache)
25571 5 : .ToLocalChecked();
25572 : USE(script);
25573 : const v8::ScriptCompiler::CachedData* new_cached_data =
25574 5 : source_with_cached_data.GetCachedData();
25575 5 : CHECK_NOT_NULL(new_cached_data);
25576 5 : CHECK(!new_cached_data->rejected);
25577 : }
25578 : // Compile an incompatible script with the cached data. The new script doesn't
25579 : // have the same starting position for the function as the old one, so the old
25580 : // cached data will be incompatible with it and will be rejected.
25581 : {
25582 : v8::Local<v8::String> incompatible_source_str =
25583 5 : v8_str(" function foo() {}");
25584 : v8::ScriptCompiler::Source source_with_cached_data(
25585 : incompatible_source_str, origin,
25586 : new v8::ScriptCompiler::CachedData(original_cached_data->data,
25587 5 : original_cached_data->length));
25588 : v8::Local<v8::Script> script =
25589 : v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
25590 5 : v8::ScriptCompiler::kConsumeParserCache)
25591 5 : .ToLocalChecked();
25592 : USE(script);
25593 : const v8::ScriptCompiler::CachedData* new_cached_data =
25594 5 : source_with_cached_data.GetCachedData();
25595 5 : CHECK_NOT_NULL(new_cached_data);
25596 5 : CHECK(new_cached_data->rejected);
25597 5 : }
25598 : }
25599 :
25600 :
25601 23723 : TEST(StringConcatOverflow) {
25602 5 : v8::V8::Initialize();
25603 5 : v8::HandleScope scope(CcTest::isolate());
25604 : RandomLengthOneByteResource* r =
25605 5 : new RandomLengthOneByteResource(i::String::kMaxLength);
25606 : v8::Local<v8::String> str =
25607 5 : v8::String::NewExternalOneByte(CcTest::isolate(), r).ToLocalChecked();
25608 5 : CHECK(!str.IsEmpty());
25609 10 : v8::TryCatch try_catch(CcTest::isolate());
25610 5 : v8::Local<v8::String> result = v8::String::Concat(str, str);
25611 5 : CHECK(result.IsEmpty());
25612 10 : CHECK(!try_catch.HasCaught());
25613 5 : }
25614 :
25615 23723 : TEST(TurboAsmDisablesNeuter) {
25616 5 : i::FLAG_opt = true;
25617 5 : i::FLAG_allow_natives_syntax = true;
25618 5 : v8::V8::Initialize();
25619 5 : v8::HandleScope scope(CcTest::isolate());
25620 10 : LocalContext context;
25621 : const char* load =
25622 : "function Module(stdlib, foreign, heap) {"
25623 : " 'use asm';"
25624 : " var MEM32 = new stdlib.Int32Array(heap);"
25625 : " function load() { return MEM32[0] | 0; }"
25626 : " return { load: load };"
25627 : "}"
25628 : "var buffer = new ArrayBuffer(1024);"
25629 : "var module = Module(this, {}, buffer);"
25630 : "%OptimizeFunctionOnNextCall(module.load);"
25631 : "module.load();"
25632 : "buffer";
25633 :
25634 : v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
25635 5 : CHECK(!result->IsNeuterable());
25636 :
25637 : const char* store =
25638 : "function Module(stdlib, foreign, heap) {"
25639 : " 'use asm';"
25640 : " var MEM32 = new stdlib.Int32Array(heap);"
25641 : " function store() { MEM32[0] = 0; }"
25642 : " return { store: store };"
25643 : "}"
25644 : "var buffer = new ArrayBuffer(1024);"
25645 : "var module = Module(this, {}, buffer);"
25646 : "%OptimizeFunctionOnNextCall(module.store);"
25647 : "module.store();"
25648 : "buffer";
25649 :
25650 : result = CompileRun(store).As<v8::ArrayBuffer>();
25651 10 : CHECK(!result->IsNeuterable());
25652 5 : }
25653 :
25654 23723 : TEST(GetPrototypeAccessControl) {
25655 5 : i::FLAG_allow_natives_syntax = true;
25656 5 : v8::Isolate* isolate = CcTest::isolate();
25657 5 : v8::HandleScope handle_scope(isolate);
25658 10 : LocalContext env;
25659 :
25660 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
25661 5 : obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
25662 :
25663 30 : CHECK(env->Global()
25664 : ->Set(env.local(), v8_str("prohibited"),
25665 : obj_template->NewInstance(env.local()).ToLocalChecked())
25666 : .FromJust());
25667 :
25668 5 : CHECK(CompileRun(
25669 : "function f() { return %_GetPrototype(prohibited); }"
25670 : "%OptimizeFunctionOnNextCall(f);"
25671 5 : "f();")->IsNull());
25672 5 : }
25673 :
25674 :
25675 23723 : TEST(GetPrototypeHidden) {
25676 5 : i::FLAG_allow_natives_syntax = true;
25677 5 : v8::Isolate* isolate = CcTest::isolate();
25678 5 : v8::HandleScope handle_scope(isolate);
25679 10 : LocalContext env;
25680 :
25681 5 : Local<FunctionTemplate> t = FunctionTemplate::New(isolate);
25682 5 : t->SetHiddenPrototype(true);
25683 5 : Local<Object> proto = t->GetFunction(env.local())
25684 5 : .ToLocalChecked()
25685 5 : ->NewInstance(env.local())
25686 : .ToLocalChecked();
25687 5 : Local<Object> object = Object::New(isolate);
25688 5 : Local<Object> proto2 = Object::New(isolate);
25689 15 : object->SetPrototype(env.local(), proto).FromJust();
25690 10 : proto->SetPrototype(env.local(), proto2).FromJust();
25691 :
25692 25 : CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
25693 25 : CHECK(env->Global()->Set(env.local(), v8_str("proto"), proto).FromJust());
25694 25 : CHECK(env->Global()->Set(env.local(), v8_str("proto2"), proto2).FromJust());
25695 :
25696 : v8::Local<v8::Value> result = CompileRun("%_GetPrototype(object)");
25697 10 : CHECK(result->Equals(env.local(), proto2).FromJust());
25698 :
25699 : result = CompileRun(
25700 : "function f() { return %_GetPrototype(object); }"
25701 : "%OptimizeFunctionOnNextCall(f);"
25702 : "f()");
25703 15 : CHECK(result->Equals(env.local(), proto2).FromJust());
25704 5 : }
25705 :
25706 :
25707 23723 : TEST(ClassPrototypeCreationContext) {
25708 5 : v8::Isolate* isolate = CcTest::isolate();
25709 5 : v8::HandleScope handle_scope(isolate);
25710 10 : LocalContext env;
25711 :
25712 : Local<Object> result = Local<Object>::Cast(
25713 : CompileRun("'use strict'; class Example { }; Example.prototype"));
25714 15 : CHECK(env.local() == result->CreationContext());
25715 5 : }
25716 :
25717 :
25718 23723 : TEST(SimpleStreamingScriptWithSourceURL) {
25719 : const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
25720 5 : "//# sourceURL=bar2.js\n", nullptr};
25721 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25722 5 : "bar2.js");
25723 5 : }
25724 :
25725 :
25726 23723 : TEST(StreamingScriptWithSplitSourceURL) {
25727 : const char* chunks[] = {"function foo() { ret", "urn 13; } f",
25728 5 : "oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
25729 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25730 5 : "bar2.js");
25731 5 : }
25732 :
25733 :
25734 23723 : TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
25735 : const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
25736 5 : " sourceMappingURL=bar2.js\n", "foo();", nullptr};
25737 : RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25738 5 : nullptr, "bar2.js");
25739 5 : }
25740 :
25741 :
25742 23723 : TEST(NewStringRangeError) {
25743 : // This test uses a lot of memory and fails with flaky OOM when run
25744 : // with --stress-incremental-marking on TSAN.
25745 5 : i::FLAG_stress_incremental_marking = false;
25746 5 : v8::Isolate* isolate = CcTest::isolate();
25747 5 : v8::HandleScope handle_scope(isolate);
25748 : const int length = i::String::kMaxLength + 1;
25749 : const int buffer_size = length * sizeof(uint16_t);
25750 5 : void* buffer = malloc(buffer_size);
25751 5 : if (buffer == nullptr) return;
25752 : memset(buffer, 'A', buffer_size);
25753 : {
25754 5 : v8::TryCatch try_catch(isolate);
25755 : char* data = reinterpret_cast<char*>(buffer);
25756 10 : CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
25757 : length)
25758 : .IsEmpty());
25759 5 : CHECK(!try_catch.HasCaught());
25760 : }
25761 : {
25762 5 : v8::TryCatch try_catch(isolate);
25763 : uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
25764 10 : CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
25765 : length)
25766 : .IsEmpty());
25767 5 : CHECK(!try_catch.HasCaught());
25768 : }
25769 : {
25770 5 : v8::TryCatch try_catch(isolate);
25771 : uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
25772 10 : CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
25773 : length)
25774 : .IsEmpty());
25775 5 : CHECK(!try_catch.HasCaught());
25776 : }
25777 5 : free(buffer);
25778 : }
25779 :
25780 :
25781 23718 : TEST(SealHandleScope) {
25782 0 : v8::Isolate* isolate = CcTest::isolate();
25783 0 : v8::HandleScope handle_scope(isolate);
25784 0 : LocalContext env;
25785 :
25786 0 : v8::SealHandleScope seal(isolate);
25787 :
25788 : // Should fail
25789 0 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25790 :
25791 0 : USE(obj);
25792 0 : }
25793 :
25794 :
25795 23723 : TEST(SealHandleScopeNested) {
25796 5 : v8::Isolate* isolate = CcTest::isolate();
25797 5 : v8::HandleScope handle_scope(isolate);
25798 10 : LocalContext env;
25799 :
25800 10 : v8::SealHandleScope seal(isolate);
25801 :
25802 : {
25803 5 : v8::HandleScope handle_scope(isolate);
25804 :
25805 : // Should work
25806 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
25807 :
25808 5 : USE(obj);
25809 5 : }
25810 5 : }
25811 :
25812 :
25813 10 : static void ExtrasBindingTestRuntimeFunction(
25814 20 : const v8::FunctionCallbackInfo<v8::Value>& args) {
25815 30 : CHECK_EQ(
25816 : 3,
25817 : args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
25818 10 : args.GetReturnValue().Set(v8_num(7));
25819 10 : }
25820 :
25821 23723 : TEST(ExtrasFunctionSource) {
25822 5 : v8::Isolate* isolate = CcTest::isolate();
25823 5 : v8::HandleScope handle_scope(isolate);
25824 10 : LocalContext env;
25825 :
25826 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25827 :
25828 : // Functions defined in extras do not expose source code.
25829 15 : auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
25830 5 : .ToLocalChecked()
25831 : .As<v8::Function>();
25832 : auto undefined = v8::Undefined(isolate);
25833 10 : auto result = func->Call(env.local(), undefined, 0, {})
25834 5 : .ToLocalChecked()
25835 : .As<v8::String>();
25836 10 : CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
25837 :
25838 : // Functions defined in extras do not show up in the stack trace.
25839 15 : auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
25840 5 : .ToLocalChecked()
25841 : .As<v8::Function>();
25842 25 : CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
25843 : ExpectString(
25844 : "function f(x) { return wrapper(x) }"
25845 : "function g() { return new Error().stack; }"
25846 : "f(g)",
25847 : "Error\n"
25848 : " at g (<anonymous>:1:58)\n"
25849 : " at f (<anonymous>:1:24)\n"
25850 10 : " at <anonymous>:1:78");
25851 5 : }
25852 :
25853 23723 : TEST(ExtrasBindingObject) {
25854 5 : v8::Isolate* isolate = CcTest::isolate();
25855 5 : v8::HandleScope handle_scope(isolate);
25856 10 : LocalContext env;
25857 :
25858 : // standalone.gypi ensures we include the test-extra.js file, which should
25859 : // export the tested functions.
25860 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25861 :
25862 15 : auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
25863 5 : .ToLocalChecked()
25864 : .As<v8::Function>();
25865 : auto undefined = v8::Undefined(isolate);
25866 10 : auto result = func->Call(env.local(), undefined, 0, {})
25867 5 : .ToLocalChecked()
25868 : .As<v8::Number>();
25869 10 : CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
25870 :
25871 : v8::Local<v8::FunctionTemplate> runtimeFunction =
25872 5 : v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
25873 : binding->Set(env.local(), v8_str("runtime"),
25874 25 : runtimeFunction->GetFunction(env.local()).ToLocalChecked())
25875 10 : .FromJust();
25876 15 : func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
25877 5 : .ToLocalChecked()
25878 : .As<v8::Function>();
25879 10 : result = func->Call(env.local(), undefined, 0, {})
25880 5 : .ToLocalChecked()
25881 : .As<v8::Number>();
25882 15 : CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
25883 5 : }
25884 :
25885 :
25886 23723 : TEST(ExperimentalExtras) {
25887 5 : i::FLAG_experimental_extras = true;
25888 :
25889 5 : v8::Isolate* isolate = CcTest::isolate();
25890 5 : v8::HandleScope handle_scope(isolate);
25891 10 : LocalContext env;
25892 :
25893 : // standalone.gypi ensures we include the test-experimental-extra.js file,
25894 : // which should export the tested functions.
25895 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25896 :
25897 : auto func =
25898 15 : binding->Get(env.local(), v8_str("testExperimentalExtraShouldReturnTen"))
25899 5 : .ToLocalChecked()
25900 : .As<v8::Function>();
25901 : auto undefined = v8::Undefined(isolate);
25902 10 : auto result = func->Call(env.local(), undefined, 0, {})
25903 5 : .ToLocalChecked()
25904 : .As<v8::Number>();
25905 10 : CHECK_EQ(10, result->Int32Value(env.local()).FromJust());
25906 :
25907 : v8::Local<v8::FunctionTemplate> runtimeFunction =
25908 5 : v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
25909 : binding->Set(env.local(), v8_str("runtime"),
25910 25 : runtimeFunction->GetFunction(env.local()).ToLocalChecked())
25911 10 : .FromJust();
25912 : func = binding->Get(env.local(),
25913 15 : v8_str("testExperimentalExtraShouldCallToRuntime"))
25914 5 : .ToLocalChecked()
25915 : .As<v8::Function>();
25916 10 : result = func->Call(env.local(), undefined, 0, {})
25917 5 : .ToLocalChecked()
25918 : .As<v8::Number>();
25919 15 : CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
25920 5 : }
25921 :
25922 :
25923 23723 : TEST(ExtrasUtilsObject) {
25924 5 : LocalContext context;
25925 5 : v8::Isolate* isolate = context->GetIsolate();
25926 10 : v8::HandleScope handle_scope(isolate);
25927 :
25928 10 : LocalContext env;
25929 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25930 :
25931 15 : auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
25932 5 : .ToLocalChecked()
25933 : .As<v8::Function>();
25934 : auto undefined = v8::Undefined(isolate);
25935 10 : auto result = func->Call(env.local(), undefined, 0, {})
25936 5 : .ToLocalChecked()
25937 : .As<v8::Object>();
25938 :
25939 15 : auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
25940 5 : .ToLocalChecked()
25941 : .As<v8::Symbol>();
25942 : i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
25943 5 : CHECK(ips->IsPrivate());
25944 :
25945 : CompileRun("var result = 0; function store(x) { result = x; }");
25946 5 : auto store = CompileRun("store").As<v8::Function>();
25947 :
25948 15 : auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
25949 5 : .ToLocalChecked()
25950 : .As<v8::Promise>();
25951 5 : fulfilled_promise->Then(env.local(), store).ToLocalChecked();
25952 5 : isolate->RunMicrotasks();
25953 15 : CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
25954 :
25955 : auto fulfilled_promise_2 =
25956 15 : result->Get(env.local(), v8_str("fulfilledPromise2"))
25957 5 : .ToLocalChecked()
25958 : .As<v8::Promise>();
25959 5 : fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
25960 5 : isolate->RunMicrotasks();
25961 15 : CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
25962 :
25963 15 : auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
25964 5 : .ToLocalChecked()
25965 : .As<v8::Promise>();
25966 5 : rejected_promise->Catch(env.local(), store).ToLocalChecked();
25967 5 : isolate->RunMicrotasks();
25968 15 : CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
25969 :
25970 : auto rejected_but_handled_promise =
25971 15 : result->Get(env.local(), v8_str("rejectedButHandledPromise"))
25972 5 : .ToLocalChecked()
25973 : .As<v8::Promise>();
25974 5 : CHECK(rejected_but_handled_promise->HasHandler());
25975 :
25976 15 : auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
25977 5 : .ToLocalChecked()
25978 : .As<v8::String>();
25979 10 : String::Utf8Value promise_states_string(isolate, promise_states);
25980 5 : CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
25981 :
25982 15 : auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
25983 5 : .ToLocalChecked()
25984 : .As<v8::Boolean>();
25985 5 : CHECK_EQ(true, promise_is_promise->Value());
25986 :
25987 : auto thenable_is_promise =
25988 15 : result->Get(env.local(), v8_str("thenableIsPromise"))
25989 5 : .ToLocalChecked()
25990 : .As<v8::Boolean>();
25991 15 : CHECK_EQ(false, thenable_is_promise->Value());
25992 5 : }
25993 :
25994 :
25995 23723 : TEST(Map) {
25996 5 : v8::Isolate* isolate = CcTest::isolate();
25997 5 : v8::HandleScope handle_scope(isolate);
25998 10 : LocalContext env;
25999 :
26000 5 : v8::Local<v8::Map> map = v8::Map::New(isolate);
26001 5 : CHECK(map->IsObject());
26002 5 : CHECK(map->IsMap());
26003 10 : CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
26004 5 : CHECK_EQ(0U, map->Size());
26005 :
26006 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
26007 5 : CHECK(val->IsMap());
26008 : map = v8::Local<v8::Map>::Cast(val);
26009 5 : CHECK_EQ(2U, map->Size());
26010 :
26011 5 : v8::Local<v8::Array> contents = map->AsArray();
26012 5 : CHECK_EQ(4U, contents->Length());
26013 10 : CHECK_EQ(
26014 : 1,
26015 : contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26016 10 : CHECK_EQ(
26017 : 2,
26018 : contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26019 10 : CHECK_EQ(
26020 : 3,
26021 : contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
26022 10 : CHECK_EQ(
26023 : 4,
26024 : contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
26025 :
26026 5 : CHECK_EQ(2U, map->Size());
26027 :
26028 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26029 15 : CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26030 :
26031 15 : CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26032 10 : CHECK(!map->Has(env.local(), map).FromJust());
26033 :
26034 20 : CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
26035 : .ToLocalChecked()
26036 : ->Int32Value(env.local())
26037 : .FromJust());
26038 20 : CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
26039 : .ToLocalChecked()
26040 : ->Int32Value(env.local())
26041 : .FromJust());
26042 :
26043 15 : CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
26044 : .ToLocalChecked()
26045 : ->IsUndefined());
26046 :
26047 10 : CHECK(!map->Set(env.local(), map, map).IsEmpty());
26048 5 : CHECK_EQ(3U, map->Size());
26049 10 : CHECK(map->Has(env.local(), map).FromJust());
26050 :
26051 10 : CHECK(map->Delete(env.local(), map).FromJust());
26052 5 : CHECK_EQ(2U, map->Size());
26053 10 : CHECK(!map->Has(env.local(), map).FromJust());
26054 10 : CHECK(!map->Delete(env.local(), map).FromJust());
26055 :
26056 5 : map->Clear();
26057 10 : CHECK_EQ(0U, map->Size());
26058 5 : }
26059 :
26060 :
26061 23723 : TEST(Set) {
26062 5 : v8::Isolate* isolate = CcTest::isolate();
26063 5 : v8::HandleScope handle_scope(isolate);
26064 10 : LocalContext env;
26065 :
26066 5 : v8::Local<v8::Set> set = v8::Set::New(isolate);
26067 5 : CHECK(set->IsObject());
26068 5 : CHECK(set->IsSet());
26069 10 : CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
26070 5 : CHECK_EQ(0U, set->Size());
26071 :
26072 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
26073 5 : CHECK(val->IsSet());
26074 : set = v8::Local<v8::Set>::Cast(val);
26075 5 : CHECK_EQ(2U, set->Size());
26076 :
26077 5 : v8::Local<v8::Array> keys = set->AsArray();
26078 5 : CHECK_EQ(2U, keys->Length());
26079 10 : CHECK_EQ(1,
26080 : keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26081 10 : CHECK_EQ(2,
26082 : keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26083 :
26084 5 : CHECK_EQ(2U, set->Size());
26085 :
26086 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26087 15 : CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26088 :
26089 15 : CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26090 10 : CHECK(!set->Has(env.local(), set).FromJust());
26091 :
26092 10 : CHECK(!set->Add(env.local(), set).IsEmpty());
26093 5 : CHECK_EQ(3U, set->Size());
26094 10 : CHECK(set->Has(env.local(), set).FromJust());
26095 :
26096 10 : CHECK(set->Delete(env.local(), set).FromJust());
26097 5 : CHECK_EQ(2U, set->Size());
26098 10 : CHECK(!set->Has(env.local(), set).FromJust());
26099 10 : CHECK(!set->Delete(env.local(), set).FromJust());
26100 :
26101 5 : set->Clear();
26102 10 : CHECK_EQ(0U, set->Size());
26103 5 : }
26104 :
26105 23723 : TEST(SetDeleteThenAsArray) {
26106 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26107 5 : v8::Isolate* isolate = CcTest::isolate();
26108 5 : v8::HandleScope handle_scope(isolate);
26109 10 : LocalContext env;
26110 :
26111 : // make a Set
26112 : v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
26113 : v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
26114 5 : CHECK_EQ(3U, set->Size());
26115 :
26116 : // delete the "middle" element (using AsArray to
26117 : // determine which element is the "middle" element)
26118 5 : v8::Local<v8::Array> array1 = set->AsArray();
26119 5 : CHECK_EQ(3U, array1->Length());
26120 15 : CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
26121 : .FromJust());
26122 :
26123 : // make sure there are no undefined values when we convert to an array again.
26124 5 : v8::Local<v8::Array> array2 = set->AsArray();
26125 5 : uint32_t length = array2->Length();
26126 5 : CHECK_EQ(2U, length);
26127 10 : for (uint32_t i = 0; i < length; i++) {
26128 20 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26129 5 : }
26130 5 : }
26131 :
26132 23723 : TEST(MapDeleteThenAsArray) {
26133 : // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26134 5 : v8::Isolate* isolate = CcTest::isolate();
26135 5 : v8::HandleScope handle_scope(isolate);
26136 10 : LocalContext env;
26137 :
26138 : // make a Map
26139 : v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
26140 : v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
26141 5 : CHECK_EQ(3U, map->Size());
26142 :
26143 : // delete the "middle" element (using AsArray to
26144 : // determine which element is the "middle" element)
26145 5 : v8::Local<v8::Array> array1 = map->AsArray();
26146 5 : CHECK_EQ(6U, array1->Length());
26147 : // Map::AsArray returns a flat array, so the second key is at index 2.
26148 10 : v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
26149 10 : CHECK(map->Delete(env.local(), key).FromJust());
26150 :
26151 : // make sure there are no undefined values when we convert to an array again.
26152 5 : v8::Local<v8::Array> array2 = map->AsArray();
26153 5 : uint32_t length = array2->Length();
26154 5 : CHECK_EQ(4U, length);
26155 20 : for (uint32_t i = 0; i < length; i++) {
26156 40 : CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26157 5 : }
26158 5 : }
26159 :
26160 23723 : TEST(CompatibleReceiverCheckOnCachedICHandler) {
26161 5 : v8::Isolate* isolate = CcTest::isolate();
26162 5 : v8::HandleScope scope(isolate);
26163 5 : v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
26164 5 : v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
26165 : auto returns_42 =
26166 5 : v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
26167 15 : parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
26168 5 : v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
26169 5 : child->Inherit(parent);
26170 10 : LocalContext env;
26171 30 : CHECK(env->Global()
26172 : ->Set(env.local(), v8_str("Child"),
26173 : child->GetFunction(env.local()).ToLocalChecked())
26174 : .FromJust());
26175 :
26176 : // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
26177 : CompileRun(
26178 : "var real = new Child();\n"
26179 : "for (var i = 0; i < 3; ++i) {\n"
26180 : " real.age;\n"
26181 : "}\n");
26182 :
26183 : // Check that the cached stub is never used.
26184 : ExpectInt32(
26185 : "var fake = Object.create(Child.prototype);\n"
26186 : "var result = 0;\n"
26187 : "function test(d) {\n"
26188 : " if (d == 3) return;\n"
26189 : " try {\n"
26190 : " fake.age;\n"
26191 : " result = 1;\n"
26192 : " } catch (e) {\n"
26193 : " }\n"
26194 : " test(d+1);\n"
26195 : "}\n"
26196 : "test(0);\n"
26197 : "result;\n",
26198 10 : 0);
26199 5 : }
26200 :
26201 23724 : THREADED_TEST(ReceiverConversionForAccessors) {
26202 6 : LocalContext env;
26203 6 : v8::Isolate* isolate = CcTest::isolate();
26204 12 : v8::HandleScope scope(isolate);
26205 : Local<v8::FunctionTemplate> acc =
26206 6 : v8::FunctionTemplate::New(isolate, Returns42);
26207 42 : CHECK(env->Global()
26208 : ->Set(env.local(), v8_str("acc"),
26209 : acc->GetFunction(env.local()).ToLocalChecked())
26210 : .FromJust());
26211 :
26212 6 : Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
26213 12 : templ->SetAccessorProperty(v8_str("acc"), acc, acc);
26214 6 : Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
26215 :
26216 30 : CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
26217 18 : CHECK(CompileRun("(p.acc == 42)")->BooleanValue(env.local()).FromJust());
26218 18 : CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
26219 :
26220 6 : CHECK(!CompileRun("Number.prototype.__proto__ = p;"
26221 : "var a = 1;")
26222 : .IsEmpty());
26223 18 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
26224 18 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
26225 :
26226 6 : CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
26227 : "var a = true;")
26228 : .IsEmpty());
26229 18 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
26230 18 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
26231 :
26232 6 : CHECK(!CompileRun("String.prototype.__proto__ = p;"
26233 : "var a = 'foo';")
26234 : .IsEmpty());
26235 18 : CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
26236 18 : CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
26237 :
26238 18 : CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(env.local()).FromJust());
26239 18 : CHECK(CompileRun("acc.call(true)==42")->BooleanValue(env.local()).FromJust());
26240 18 : CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(env.local()).FromJust());
26241 18 : CHECK(
26242 : CompileRun("acc.call(null) == 42")->BooleanValue(env.local()).FromJust());
26243 18 : CHECK(CompileRun("acc.call(undefined) == 42")
26244 : ->BooleanValue(env.local())
26245 6 : .FromJust());
26246 6 : }
26247 :
26248 5 : class FutexInterruptionThread : public v8::base::Thread {
26249 : public:
26250 : explicit FutexInterruptionThread(v8::Isolate* isolate)
26251 5 : : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
26252 :
26253 5 : virtual void Run() {
26254 : // Wait a bit before terminating.
26255 5 : v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
26256 5 : isolate_->TerminateExecution();
26257 5 : }
26258 :
26259 : private:
26260 : v8::Isolate* isolate_;
26261 : };
26262 :
26263 :
26264 23723 : TEST(FutexInterruption) {
26265 5 : i::FLAG_harmony_sharedarraybuffer = true;
26266 5 : v8::Isolate* isolate = CcTest::isolate();
26267 5 : v8::HandleScope scope(isolate);
26268 10 : LocalContext env;
26269 :
26270 : FutexInterruptionThread timeout_thread(isolate);
26271 :
26272 10 : v8::TryCatch try_catch(CcTest::isolate());
26273 5 : timeout_thread.Start();
26274 :
26275 : CompileRun(
26276 : "var ab = new SharedArrayBuffer(4);"
26277 : "var i32a = new Int32Array(ab);"
26278 : "Atomics.wait(i32a, 0, 0);");
26279 5 : CHECK(try_catch.HasTerminated());
26280 10 : timeout_thread.Join();
26281 5 : }
26282 :
26283 23724 : THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
26284 6 : i::FLAG_harmony_sharedarraybuffer = true;
26285 6 : LocalContext env;
26286 6 : v8::Isolate* isolate = env->GetIsolate();
26287 12 : v8::HandleScope handle_scope(isolate);
26288 :
26289 : const size_t ab_size = 1024;
26290 : Local<v8::SharedArrayBuffer> ab =
26291 6 : v8::SharedArrayBuffer::New(isolate, ab_size);
26292 12 : ScopedSharedArrayBufferContents contents(ab->Externalize());
26293 :
26294 : // Array buffers should have normal allocation mode.
26295 6 : CHECK_EQ(contents.AllocationMode(),
26296 : v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
26297 : // The allocation must contain the buffer (normally they will be equal, but
26298 : // this is not required by the contract).
26299 6 : CHECK_NOT_NULL(contents.AllocationBase());
26300 : const uintptr_t alloc =
26301 6 : reinterpret_cast<uintptr_t>(contents.AllocationBase());
26302 6 : const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
26303 6 : CHECK_LE(alloc, data);
26304 12 : CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
26305 6 : }
26306 :
26307 : static int nb_uncaught_exception_callback_calls = 0;
26308 :
26309 :
26310 5 : bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
26311 5 : ++nb_uncaught_exception_callback_calls;
26312 5 : return false;
26313 : }
26314 :
26315 :
26316 23723 : TEST(AbortOnUncaughtExceptionNoAbort) {
26317 5 : v8::Isolate* isolate = CcTest::isolate();
26318 5 : v8::HandleScope handle_scope(isolate);
26319 : v8::Local<v8::ObjectTemplate> global_template =
26320 5 : v8::ObjectTemplate::New(isolate);
26321 10 : LocalContext env(nullptr, global_template);
26322 :
26323 5 : i::FLAG_abort_on_uncaught_exception = true;
26324 5 : isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
26325 :
26326 : CompileRun("function boom() { throw new Error(\"boom\") }");
26327 :
26328 5 : v8::Local<v8::Object> global_object = env->Global();
26329 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
26330 20 : global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
26331 :
26332 10 : CHECK(foo->Call(env.local(), global_object, 0, nullptr).IsEmpty());
26333 :
26334 10 : CHECK_EQ(1, nb_uncaught_exception_callback_calls);
26335 5 : }
26336 :
26337 :
26338 23723 : TEST(AccessCheckedIsConcatSpreadable) {
26339 5 : v8::Isolate* isolate = CcTest::isolate();
26340 5 : HandleScope scope(isolate);
26341 10 : LocalContext env;
26342 :
26343 : // Object with access check
26344 5 : Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
26345 5 : spreadable_template->SetAccessCheckCallback(AccessBlocker);
26346 : spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
26347 10 : v8::Boolean::New(isolate, true));
26348 : Local<Object> object =
26349 5 : spreadable_template->NewInstance(env.local()).ToLocalChecked();
26350 :
26351 5 : allowed_access = true;
26352 25 : CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
26353 15 : object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
26354 15 : object->Set(env.local(), 0U, v8_str("a")).FromJust();
26355 15 : object->Set(env.local(), 1U, v8_str("b")).FromJust();
26356 :
26357 : // Access check is allowed, and the object is spread
26358 : CompileRun("var result = [].concat(object)");
26359 : ExpectTrue("Array.isArray(result)");
26360 5 : ExpectString("result[0]", "a");
26361 5 : ExpectString("result[1]", "b");
26362 : ExpectTrue("result.length === 2");
26363 : ExpectTrue("object[Symbol.isConcatSpreadable]");
26364 :
26365 : // If access check fails, the value of @@isConcatSpreadable is ignored
26366 5 : allowed_access = false;
26367 : CompileRun("var result = [].concat(object)");
26368 : ExpectTrue("Array.isArray(result)");
26369 : ExpectTrue("result[0] === object");
26370 : ExpectTrue("result.length === 1");
26371 5 : ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
26372 5 : }
26373 :
26374 :
26375 23723 : TEST(AccessCheckedToStringTag) {
26376 5 : v8::Isolate* isolate = CcTest::isolate();
26377 5 : HandleScope scope(isolate);
26378 10 : LocalContext env;
26379 :
26380 : // Object with access check
26381 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26382 5 : object_template->SetAccessCheckCallback(AccessBlocker);
26383 : Local<Object> object =
26384 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26385 :
26386 5 : allowed_access = true;
26387 25 : env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
26388 20 : object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
26389 10 : .FromJust();
26390 :
26391 : // Access check is allowed, and the toStringTag is read
26392 : CompileRun("var result = Object.prototype.toString.call(object)");
26393 5 : ExpectString("result", "[object hello]");
26394 5 : ExpectString("object[Symbol.toStringTag]", "hello");
26395 :
26396 : // ToString through the API should succeed too.
26397 : String::Utf8Value result_allowed(
26398 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26399 5 : CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
26400 :
26401 : // If access check fails, the value of @@toStringTag is ignored
26402 5 : allowed_access = false;
26403 : CompileRun("var result = Object.prototype.toString.call(object)");
26404 5 : ExpectString("result", "[object Object]");
26405 : ExpectTrue("object[Symbol.toStringTag] === undefined");
26406 :
26407 : // ToString through the API should also fail.
26408 : String::Utf8Value result_denied(
26409 15 : isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26410 10 : CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
26411 5 : }
26412 :
26413 23723 : TEST(TemplateIteratorPrototypeIntrinsics) {
26414 5 : v8::Isolate* isolate = CcTest::isolate();
26415 5 : v8::HandleScope scope(isolate);
26416 10 : LocalContext env;
26417 :
26418 : // Object templates.
26419 : {
26420 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26421 : object_template->SetIntrinsicDataProperty(v8_str("iter_proto"),
26422 10 : v8::kIteratorPrototype);
26423 : Local<Object> object =
26424 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26425 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26426 : ExpectTrue("obj.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26427 : }
26428 : // Setting %IteratorProto% on the function object's prototype template.
26429 : {
26430 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26431 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26432 15 : v8_str("iter_proto"), v8::kIteratorPrototype);
26433 : Local<Function> func1 =
26434 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26435 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26436 : Local<Function> func2 =
26437 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26438 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26439 : ExpectTrue(
26440 : "func1.prototype.iter_proto === "
26441 : "[][Symbol.iterator]().__proto__.__proto__");
26442 : ExpectTrue(
26443 : "func2.prototype.iter_proto === "
26444 : "[][Symbol.iterator]().__proto__.__proto__");
26445 : ExpectTrue("func1.prototype.iter_proto === func2.prototype.iter_proto");
26446 :
26447 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26448 25 : CHECK(env->Global()
26449 : ->Set(env.local(), v8_str("instance1"), instance1)
26450 : .FromJust());
26451 : ExpectFalse("instance1.hasOwnProperty('iter_proto')");
26452 : ExpectTrue("'iter_proto' in instance1.__proto__");
26453 : ExpectTrue(
26454 : "instance1.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26455 : }
26456 : // Put %IteratorProto% in a function object's inheritance chain.
26457 : {
26458 : Local<FunctionTemplate> parent_template =
26459 5 : v8::FunctionTemplate::New(isolate);
26460 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26461 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26462 10 : v8::kIteratorPrototype);
26463 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26464 5 : func_template->Inherit(parent_template);
26465 :
26466 : Local<Function> func =
26467 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26468 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26469 : ExpectTrue(
26470 : "func.prototype.__proto__ === "
26471 : "[][Symbol.iterator]().__proto__.__proto__");
26472 :
26473 : Local<Object> func_instance =
26474 5 : func->NewInstance(env.local()).ToLocalChecked();
26475 25 : CHECK(env->Global()
26476 : ->Set(env.local(), v8_str("instance"), func_instance)
26477 : .FromJust());
26478 : ExpectTrue(
26479 : "instance.__proto__.__proto__ === "
26480 : "[][Symbol.iterator]().__proto__.__proto__");
26481 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26482 5 : }
26483 5 : }
26484 :
26485 23723 : TEST(TemplateErrorPrototypeIntrinsics) {
26486 5 : v8::Isolate* isolate = CcTest::isolate();
26487 5 : v8::HandleScope scope(isolate);
26488 10 : LocalContext env;
26489 :
26490 : // Object templates.
26491 : {
26492 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26493 : object_template->SetIntrinsicDataProperty(v8_str("error_proto"),
26494 10 : v8::kErrorPrototype);
26495 : Local<Object> object =
26496 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26497 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26498 : ExpectTrue("obj.error_proto === Error.prototype");
26499 5 : Local<Value> error = v8::Exception::Error(v8_str("error message"));
26500 25 : CHECK(env->Global()->Set(env.local(), v8_str("err"), error).FromJust());
26501 : ExpectTrue("obj.error_proto === Object.getPrototypeOf(err)");
26502 : }
26503 : // Setting %ErrorPrototype% on the function object's prototype template.
26504 : {
26505 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26506 10 : func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26507 15 : v8_str("error_proto"), v8::kErrorPrototype);
26508 : Local<Function> func1 =
26509 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26510 25 : CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26511 : Local<Function> func2 =
26512 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26513 25 : CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26514 : ExpectTrue("func1.prototype.error_proto === Error.prototype");
26515 : ExpectTrue("func2.prototype.error_proto === Error.prototype");
26516 : ExpectTrue("func1.prototype.error_proto === func2.prototype.error_proto");
26517 :
26518 5 : Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26519 25 : CHECK(env->Global()
26520 : ->Set(env.local(), v8_str("instance1"), instance1)
26521 : .FromJust());
26522 : ExpectFalse("instance1.hasOwnProperty('error_proto')");
26523 : ExpectTrue("'error_proto' in instance1.__proto__");
26524 : ExpectTrue("instance1.error_proto === Error.prototype");
26525 : }
26526 : // Put %ErrorPrototype% in a function object's inheritance chain.
26527 : {
26528 : Local<FunctionTemplate> parent_template =
26529 5 : v8::FunctionTemplate::New(isolate);
26530 5 : parent_template->RemovePrototype(); // Remove so there is no name clash.
26531 : parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26532 10 : v8::kErrorPrototype);
26533 5 : Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26534 5 : func_template->Inherit(parent_template);
26535 :
26536 : Local<Function> func =
26537 5 : func_template->GetFunction(env.local()).ToLocalChecked();
26538 25 : CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26539 : ExpectTrue("func.prototype.__proto__ === Error.prototype");
26540 :
26541 : Local<Object> func_instance =
26542 5 : func->NewInstance(env.local()).ToLocalChecked();
26543 25 : CHECK(env->Global()
26544 : ->Set(env.local(), v8_str("instance"), func_instance)
26545 : .FromJust());
26546 : ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26547 : // Now let's check if %ErrorPrototype% properties are in the instance.
26548 : ExpectTrue("'constructor' in instance");
26549 : ExpectTrue("'message' in instance");
26550 : ExpectTrue("'name' in instance");
26551 : ExpectTrue("'toString' in instance");
26552 5 : }
26553 5 : }
26554 :
26555 23723 : TEST(ObjectTemplateArrayProtoIntrinsics) {
26556 5 : v8::Isolate* isolate = CcTest::isolate();
26557 5 : v8::HandleScope scope(isolate);
26558 10 : LocalContext env;
26559 :
26560 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26561 : object_template->SetIntrinsicDataProperty(v8_str("prop_entries"),
26562 10 : v8::kArrayProto_entries);
26563 : object_template->SetIntrinsicDataProperty(v8_str("prop_forEach"),
26564 10 : v8::kArrayProto_forEach);
26565 : object_template->SetIntrinsicDataProperty(v8_str("prop_keys"),
26566 10 : v8::kArrayProto_keys);
26567 : object_template->SetIntrinsicDataProperty(v8_str("prop_values"),
26568 10 : v8::kArrayProto_values);
26569 : Local<Object> object =
26570 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26571 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26572 :
26573 : const struct {
26574 : const char* const object_property_name;
26575 : const char* const array_property_name;
26576 : } intrinsics_comparisons[] = {
26577 : {"prop_entries", "Array.prototype.entries"},
26578 : {"prop_forEach", "Array.prototype.forEach"},
26579 : {"prop_keys", "Array.prototype.keys"},
26580 : {"prop_values", "Array.prototype[Symbol.iterator]"},
26581 5 : };
26582 :
26583 25 : for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) {
26584 : i::ScopedVector<char> test_string(64);
26585 :
26586 : i::SNPrintF(test_string, "typeof obj1.%s",
26587 20 : intrinsics_comparisons[i].object_property_name);
26588 20 : ExpectString(test_string.start(), "function");
26589 :
26590 : i::SNPrintF(test_string, "obj1.%s === %s",
26591 : intrinsics_comparisons[i].object_property_name,
26592 20 : intrinsics_comparisons[i].array_property_name);
26593 : ExpectTrue(test_string.start());
26594 :
26595 : i::SNPrintF(test_string, "obj1.%s = 42",
26596 20 : intrinsics_comparisons[i].object_property_name);
26597 : CompileRun(test_string.start());
26598 :
26599 : i::SNPrintF(test_string, "obj1.%s === %s",
26600 : intrinsics_comparisons[i].object_property_name,
26601 20 : intrinsics_comparisons[i].array_property_name);
26602 : ExpectFalse(test_string.start());
26603 :
26604 : i::SNPrintF(test_string, "typeof obj1.%s",
26605 20 : intrinsics_comparisons[i].object_property_name);
26606 20 : ExpectString(test_string.start(), "number");
26607 5 : }
26608 5 : }
26609 :
26610 23723 : TEST(ObjectTemplatePerContextIntrinsics) {
26611 5 : v8::Isolate* isolate = CcTest::isolate();
26612 5 : v8::HandleScope scope(isolate);
26613 10 : LocalContext env;
26614 :
26615 5 : Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26616 : object_template->SetIntrinsicDataProperty(v8_str("values"),
26617 10 : v8::kArrayProto_values);
26618 : Local<Object> object =
26619 5 : object_template->NewInstance(env.local()).ToLocalChecked();
26620 :
26621 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26622 5 : ExpectString("typeof obj1.values", "function");
26623 :
26624 : auto values = Local<Function>::Cast(
26625 15 : object->Get(env.local(), v8_str("values")).ToLocalChecked());
26626 : auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
26627 10 : auto ctx = v8::Utils::OpenHandle(*env.local());
26628 10 : CHECK_EQ(*fn->GetCreationContext(), *ctx);
26629 :
26630 : {
26631 5 : LocalContext env2;
26632 : Local<Object> object2 =
26633 5 : object_template->NewInstance(env2.local()).ToLocalChecked();
26634 25 : CHECK(
26635 : env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
26636 5 : ExpectString("typeof obj2.values", "function");
26637 25 : CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
26638 : *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26639 :
26640 : auto values2 = Local<Function>::Cast(
26641 15 : object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26642 : auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
26643 10 : auto ctx2 = v8::Utils::OpenHandle(*env2.local());
26644 10 : CHECK_EQ(*fn2->GetCreationContext(), *ctx2);
26645 5 : }
26646 5 : }
26647 :
26648 :
26649 23723 : TEST(Proxy) {
26650 5 : LocalContext context;
26651 5 : v8::Isolate* isolate = CcTest::isolate();
26652 10 : v8::HandleScope scope(isolate);
26653 : v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
26654 : v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
26655 :
26656 : v8::Local<v8::Proxy> proxy =
26657 5 : v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
26658 5 : CHECK(proxy->IsProxy());
26659 5 : CHECK(!target->IsProxy());
26660 5 : CHECK(!proxy->IsRevoked());
26661 10 : CHECK(proxy->GetTarget()->SameValue(target));
26662 10 : CHECK(proxy->GetHandler()->SameValue(handler));
26663 :
26664 5 : proxy->Revoke();
26665 5 : CHECK(proxy->IsProxy());
26666 5 : CHECK(!target->IsProxy());
26667 5 : CHECK(proxy->IsRevoked());
26668 10 : CHECK(proxy->GetTarget()->SameValue(target));
26669 15 : CHECK(proxy->GetHandler()->IsNull());
26670 5 : }
26671 :
26672 10 : WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
26673 : v8::Isolate* isolate, WeakCallCounter* counter) {
26674 : v8::Locker locker(isolate);
26675 20 : LocalContext env;
26676 20 : HandleScope scope(isolate);
26677 : WeakCallCounterAndPersistent<Value>* val =
26678 10 : new WeakCallCounterAndPersistent<Value>(counter);
26679 20 : val->handle.Reset(isolate, Object::New(isolate));
26680 : val->handle.SetWeak(val, &WeakPointerCallback,
26681 : v8::WeakCallbackType::kParameter);
26682 10 : return val;
26683 : }
26684 :
26685 5 : class MemoryPressureThread : public v8::base::Thread {
26686 : public:
26687 : explicit MemoryPressureThread(v8::Isolate* isolate,
26688 : v8::MemoryPressureLevel level)
26689 : : Thread(Options("MemoryPressureThread")),
26690 : isolate_(isolate),
26691 5 : level_(level) {}
26692 :
26693 5 : virtual void Run() { isolate_->MemoryPressureNotification(level_); }
26694 :
26695 : private:
26696 : v8::Isolate* isolate_;
26697 : v8::MemoryPressureLevel level_;
26698 : };
26699 :
26700 23723 : TEST(MemoryPressure) {
26701 5 : if (v8::internal::FLAG_optimize_for_size) return;
26702 5 : v8::Isolate* isolate = CcTest::isolate();
26703 : WeakCallCounter counter(1234);
26704 :
26705 : // Check that critical memory pressure notification sets GC interrupt.
26706 5 : auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26707 5 : CHECK(!v8::Locker::IsLocked(isolate));
26708 : {
26709 : v8::Locker locker(isolate);
26710 10 : v8::HandleScope scope(isolate);
26711 10 : LocalContext env;
26712 : MemoryPressureThread memory_pressure_thread(
26713 : isolate, v8::MemoryPressureLevel::kCritical);
26714 5 : memory_pressure_thread.Start();
26715 5 : memory_pressure_thread.Join();
26716 : // This should trigger GC.
26717 5 : CHECK_EQ(0, counter.NumberOfWeakCalls());
26718 : CompileRun("(function noop() { return 0; })()");
26719 10 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26720 : }
26721 5 : delete garbage;
26722 : // Check that critical memory pressure notification triggers GC.
26723 5 : garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26724 : {
26725 : v8::Locker locker(isolate);
26726 : // If isolate is locked, memory pressure notification should trigger GC.
26727 5 : CHECK_EQ(1, counter.NumberOfWeakCalls());
26728 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
26729 5 : CHECK_EQ(2, counter.NumberOfWeakCalls());
26730 : }
26731 5 : delete garbage;
26732 : // Check that moderate memory pressure notification sets GC into memory
26733 : // optimizing mode.
26734 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
26735 5 : CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26736 : // Check that disabling memory pressure returns GC into normal mode.
26737 5 : isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
26738 5 : CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26739 : }
26740 :
26741 23723 : TEST(SetIntegrityLevel) {
26742 5 : LocalContext context;
26743 5 : v8::Isolate* isolate = CcTest::isolate();
26744 10 : v8::HandleScope scope(isolate);
26745 :
26746 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
26747 25 : CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
26748 :
26749 : v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
26750 10 : CHECK(!is_frozen->BooleanValue(context.local()).FromJust());
26751 :
26752 10 : CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
26753 : .FromJust());
26754 :
26755 : is_frozen = CompileRun("Object.isFrozen(o)");
26756 15 : CHECK(is_frozen->BooleanValue(context.local()).FromJust());
26757 5 : }
26758 :
26759 23723 : TEST(PrivateForApiIsNumber) {
26760 5 : LocalContext context;
26761 5 : v8::Isolate* isolate = CcTest::isolate();
26762 10 : v8::HandleScope scope(isolate);
26763 :
26764 : // Shouldn't crash.
26765 10 : v8::Private::ForApi(isolate, v8_str("42"));
26766 5 : }
26767 :
26768 23724 : THREADED_TEST(ImmutableProto) {
26769 6 : LocalContext context;
26770 6 : v8::Isolate* isolate = context->GetIsolate();
26771 12 : v8::HandleScope handle_scope(isolate);
26772 :
26773 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26774 12 : templ->InstanceTemplate()->SetImmutableProto();
26775 :
26776 6 : Local<v8::Object> object = templ->GetFunction(context.local())
26777 6 : .ToLocalChecked()
26778 6 : ->NewInstance(context.local())
26779 : .ToLocalChecked();
26780 :
26781 : // Look up the prototype
26782 : Local<v8::Value> original_proto =
26783 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26784 :
26785 : // Setting the prototype (e.g., to null) throws
26786 12 : CHECK(object->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26787 :
26788 : // The original prototype is still there
26789 : Local<Value> new_proto =
26790 18 : object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26791 6 : CHECK(new_proto->IsObject());
26792 12 : CHECK(new_proto.As<v8::Object>()
26793 : ->Equals(context.local(), original_proto)
26794 6 : .FromJust());
26795 6 : }
26796 :
26797 : Local<v8::Context> call_eval_context;
26798 : Local<v8::Function> call_eval_bound_function;
26799 :
26800 10 : static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
26801 : v8::Context::Scope scope(call_eval_context);
26802 : args.GetReturnValue().Set(
26803 : call_eval_bound_function
26804 10 : ->Call(call_eval_context, call_eval_context->Global(), 0, nullptr)
26805 5 : .ToLocalChecked());
26806 5 : }
26807 :
26808 23723 : TEST(CrossActivationEval) {
26809 5 : LocalContext env;
26810 5 : v8::Isolate* isolate = env->GetIsolate();
26811 10 : v8::HandleScope scope(isolate);
26812 : {
26813 5 : call_eval_context = v8::Context::New(isolate);
26814 : v8::Context::Scope scope(call_eval_context);
26815 : call_eval_bound_function =
26816 5 : Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
26817 : }
26818 : env->Global()
26819 : ->Set(env.local(), v8_str("CallEval"),
26820 5 : v8::FunctionTemplate::New(isolate, CallEval)
26821 15 : ->GetFunction(env.local())
26822 25 : .ToLocalChecked())
26823 10 : .FromJust();
26824 : Local<Value> result = CompileRun("CallEval();");
26825 5 : CHECK(result->IsInt32());
26826 15 : CHECK_EQ(1, result->Int32Value(env.local()).FromJust());
26827 5 : }
26828 :
26829 23723 : TEST(EvalInAccessCheckedContext) {
26830 5 : v8::Isolate* isolate = CcTest::isolate();
26831 5 : v8::HandleScope scope(isolate);
26832 :
26833 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26834 :
26835 5 : obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
26836 :
26837 5 : v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
26838 5 : v8::Local<Context> context1 = Context::New(isolate, nullptr, obj_template);
26839 :
26840 5 : Local<Value> foo = v8_str("foo");
26841 5 : Local<Value> bar = v8_str("bar");
26842 :
26843 : // Set to different domains.
26844 5 : context0->SetSecurityToken(foo);
26845 5 : context1->SetSecurityToken(bar);
26846 :
26847 : // Set up function in context0 that uses eval from context0.
26848 5 : context0->Enter();
26849 : v8::Local<v8::Value> fun = CompileRun(
26850 : "var x = 42;"
26851 : "(function() {"
26852 : " var e = eval;"
26853 : " return function(s) { return e(s); }"
26854 5 : "})()");
26855 5 : context0->Exit();
26856 :
26857 : // Put the function into context1 and call it. Since the access check
26858 : // callback always returns true, the call succeeds even though the tokens
26859 : // are different.
26860 5 : context1->Enter();
26861 20 : context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
26862 : v8::Local<v8::Value> x_value = CompileRun("fun('x')");
26863 10 : CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
26864 5 : context1->Exit();
26865 5 : }
26866 :
26867 23724 : THREADED_TEST(ImmutableProtoWithParent) {
26868 6 : LocalContext context;
26869 6 : v8::Isolate* isolate = context->GetIsolate();
26870 12 : v8::HandleScope handle_scope(isolate);
26871 :
26872 6 : Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
26873 :
26874 6 : Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26875 6 : templ->Inherit(parent);
26876 12 : templ->PrototypeTemplate()->SetImmutableProto();
26877 :
26878 : Local<v8::Function> function =
26879 6 : templ->GetFunction(context.local()).ToLocalChecked();
26880 : Local<v8::Object> instance =
26881 6 : function->NewInstance(context.local()).ToLocalChecked();
26882 : Local<v8::Object> prototype =
26883 18 : instance->Get(context.local(), v8_str("__proto__"))
26884 6 : .ToLocalChecked()
26885 6 : ->ToObject(context.local())
26886 6 : .ToLocalChecked();
26887 :
26888 : // Look up the prototype
26889 : Local<v8::Value> original_proto =
26890 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26891 :
26892 : // Setting the prototype (e.g., to null) throws
26893 12 : CHECK(
26894 : prototype->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26895 :
26896 : // The original prototype is still there
26897 : Local<Value> new_proto =
26898 18 : prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26899 6 : CHECK(new_proto->IsObject());
26900 12 : CHECK(new_proto.As<v8::Object>()
26901 : ->Equals(context.local(), original_proto)
26902 6 : .FromJust());
26903 6 : }
26904 :
26905 23723 : TEST(InternalFieldsOnGlobalProxy) {
26906 5 : v8::Isolate* isolate = CcTest::isolate();
26907 5 : v8::HandleScope scope(isolate);
26908 :
26909 5 : v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26910 5 : obj_template->SetInternalFieldCount(1);
26911 :
26912 5 : v8::Local<v8::Context> context = Context::New(isolate, nullptr, obj_template);
26913 5 : v8::Local<v8::Object> global = context->Global();
26914 5 : CHECK_EQ(1, global->InternalFieldCount());
26915 5 : }
26916 :
26917 23724 : THREADED_TEST(ImmutableProtoGlobal) {
26918 6 : v8::Isolate* isolate = CcTest::isolate();
26919 6 : v8::HandleScope handle_scope(isolate);
26920 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26921 6 : global_template->SetImmutableProto();
26922 6 : v8::Local<Context> context = Context::New(isolate, 0, global_template);
26923 : Context::Scope context_scope(context);
26924 : v8::Local<Value> result = CompileRun(
26925 : "global = this;"
26926 : "(function() {"
26927 : " try {"
26928 : " global.__proto__ = {};"
26929 : " return 0;"
26930 : " } catch (e) {"
26931 : " return 1;"
26932 : " }"
26933 : "})()");
26934 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 1))
26935 6 : .FromJust());
26936 6 : }
26937 :
26938 23724 : THREADED_TEST(MutableProtoGlobal) {
26939 6 : v8::Isolate* isolate = CcTest::isolate();
26940 6 : v8::HandleScope handle_scope(isolate);
26941 6 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26942 6 : v8::Local<Context> context = Context::New(isolate, 0, global_template);
26943 : Context::Scope context_scope(context);
26944 : v8::Local<Value> result = CompileRun(
26945 : "global = this;"
26946 : "(function() {"
26947 : " try {"
26948 : " global.__proto__ = {};"
26949 : " return 0;"
26950 : " } catch (e) {"
26951 : " return 1;"
26952 : " }"
26953 : "})()");
26954 18 : CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 0))
26955 6 : .FromJust());
26956 6 : }
26957 :
26958 23723 : TEST(InternalFieldsOnTypedArray) {
26959 5 : LocalContext env;
26960 5 : v8::Isolate* isolate = env->GetIsolate();
26961 10 : v8::HandleScope scope(isolate);
26962 5 : v8::Local<v8::Context> context = env.local();
26963 : Context::Scope context_scope(context);
26964 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
26965 5 : v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
26966 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
26967 10 : CHECK_EQ(static_cast<void*>(nullptr),
26968 : array->GetAlignedPointerFromInternalField(i));
26969 5 : }
26970 5 : }
26971 :
26972 23723 : TEST(InternalFieldsOnDataView) {
26973 5 : LocalContext env;
26974 5 : v8::Isolate* isolate = env->GetIsolate();
26975 10 : v8::HandleScope scope(isolate);
26976 5 : v8::Local<v8::Context> context = env.local();
26977 : Context::Scope context_scope(context);
26978 5 : v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
26979 5 : v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
26980 15 : for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
26981 10 : CHECK_EQ(static_cast<void*>(nullptr),
26982 : array->GetAlignedPointerFromInternalField(i));
26983 5 : }
26984 5 : }
26985 :
26986 23723 : TEST(SetPrototypeTemplate) {
26987 5 : LocalContext env;
26988 5 : v8::Isolate* isolate = env->GetIsolate();
26989 10 : v8::HandleScope scope(isolate);
26990 :
26991 5 : Local<FunctionTemplate> HTMLElementTemplate = FunctionTemplate::New(isolate);
26992 : Local<FunctionTemplate> HTMLImageElementTemplate =
26993 5 : FunctionTemplate::New(isolate);
26994 5 : HTMLImageElementTemplate->Inherit(HTMLElementTemplate);
26995 :
26996 5 : Local<FunctionTemplate> ImageTemplate = FunctionTemplate::New(isolate);
26997 5 : ImageTemplate->SetPrototypeProviderTemplate(HTMLImageElementTemplate);
26998 :
26999 : Local<Function> HTMLImageElement =
27000 5 : HTMLImageElementTemplate->GetFunction(env.local()).ToLocalChecked();
27001 : Local<Function> Image =
27002 5 : ImageTemplate->GetFunction(env.local()).ToLocalChecked();
27003 :
27004 25 : CHECK(env->Global()
27005 : ->Set(env.local(), v8_str("HTMLImageElement"), HTMLImageElement)
27006 : .FromJust());
27007 25 : CHECK(env->Global()->Set(env.local(), v8_str("Image"), Image).FromJust());
27008 :
27009 5 : ExpectTrue("Image.prototype === HTMLImageElement.prototype");
27010 5 : }
27011 :
27012 120 : void ensure_receiver_is_global_proxy(
27013 : v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
27014 120 : CHECK(v8::Utils::OpenHandle(*info.This())->IsJSGlobalProxy());
27015 120 : }
27016 :
27017 23724 : THREADED_TEST(GlobalAccessorInfo) {
27018 6 : v8::Isolate* isolate = CcTest::isolate();
27019 6 : v8::HandleScope scope(isolate);
27020 6 : Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
27021 : global_template->SetAccessor(
27022 : v8::String::NewFromUtf8(isolate, "prop", v8::NewStringType::kInternalized)
27023 : .ToLocalChecked(),
27024 12 : &ensure_receiver_is_global_proxy);
27025 12 : LocalContext env(nullptr, global_template);
27026 : CompileRun("for (var i = 0; i < 10; i++) this.prop");
27027 6 : CompileRun("for (var i = 0; i < 10; i++) prop");
27028 6 : }
27029 :
27030 23723 : UNINITIALIZED_TEST(IncreaseHeapLimitForDebugging) {
27031 : v8::Isolate::CreateParams create_params;
27032 : create_params.constraints.set_max_old_space_size(16);
27033 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27034 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
27035 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27036 : {
27037 5 : size_t limit_before = i_isolate->heap()->MaxOldGenerationSize();
27038 5 : CHECK_EQ(16 * i::MB, limit_before);
27039 5 : CHECK(!isolate->IsHeapLimitIncreasedForDebugging());
27040 5 : isolate->IncreaseHeapLimitForDebugging();
27041 5 : CHECK(isolate->IsHeapLimitIncreasedForDebugging());
27042 5 : size_t limit_after = i_isolate->heap()->MaxOldGenerationSize();
27043 5 : CHECK_EQ(4 * 16 * i::MB, limit_after);
27044 5 : isolate->RestoreOriginalHeapLimit();
27045 5 : CHECK(!isolate->IsHeapLimitIncreasedForDebugging());
27046 5 : CHECK_EQ(limit_before, i_isolate->heap()->MaxOldGenerationSize());
27047 : }
27048 5 : isolate->Dispose();
27049 5 : }
27050 :
27051 23723 : TEST(DeterministicRandomNumberGeneration) {
27052 5 : v8::HandleScope scope(CcTest::isolate());
27053 :
27054 5 : int previous_seed = v8::internal::FLAG_random_seed;
27055 5 : v8::internal::FLAG_random_seed = 1234;
27056 :
27057 : double first_value;
27058 : double second_value;
27059 : {
27060 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27061 : Context::Scope context_scope(context);
27062 : v8::Local<Value> result = CompileRun("Math.random();");
27063 10 : first_value = result->ToNumber(context).ToLocalChecked()->Value();
27064 : }
27065 : {
27066 5 : v8::Local<Context> context = Context::New(CcTest::isolate());
27067 : Context::Scope context_scope(context);
27068 : v8::Local<Value> result = CompileRun("Math.random();");
27069 10 : second_value = result->ToNumber(context).ToLocalChecked()->Value();
27070 : }
27071 5 : CHECK_EQ(first_value, second_value);
27072 :
27073 5 : v8::internal::FLAG_random_seed = previous_seed;
27074 5 : }
27075 :
27076 23723 : UNINITIALIZED_TEST(AllowAtomicsWait) {
27077 : v8::Isolate::CreateParams create_params;
27078 5 : create_params.allow_atomics_wait = false;
27079 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27080 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
27081 10 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27082 : {
27083 5 : CHECK_EQ(false, i_isolate->allow_atomics_wait());
27084 5 : isolate->SetAllowAtomicsWait(true);
27085 5 : CHECK_EQ(true, i_isolate->allow_atomics_wait());
27086 : }
27087 5 : isolate->Dispose();
27088 5 : }
27089 :
27090 : enum ContextId { EnteredContext, CurrentContext };
27091 :
27092 20 : void CheckContexts(v8::Isolate* isolate) {
27093 60 : CHECK_EQ(CurrentContext, isolate->GetCurrentContext()
27094 : ->GetEmbedderData(1)
27095 : .As<v8::Integer>()
27096 : ->Value());
27097 60 : CHECK_EQ(EnteredContext, isolate->GetEnteredContext()
27098 : ->GetEmbedderData(1)
27099 : .As<v8::Integer>()
27100 : ->Value());
27101 20 : }
27102 :
27103 5 : void ContextCheckGetter(Local<String> name,
27104 : const v8::PropertyCallbackInfo<v8::Value>& info) {
27105 5 : CheckContexts(info.GetIsolate());
27106 : info.GetReturnValue().Set(true);
27107 5 : }
27108 :
27109 5 : void ContextCheckSetter(Local<String> name, Local<Value>,
27110 : const v8::PropertyCallbackInfo<void>& info) {
27111 5 : CheckContexts(info.GetIsolate());
27112 5 : }
27113 :
27114 20 : void ContextCheckToString(const v8::FunctionCallbackInfo<v8::Value>& info) {
27115 10 : CheckContexts(info.GetIsolate());
27116 10 : info.GetReturnValue().Set(v8_str("foo"));
27117 10 : }
27118 :
27119 23723 : TEST(CorrectEnteredContext) {
27120 5 : v8::HandleScope scope(CcTest::isolate());
27121 :
27122 10 : LocalContext currentContext;
27123 : currentContext->SetEmbedderData(
27124 10 : 1, v8::Integer::New(currentContext->GetIsolate(), CurrentContext));
27125 10 : LocalContext enteredContext;
27126 : enteredContext->SetEmbedderData(
27127 10 : 1, v8::Integer::New(enteredContext->GetIsolate(), EnteredContext));
27128 :
27129 5 : v8::Context::Scope contextScope(enteredContext.local());
27130 :
27131 : v8::Local<v8::ObjectTemplate> object_template =
27132 5 : ObjectTemplate::New(currentContext->GetIsolate());
27133 : object_template->SetAccessor(v8_str("p"), &ContextCheckGetter,
27134 5 : &ContextCheckSetter);
27135 :
27136 : v8::Local<v8::Object> object =
27137 5 : object_template->NewInstance(currentContext.local()).ToLocalChecked();
27138 :
27139 15 : object->Get(currentContext.local(), v8_str("p")).ToLocalChecked();
27140 15 : object->Set(currentContext.local(), v8_str("p"), v8_int(0)).FromJust();
27141 :
27142 : v8::Local<v8::Function> to_string =
27143 10 : v8::Function::New(currentContext.local(), ContextCheckToString)
27144 5 : .ToLocalChecked();
27145 :
27146 10 : to_string->Call(currentContext.local(), object, 0, nullptr).ToLocalChecked();
27147 :
27148 : object
27149 : ->CreateDataProperty(currentContext.local(), v8_str("toString"),
27150 15 : to_string)
27151 10 : .FromJust();
27152 :
27153 10 : object->ToString(currentContext.local()).ToLocalChecked();
27154 5 : }
27155 :
27156 5 : v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
27157 : Local<Context> context, Local<v8::ScriptOrModule> referrer,
27158 : Local<String> specifier) {
27159 5 : CHECK(!referrer.IsEmpty());
27160 : String::Utf8Value referrer_utf8(
27161 10 : context->GetIsolate(), Local<String>::Cast(referrer->GetResourceName()));
27162 5 : CHECK_EQ(0, strcmp("www.google.com", *referrer_utf8));
27163 15 : CHECK(referrer->GetHostDefinedOptions()->Get(0)->IsSymbol());
27164 :
27165 5 : CHECK(!specifier.IsEmpty());
27166 10 : String::Utf8Value specifier_utf8(context->GetIsolate(), specifier);
27167 5 : CHECK_EQ(0, strcmp("index.js", *specifier_utf8));
27168 :
27169 : Local<v8::Promise::Resolver> resolver =
27170 5 : v8::Promise::Resolver::New(context).ToLocalChecked();
27171 5 : auto result = v8_str("hello world");
27172 10 : resolver->Resolve(context, result).ToChecked();
27173 10 : return resolver->GetPromise();
27174 : }
27175 :
27176 23723 : TEST(DynamicImport) {
27177 5 : i::FLAG_harmony_dynamic_import = true;
27178 5 : LocalContext context;
27179 5 : v8::Isolate* isolate = context->GetIsolate();
27180 10 : v8::HandleScope scope(isolate);
27181 :
27182 : isolate->SetHostImportModuleDynamicallyCallback(
27183 5 : HostImportModuleDynamicallyCallbackResolve);
27184 :
27185 10 : i::Handle<i::String> url(v8::Utils::OpenHandle(*v8_str("www.google.com")));
27186 10 : i::Handle<i::Object> specifier(v8::Utils::OpenHandle(*v8_str("index.js")));
27187 10 : i::Handle<i::String> result(v8::Utils::OpenHandle(*v8_str("hello world")));
27188 10 : i::Handle<i::String> source(v8::Utils::OpenHandle(*v8_str("foo")));
27189 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27190 5 : i::Handle<i::FixedArray> options = i_isolate->factory()->NewFixedArray(1);
27191 5 : i::Handle<i::Symbol> symbol = i_isolate->factory()->NewSymbol();
27192 5 : options->set(0, *symbol);
27193 5 : i::Handle<i::Script> referrer = i_isolate->factory()->NewScript(source);
27194 5 : referrer->set_name(*url);
27195 5 : referrer->set_host_defined_options(*options);
27196 : i::MaybeHandle<i::JSPromise> maybe_promise =
27197 5 : i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
27198 : i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
27199 5 : isolate->RunMicrotasks();
27200 10 : CHECK(result->Equals(i::String::cast(promise->result())));
27201 5 : }
27202 :
27203 5 : void HostInitializeImportMetaObjectCallbackStatic(Local<Context> context,
27204 : Local<Module> module,
27205 : Local<Object> meta) {
27206 5 : CHECK(!module.IsEmpty());
27207 :
27208 20 : meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
27209 5 : }
27210 :
27211 0 : v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
27212 : Local<String> specifier,
27213 : Local<Module> referrer) {
27214 0 : CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
27215 : }
27216 :
27217 23723 : TEST(ImportMeta) {
27218 5 : i::FLAG_harmony_dynamic_import = true;
27219 5 : i::FLAG_harmony_import_meta = true;
27220 5 : LocalContext context;
27221 5 : v8::Isolate* isolate = context->GetIsolate();
27222 10 : v8::HandleScope scope(isolate);
27223 :
27224 : isolate->SetHostInitializeImportMetaObjectCallback(
27225 5 : HostInitializeImportMetaObjectCallbackStatic);
27226 :
27227 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27228 5 : Local<String> url = v8_str("www.google.com");
27229 5 : Local<String> source_text = v8_str("import.meta;");
27230 : v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27231 : Local<v8::Boolean>(), Local<v8::Integer>(),
27232 : Local<v8::Value>(), Local<v8::Boolean>(),
27233 : Local<v8::Boolean>(), True(isolate));
27234 : v8::ScriptCompiler::Source source(source_text, origin);
27235 : Local<Module> module =
27236 5 : v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27237 : i::Handle<i::Object> meta =
27238 : i_isolate->RunHostInitializeImportMetaObjectCallback(
27239 5 : v8::Utils::OpenHandle(*module));
27240 5 : CHECK(meta->IsJSObject());
27241 : Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
27242 15 : CHECK(meta_obj->Get(context.local(), v8_str("foo"))
27243 : .ToLocalChecked()
27244 : ->IsString());
27245 15 : CHECK(meta_obj->Get(context.local(), v8_str("zapp"))
27246 : .ToLocalChecked()
27247 : ->IsUndefined());
27248 :
27249 5 : module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27250 10 : .ToChecked();
27251 5 : Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
27252 10 : CHECK(result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
27253 5 : }
27254 :
27255 23723 : TEST(GlobalTemplateWithDoubleProperty) {
27256 5 : v8::Isolate* isolate = CcTest::isolate();
27257 5 : v8::HandleScope handle_scope(isolate);
27258 :
27259 5 : v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
27260 15 : global->Set(v8_str("double"), v8_num(3.14));
27261 :
27262 5 : v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
27263 :
27264 : v8::Context::Scope context_scope(context);
27265 :
27266 : Local<Value> result = CompileRun("double");
27267 5 : CHECK(result->IsNumber());
27268 15 : CheckDoubleEquals(3.14, result->NumberValue(context).ToChecked());
27269 5 : }
27270 :
27271 23723 : TEST(PrimitiveArray) {
27272 5 : v8::Isolate* isolate = CcTest::isolate();
27273 5 : v8::HandleScope scope(isolate);
27274 10 : LocalContext env;
27275 :
27276 : int length = 5;
27277 5 : Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 5));
27278 5 : CHECK_EQ(length, array->Length());
27279 :
27280 25 : for (int i = 0; i < length; i++) {
27281 25 : Local<v8::Primitive> item = array->Get(i);
27282 25 : CHECK(item->IsUndefined());
27283 : }
27284 :
27285 5 : Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
27286 5 : array->Set(0, symbol);
27287 10 : CHECK(array->Get(0)->IsSymbol());
27288 :
27289 : Local<v8::String> string =
27290 : v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kInternalized)
27291 5 : .ToLocalChecked();
27292 5 : array->Set(1, string);
27293 10 : CHECK(array->Get(0)->IsSymbol());
27294 10 : CHECK(array->Get(1)->IsString());
27295 :
27296 5 : Local<v8::Number> num = v8::Number::New(env->GetIsolate(), 3.1415926);
27297 5 : array->Set(2, num);
27298 10 : CHECK(array->Get(0)->IsSymbol());
27299 10 : CHECK(array->Get(1)->IsString());
27300 10 : CHECK(array->Get(2)->IsNumber());
27301 :
27302 : v8::Local<v8::Boolean> f = v8::False(isolate);
27303 5 : array->Set(3, f);
27304 10 : CHECK(array->Get(0)->IsSymbol());
27305 10 : CHECK(array->Get(1)->IsString());
27306 10 : CHECK(array->Get(2)->IsNumber());
27307 10 : CHECK(array->Get(3)->IsBoolean());
27308 :
27309 5 : v8::Local<v8::Primitive> n = v8::Null(isolate);
27310 5 : array->Set(4, n);
27311 10 : CHECK(array->Get(0)->IsSymbol());
27312 10 : CHECK(array->Get(1)->IsString());
27313 10 : CHECK(array->Get(2)->IsNumber());
27314 10 : CHECK(array->Get(3)->IsBoolean());
27315 15 : CHECK(array->Get(4)->IsNull());
27316 5 : }
27317 :
27318 23723 : TEST(PersistentValueMap) {
27319 5 : v8::Isolate* isolate = CcTest::isolate();
27320 5 : v8::HandleScope scope(isolate);
27321 10 : LocalContext env;
27322 :
27323 : v8::PersistentValueMap<
27324 : std::string, v8::Value,
27325 : v8::DefaultPersistentValueMapTraits<std::string, v8::Value>>
27326 : map(isolate);
27327 : v8::Local<v8::Value> value =
27328 : v8::String::NewFromUtf8(isolate, "value",
27329 : v8::NewStringType::kInternalized)
27330 5 : .ToLocalChecked();
27331 20 : map.Set("key", value);
27332 71159 : }
|