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 <stdlib.h>
29
30 #include "include/v8-function.h"
31 #include "src/api/api-inl.h"
32 #include "src/execution/frames-inl.h"
33 #include "src/strings/string-stream.h"
34 #include "test/cctest/cctest.h"
35
36 using ::v8::ObjectTemplate;
37 using ::v8::Value;
38 using ::v8::Context;
39 using ::v8::Local;
40 using ::v8::Name;
41 using ::v8::String;
42 using ::v8::Script;
43 using ::v8::Function;
44 using ::v8::Extension;
45
handle_property(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)46 static void handle_property(Local<String> name,
47 const v8::PropertyCallbackInfo<v8::Value>& info) {
48 ApiTestFuzzer::Fuzz();
49 info.GetReturnValue().Set(v8_num(900));
50 }
51
handle_property_2(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)52 static void handle_property_2(Local<String> name,
53 const v8::PropertyCallbackInfo<v8::Value>& info) {
54 ApiTestFuzzer::Fuzz();
55 info.GetReturnValue().Set(v8_num(902));
56 }
57
58
handle_property(const v8::FunctionCallbackInfo<v8::Value> & info)59 static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
60 ApiTestFuzzer::Fuzz();
61 CHECK_EQ(0, info.Length());
62 info.GetReturnValue().Set(v8_num(907));
63 }
64
65
THREADED_TEST(PropertyHandler)66 THREADED_TEST(PropertyHandler) {
67 LocalContext env;
68 v8::Isolate* isolate = env->GetIsolate();
69 v8::HandleScope scope(isolate);
70 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
71 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
72 Local<v8::FunctionTemplate> getter_templ =
73 v8::FunctionTemplate::New(isolate, handle_property);
74 getter_templ->SetLength(0);
75 fun_templ->
76 InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
77 fun_templ->InstanceTemplate()->
78 SetNativeDataProperty(v8_str("instance_foo"), handle_property);
79 fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
80 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
81 CHECK(env->Global()->Set(env.local(), v8_str("Fun"), fun).FromJust());
82 Local<Script> getter;
83 Local<Script> setter;
84 // check function instance accessors
85 getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
86 for (int i = 0; i < 4; i++) {
87 CHECK_EQ(900, getter->Run(env.local())
88 .ToLocalChecked()
89 ->Int32Value(env.local())
90 .FromJust());
91 }
92 setter = v8_compile("obj.instance_foo = 901;");
93 for (int i = 0; i < 4; i++) {
94 CHECK_EQ(901, setter->Run(env.local())
95 .ToLocalChecked()
96 ->Int32Value(env.local())
97 .FromJust());
98 }
99 getter = v8_compile("obj.bar;");
100 for (int i = 0; i < 4; i++) {
101 CHECK_EQ(907, getter->Run(env.local())
102 .ToLocalChecked()
103 ->Int32Value(env.local())
104 .FromJust());
105 }
106 setter = v8_compile("obj.bar = 908;");
107 for (int i = 0; i < 4; i++) {
108 CHECK_EQ(908, setter->Run(env.local())
109 .ToLocalChecked()
110 ->Int32Value(env.local())
111 .FromJust());
112 }
113 // check function static accessors
114 getter = v8_compile("Fun.object_foo;");
115 for (int i = 0; i < 4; i++) {
116 CHECK_EQ(902, getter->Run(env.local())
117 .ToLocalChecked()
118 ->Int32Value(env.local())
119 .FromJust());
120 }
121 setter = v8_compile("Fun.object_foo = 903;");
122 for (int i = 0; i < 4; i++) {
123 CHECK_EQ(903, setter->Run(env.local())
124 .ToLocalChecked()
125 ->Int32Value(env.local())
126 .FromJust());
127 }
128
129 // And now with null prototype.
130 CompileRun(env.local(), "obj.__proto__ = null;");
131 getter = v8_compile("obj.bar;");
132 for (int i = 0; i < 4; i++) {
133 CHECK_EQ(907, getter->Run(env.local())
134 .ToLocalChecked()
135 ->Int32Value(env.local())
136 .FromJust());
137 }
138 setter = v8_compile("obj.bar = 908;");
139 for (int i = 0; i < 4; i++) {
140 CHECK_EQ(908, setter->Run(env.local())
141 .ToLocalChecked()
142 ->Int32Value(env.local())
143 .FromJust());
144 }
145 }
146
147
GetIntValue(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)148 static void GetIntValue(Local<String> property,
149 const v8::PropertyCallbackInfo<v8::Value>& info) {
150 ApiTestFuzzer::Fuzz();
151 int* value = static_cast<int*>(info.Data().As<v8::External>()->Value());
152 info.GetReturnValue().Set(v8_num(*value));
153 }
154
155
SetIntValue(Local<String> property,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)156 static void SetIntValue(Local<String> property,
157 Local<Value> value,
158 const v8::PropertyCallbackInfo<void>& info) {
159 int* field = static_cast<int*>(info.Data().As<v8::External>()->Value());
160 *field = value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
161 }
162
163 int foo, bar, baz;
164
THREADED_TEST(GlobalVariableAccess)165 THREADED_TEST(GlobalVariableAccess) {
166 foo = 0;
167 bar = -4;
168 baz = 10;
169 v8::Isolate* isolate = CcTest::isolate();
170 v8::HandleScope scope(isolate);
171 v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
172 templ->InstanceTemplate()->SetAccessor(
173 v8_str("foo"), GetIntValue, SetIntValue,
174 v8::External::New(isolate, &foo));
175 templ->InstanceTemplate()->SetAccessor(
176 v8_str("bar"), GetIntValue, SetIntValue,
177 v8::External::New(isolate, &bar));
178 templ->InstanceTemplate()->SetAccessor(
179 v8_str("baz"), GetIntValue, SetIntValue,
180 v8::External::New(isolate, &baz));
181 LocalContext env(nullptr, templ->InstanceTemplate());
182 v8_compile("foo = (++bar) + baz")->Run(env.local()).ToLocalChecked();
183 CHECK_EQ(-3, bar);
184 CHECK_EQ(7, foo);
185 }
186
187
188 static int x_register[2] = {0, 0};
189 static v8::Local<v8::Object> x_receiver;
190 static v8::Local<v8::Object> x_holder;
191
192 template<class Info>
XGetter(const Info & info,int offset)193 static void XGetter(const Info& info, int offset) {
194 ApiTestFuzzer::Fuzz();
195 v8::Isolate* isolate = CcTest::isolate();
196 CHECK_EQ(isolate, info.GetIsolate());
197 CHECK(
198 x_receiver->Equals(isolate->GetCurrentContext(), info.This()).FromJust());
199 info.GetReturnValue().Set(v8_num(x_register[offset]));
200 }
201
202
XGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)203 static void XGetter(Local<String> name,
204 const v8::PropertyCallbackInfo<v8::Value>& info) {
205 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
206 .FromJust());
207 XGetter(info, 0);
208 }
209
210
XGetter(const v8::FunctionCallbackInfo<v8::Value> & info)211 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
212 CHECK(
213 x_receiver->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
214 .FromJust());
215 XGetter(info, 1);
216 }
217
218
219 template<class Info>
XSetter(Local<Value> value,const Info & info,int offset)220 static void XSetter(Local<Value> value, const Info& info, int offset) {
221 v8::Isolate* isolate = CcTest::isolate();
222 CHECK_EQ(isolate, info.GetIsolate());
223 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.This())
224 .FromJust());
225 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
226 .FromJust());
227 x_register[offset] =
228 value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
229 info.GetReturnValue().Set(v8_num(-1));
230 }
231
232
XSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)233 static void XSetter(Local<String> name,
234 Local<Value> value,
235 const v8::PropertyCallbackInfo<void>& info) {
236 XSetter(value, info, 0);
237 }
238
239
XSetter(const v8::FunctionCallbackInfo<v8::Value> & info)240 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
241 CHECK_EQ(1, info.Length());
242 XSetter(info[0], info, 1);
243 }
244
245
THREADED_TEST(AccessorIC)246 THREADED_TEST(AccessorIC) {
247 LocalContext context;
248 v8::Isolate* isolate = context->GetIsolate();
249 v8::HandleScope scope(isolate);
250 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
251 obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
252 obj->SetAccessorProperty(v8_str("x1"),
253 v8::FunctionTemplate::New(isolate, XGetter),
254 v8::FunctionTemplate::New(isolate, XSetter));
255 x_holder = obj->NewInstance(context.local()).ToLocalChecked();
256 CHECK(context->Global()
257 ->Set(context.local(), v8_str("holder"), x_holder)
258 .FromJust());
259 x_receiver = v8::Object::New(isolate);
260 CHECK(context->Global()
261 ->Set(context.local(), v8_str("obj"), x_receiver)
262 .FromJust());
263 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(
264 CompileRun("obj.__proto__ = holder;"
265 "var result = [];"
266 "var key_0 = 'x0';"
267 "var key_1 = 'x1';"
268 "for (var j = 0; j < 10; j++) {"
269 " var i = 4*j;"
270 " result.push(holder.x0 = i);"
271 " result.push(obj.x0);"
272 " result.push(holder.x1 = i + 1);"
273 " result.push(obj.x1);"
274 " result.push(holder[key_0] = i + 2);"
275 " result.push(obj[key_0]);"
276 " result.push(holder[key_1] = i + 3);"
277 " result.push(obj[key_1]);"
278 "}"
279 "result"));
280 CHECK_EQ(80u, array->Length());
281 for (int i = 0; i < 80; i++) {
282 v8::Local<Value> entry =
283 array->Get(context.local(), v8::Integer::New(isolate, i))
284 .ToLocalChecked();
285 CHECK(v8::Integer::New(isolate, i / 2)
286 ->Equals(context.local(), entry)
287 .FromJust());
288 }
289 }
290
291
292 template <int C>
HandleAllocatingGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)293 static void HandleAllocatingGetter(
294 Local<String> name,
295 const v8::PropertyCallbackInfo<v8::Value>& info) {
296 ApiTestFuzzer::Fuzz();
297 for (int i = 0; i < C; i++) {
298 USE(v8::String::NewFromUtf8Literal(info.GetIsolate(), "foo"));
299 }
300 info.GetReturnValue().Set(
301 v8::String::NewFromUtf8Literal(info.GetIsolate(), "foo"));
302 }
303
304
THREADED_TEST(HandleScopePop)305 THREADED_TEST(HandleScopePop) {
306 LocalContext context;
307 v8::Isolate* isolate = context->GetIsolate();
308 v8::HandleScope scope(isolate);
309 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
310 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
311 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
312 v8::Local<v8::Object> inst =
313 obj->NewInstance(context.local()).ToLocalChecked();
314 CHECK(
315 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
316 int count_before =
317 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
318 {
319 v8::HandleScope inner_scope(isolate);
320 CompileRun(
321 "for (var i = 0; i < 1000; i++) {"
322 " obj.one;"
323 " obj.many;"
324 "}");
325 }
326 int count_after =
327 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
328 CHECK_EQ(count_before, count_after);
329 }
330
CheckAccessorArgsCorrect(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)331 static void CheckAccessorArgsCorrect(
332 Local<String> name,
333 const v8::PropertyCallbackInfo<v8::Value>& info) {
334 CHECK(info.GetIsolate() == CcTest::isolate());
335 CHECK(info.This() == info.Holder());
336 CHECK(info.Data()
337 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
338 .FromJust());
339 ApiTestFuzzer::Fuzz();
340 CHECK(info.GetIsolate() == CcTest::isolate());
341 CHECK(info.This() == info.Holder());
342 CHECK(info.Data()
343 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
344 .FromJust());
345 CcTest::CollectAllGarbage();
346 CHECK(info.GetIsolate() == CcTest::isolate());
347 CHECK(info.This() == info.Holder());
348 CHECK(info.Data()
349 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
350 .FromJust());
351 info.GetReturnValue().Set(17);
352 }
353
354
THREADED_TEST(DirectCall)355 THREADED_TEST(DirectCall) {
356 LocalContext context;
357 v8::Isolate* isolate = context->GetIsolate();
358 v8::HandleScope scope(isolate);
359 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
360 obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, nullptr,
361 v8_str("data"));
362 v8::Local<v8::Object> inst =
363 obj->NewInstance(context.local()).ToLocalChecked();
364 CHECK(
365 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
366 Local<Script> scr =
367 v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
368 for (int i = 0; i < 10; i++) {
369 Local<Value> result = scr->Run(context.local()).ToLocalChecked();
370 CHECK(!result.IsEmpty());
371 CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
372 }
373 }
374
EmptyGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)375 static void EmptyGetter(Local<String> name,
376 const v8::PropertyCallbackInfo<v8::Value>& info) {
377 CheckAccessorArgsCorrect(name, info);
378 ApiTestFuzzer::Fuzz();
379 CheckAccessorArgsCorrect(name, info);
380 info.GetReturnValue().Set(v8::Local<v8::Value>());
381 }
382
383
THREADED_TEST(EmptyResult)384 THREADED_TEST(EmptyResult) {
385 LocalContext context;
386 v8::Isolate* isolate = context->GetIsolate();
387 v8::HandleScope scope(isolate);
388 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
389 obj->SetAccessor(v8_str("xxx"), EmptyGetter, nullptr, v8_str("data"));
390 v8::Local<v8::Object> inst =
391 obj->NewInstance(context.local()).ToLocalChecked();
392 CHECK(
393 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
394 Local<Script> scr =
395 v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
396 for (int i = 0; i < 10; i++) {
397 Local<Value> result = scr->Run(context.local()).ToLocalChecked();
398 CHECK(result == v8::Undefined(isolate));
399 }
400 }
401
402
THREADED_TEST(NoReuseRegress)403 THREADED_TEST(NoReuseRegress) {
404 // Check that the IC generated for the one test doesn't get reused
405 // for the other.
406 v8::Isolate* isolate = CcTest::isolate();
407 v8::HandleScope scope(isolate);
408 {
409 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
410 obj->SetAccessor(v8_str("xxx"), EmptyGetter, nullptr, v8_str("data"));
411 LocalContext context;
412 v8::Local<v8::Object> inst =
413 obj->NewInstance(context.local()).ToLocalChecked();
414 CHECK(context->Global()
415 ->Set(context.local(), v8_str("obj"), inst)
416 .FromJust());
417 Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
418 .ToLocalChecked();
419 for (int i = 0; i < 2; i++) {
420 Local<Value> result = scr->Run(context.local()).ToLocalChecked();
421 CHECK(result == v8::Undefined(isolate));
422 }
423 }
424 {
425 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
426 obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, nullptr,
427 v8_str("data"));
428 LocalContext context;
429 v8::Local<v8::Object> inst =
430 obj->NewInstance(context.local()).ToLocalChecked();
431 CHECK(context->Global()
432 ->Set(context.local(), v8_str("obj"), inst)
433 .FromJust());
434 Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
435 .ToLocalChecked();
436 for (int i = 0; i < 10; i++) {
437 Local<Value> result = scr->Run(context.local()).ToLocalChecked();
438 CHECK(!result.IsEmpty());
439 CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
440 }
441 }
442 }
443
ThrowingGetAccessor(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)444 static void ThrowingGetAccessor(
445 Local<String> name,
446 const v8::PropertyCallbackInfo<v8::Value>& info) {
447 ApiTestFuzzer::Fuzz();
448 info.GetIsolate()->ThrowException(v8_str("g"));
449 }
450
451
ThrowingSetAccessor(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)452 static void ThrowingSetAccessor(Local<String> name,
453 Local<Value> value,
454 const v8::PropertyCallbackInfo<void>& info) {
455 info.GetIsolate()->ThrowException(value);
456 }
457
458
THREADED_TEST(Regress1054726)459 THREADED_TEST(Regress1054726) {
460 LocalContext env;
461 v8::Isolate* isolate = env->GetIsolate();
462 v8::HandleScope scope(isolate);
463 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
464 obj->SetAccessor(v8_str("x"),
465 ThrowingGetAccessor,
466 ThrowingSetAccessor,
467 Local<Value>());
468
469 CHECK(env->Global()
470 ->Set(env.local(), v8_str("obj"),
471 obj->NewInstance(env.local()).ToLocalChecked())
472 .FromJust());
473
474 // Use the throwing property setter/getter in a loop to force
475 // the accessor ICs to be initialized.
476 v8::Local<Value> result;
477 result = Script::Compile(env.local(),
478 v8_str("var result = '';"
479 "for (var i = 0; i < 5; i++) {"
480 " try { obj.x; } catch (e) { result += e; }"
481 "}; result"))
482 .ToLocalChecked()
483 ->Run(env.local())
484 .ToLocalChecked();
485 CHECK(v8_str("ggggg")->Equals(env.local(), result).FromJust());
486
487 result =
488 Script::Compile(env.local(),
489 v8_str("var result = '';"
490 "for (var i = 0; i < 5; i++) {"
491 " try { obj.x = i; } catch (e) { result += e; }"
492 "}; result"))
493 .ToLocalChecked()
494 ->Run(env.local())
495 .ToLocalChecked();
496 CHECK(v8_str("01234")->Equals(env.local(), result).FromJust());
497 }
498
499
AllocGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)500 static void AllocGetter(Local<String> name,
501 const v8::PropertyCallbackInfo<v8::Value>& info) {
502 ApiTestFuzzer::Fuzz();
503 info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
504 }
505
506
THREADED_TEST(Gc)507 THREADED_TEST(Gc) {
508 LocalContext env;
509 v8::Isolate* isolate = env->GetIsolate();
510 v8::HandleScope scope(isolate);
511 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
512 obj->SetAccessor(v8_str("xxx"), AllocGetter);
513 CHECK(env->Global()
514 ->Set(env.local(), v8_str("obj"),
515 obj->NewInstance(env.local()).ToLocalChecked())
516 .FromJust());
517 Script::Compile(env.local(), v8_str("var last = [];"
518 "for (var i = 0; i < 2048; i++) {"
519 " var result = obj.xxx;"
520 " result[0] = last;"
521 " last = result;"
522 "}"))
523 .ToLocalChecked()
524 ->Run(env.local())
525 .ToLocalChecked();
526 }
527
528
StackCheck(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)529 static void StackCheck(Local<String> name,
530 const v8::PropertyCallbackInfo<v8::Value>& info) {
531 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
532 i::StackFrameIterator iter(isolate);
533 for (int i = 0; !iter.done(); i++) {
534 i::StackFrame* frame = iter.frame();
535 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
536 i::Code code = frame->LookupCode();
537 CHECK(code.IsCode());
538 CHECK(code.contains(isolate, frame->pc()));
539 iter.Advance();
540 }
541 }
542
543
THREADED_TEST(StackIteration)544 THREADED_TEST(StackIteration) {
545 LocalContext env;
546 v8::Isolate* isolate = env->GetIsolate();
547 v8::HandleScope scope(isolate);
548 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
549 i::StringStream::ClearMentionedObjectCache(
550 reinterpret_cast<i::Isolate*>(isolate));
551 obj->SetAccessor(v8_str("xxx"), StackCheck);
552 CHECK(env->Global()
553 ->Set(env.local(), v8_str("obj"),
554 obj->NewInstance(env.local()).ToLocalChecked())
555 .FromJust());
556 Script::Compile(env.local(), v8_str("function foo() {"
557 " return obj.xxx;"
558 "}"
559 "for (var i = 0; i < 100; i++) {"
560 " foo();"
561 "}"))
562 .ToLocalChecked()
563 ->Run(env.local())
564 .ToLocalChecked();
565 }
566
567
AllocateHandles(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)568 static void AllocateHandles(Local<String> name,
569 const v8::PropertyCallbackInfo<v8::Value>& info) {
570 for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
571 v8::Local<v8::Value>::New(info.GetIsolate(), name);
572 }
573 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
574 }
575
576
THREADED_TEST(HandleScopeSegment)577 THREADED_TEST(HandleScopeSegment) {
578 // Check that we can return values past popping of handle scope
579 // segments.
580 LocalContext env;
581 v8::Isolate* isolate = env->GetIsolate();
582 v8::HandleScope scope(isolate);
583 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
584 obj->SetAccessor(v8_str("xxx"), AllocateHandles);
585 CHECK(env->Global()
586 ->Set(env.local(), v8_str("obj"),
587 obj->NewInstance(env.local()).ToLocalChecked())
588 .FromJust());
589 v8::Local<v8::Value> result =
590 Script::Compile(env.local(), v8_str("var result;"
591 "for (var i = 0; i < 4; i++)"
592 " result = obj.xxx;"
593 "result;"))
594 .ToLocalChecked()
595 ->Run(env.local())
596 .ToLocalChecked();
597 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
598 }
599
600
JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)601 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
602 v8::Local<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
603 CHECK(array->Set(info.GetIsolate()->GetCurrentContext(), 0, v8_str("regress"))
604 .FromJust());
605 info.GetReturnValue().Set(array);
606 }
607
608
JSONStringifyGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)609 void JSONStringifyGetter(Local<Name> name,
610 const v8::PropertyCallbackInfo<v8::Value>& info) {
611 info.GetReturnValue().Set(v8_str("crbug-161028"));
612 }
613
614
THREADED_TEST(JSONStringifyNamedInterceptorObject)615 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
616 LocalContext env;
617 v8::Isolate* isolate = env->GetIsolate();
618 v8::HandleScope scope(isolate);
619
620 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
621 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
622 JSONStringifyGetter, nullptr, nullptr, nullptr, JSONStringifyEnumerator));
623 CHECK(env->Global()
624 ->Set(env.local(), v8_str("obj"),
625 obj->NewInstance(env.local()).ToLocalChecked())
626 .FromJust());
627 v8::Local<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
628 CHECK(CompileRun("JSON.stringify(obj)")
629 ->Equals(env.local(), expected)
630 .FromJust());
631 }
632
633
634 static v8::Local<v8::Context> expected_current_context;
635
636
check_contexts(const v8::FunctionCallbackInfo<v8::Value> & info)637 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
638 ApiTestFuzzer::Fuzz();
639 CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
640 }
641
642
THREADED_TEST(AccessorPropertyCrossContext)643 THREADED_TEST(AccessorPropertyCrossContext) {
644 LocalContext env;
645 v8::Isolate* isolate = env->GetIsolate();
646 v8::HandleScope scope(isolate);
647 v8::Local<v8::Function> fun =
648 v8::Function::New(env.local(), check_contexts).ToLocalChecked();
649 LocalContext switch_context;
650 CHECK(switch_context->Global()
651 ->Set(switch_context.local(), v8_str("fun"), fun)
652 .FromJust());
653 v8::TryCatch try_catch(isolate);
654 expected_current_context = env.local();
655 CompileRun(
656 "var o = Object.create(null, { n: { get:fun } });"
657 "for (var i = 0; i < 10; i++) o.n;");
658 CHECK(!try_catch.HasCaught());
659 }
660
661
THREADED_TEST(GlobalObjectAccessor)662 THREADED_TEST(GlobalObjectAccessor) {
663 LocalContext env;
664 v8::Isolate* isolate = env->GetIsolate();
665 v8::HandleScope scope(isolate);
666 CompileRun(
667 "var set_value = 1;"
668 "Object.defineProperty(this.__proto__, 'x', {"
669 " get : function() { return this; },"
670 " set : function() { set_value = this; }"
671 "});"
672 "function getter() { return x; }"
673 "function setter() { x = 1; }");
674
675 Local<Script> check_getter = v8_compile("getter()");
676 Local<Script> check_setter = v8_compile("setter(); set_value");
677
678 // Ensure that LoadGlobalICs in getter and StoreGlobalICs setter get
679 // JSGlobalProxy as a receiver regardless of the current IC state and
680 // the order in which ICs are executed.
681 for (int i = 0; i < 10; i++) {
682 CHECK(
683 v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
684 ->IsJSGlobalProxy());
685 }
686 for (int i = 0; i < 10; i++) {
687 CHECK(
688 v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
689 ->IsJSGlobalProxy());
690 }
691 for (int i = 0; i < 10; i++) {
692 CHECK(
693 v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
694 ->IsJSGlobalProxy());
695 CHECK(
696 v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
697 ->IsJSGlobalProxy());
698 }
699 }
700
701
EmptyGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)702 static void EmptyGetter(Local<Name> name,
703 const v8::PropertyCallbackInfo<v8::Value>& info) {
704 ApiTestFuzzer::Fuzz();
705 }
706
707
OneProperty(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)708 static void OneProperty(Local<String> name,
709 const v8::PropertyCallbackInfo<v8::Value>& info) {
710 ApiTestFuzzer::Fuzz();
711 info.GetReturnValue().Set(v8_num(1));
712 }
713
714
THREADED_TEST(Regress433458)715 THREADED_TEST(Regress433458) {
716 LocalContext env;
717 v8::Isolate* isolate = env->GetIsolate();
718 v8::HandleScope scope(isolate);
719 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
720 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
721 obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
722 CHECK(env->Global()
723 ->Set(env.local(), v8_str("obj"),
724 obj->NewInstance(env.local()).ToLocalChecked())
725 .FromJust());
726 CompileRun(
727 "Object.defineProperty(obj, 'prop', { writable: false });"
728 "Object.defineProperty(obj, 'prop', { writable: true });");
729 }
730
731
732 static bool security_check_value = false;
733
SecurityTestCallback(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)734 static bool SecurityTestCallback(Local<v8::Context> accessing_context,
735 Local<v8::Object> accessed_object,
736 Local<v8::Value> data) {
737 return security_check_value;
738 }
739
740
TEST(PrototypeGetterAccessCheck)741 TEST(PrototypeGetterAccessCheck) {
742 i::FLAG_allow_natives_syntax = true;
743 LocalContext env;
744 v8::Isolate* isolate = env->GetIsolate();
745 v8::HandleScope scope(isolate);
746 auto fun_templ = v8::FunctionTemplate::New(isolate);
747 auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property);
748 getter_templ->SetAcceptAnyReceiver(false);
749 fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"),
750 getter_templ);
751 auto obj_templ = v8::ObjectTemplate::New(isolate);
752 obj_templ->SetAccessCheckCallback(SecurityTestCallback);
753 CHECK(env->Global()
754 ->Set(env.local(), v8_str("Fun"),
755 fun_templ->GetFunction(env.local()).ToLocalChecked())
756 .FromJust());
757 CHECK(env->Global()
758 ->Set(env.local(), v8_str("obj"),
759 obj_templ->NewInstance(env.local()).ToLocalChecked())
760 .FromJust());
761 CHECK(env->Global()
762 ->Set(env.local(), v8_str("obj2"),
763 obj_templ->NewInstance(env.local()).ToLocalChecked())
764 .FromJust());
765
766 security_check_value = true;
767 CompileRun("var proto = new Fun();");
768 CompileRun("obj.__proto__ = proto;");
769 ExpectInt32("proto.foo", 907);
770
771 // Test direct.
772 security_check_value = true;
773 ExpectInt32("obj.foo", 907);
774 security_check_value = false;
775 {
776 v8::TryCatch try_catch(isolate);
777 CompileRun("obj.foo");
778 CHECK(try_catch.HasCaught());
779 }
780
781 // Test through call.
782 security_check_value = true;
783 ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907);
784 security_check_value = false;
785 {
786 v8::TryCatch try_catch(isolate);
787 CompileRun("proto.__lookupGetter__('foo').call(obj)");
788 CHECK(try_catch.HasCaught());
789 }
790
791 // Test ics.
792 CompileRun(
793 "function f() {"
794 " var x;"
795 " for (var i = 0; i < 4; i++) {"
796 " x = obj.foo;"
797 " }"
798 " return x;"
799 "};"
800 "%PrepareFunctionForOptimization(f);");
801
802 security_check_value = true;
803 ExpectInt32("f()", 907);
804 security_check_value = false;
805 {
806 v8::TryCatch try_catch(isolate);
807 CompileRun("f();");
808 CHECK(try_catch.HasCaught());
809 }
810
811 // Test TurboFan.
812 CompileRun("%OptimizeFunctionOnNextCall(f);");
813
814 security_check_value = true;
815 ExpectInt32("f()", 907);
816 security_check_value = false;
817 {
818 v8::TryCatch try_catch(isolate);
819 CompileRun("f();");
820 CHECK(try_catch.HasCaught());
821 }
822 }
823
CheckReceiver(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)824 static void CheckReceiver(Local<String> name,
825 const v8::PropertyCallbackInfo<v8::Value>& info) {
826 CHECK(info.This()->IsObject());
827 }
828
TEST(Regress609134)829 TEST(Regress609134) {
830 LocalContext env;
831 v8::Isolate* isolate = env->GetIsolate();
832 v8::HandleScope scope(isolate);
833 auto fun_templ = v8::FunctionTemplate::New(isolate);
834 fun_templ->InstanceTemplate()->SetNativeDataProperty(v8_str("foo"),
835 CheckReceiver);
836
837 CHECK(env->Global()
838 ->Set(env.local(), v8_str("Fun"),
839 fun_templ->GetFunction(env.local()).ToLocalChecked())
840 .FromJust());
841
842 CompileRun(
843 "var f = new Fun();"
844 "Number.prototype.__proto__ = f;"
845 "var a = 42;"
846 "for (var i = 0; i<3; i++) { a.foo; }");
847 }
848
TEST(ObjectSetLazyDataProperty)849 TEST(ObjectSetLazyDataProperty) {
850 LocalContext env;
851 v8::Isolate* isolate = env->GetIsolate();
852 v8::HandleScope scope(isolate);
853 v8::Local<v8::Object> obj = v8::Object::New(isolate);
854 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
855
856 // Despite getting the property multiple times, the getter should only be
857 // called once and data property reads should continue to produce the same
858 // value.
859 static int getter_call_count;
860 getter_call_count = 0;
861 auto result = obj->SetLazyDataProperty(
862 env.local(), v8_str("foo"),
863 [](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
864 getter_call_count++;
865 info.GetReturnValue().Set(getter_call_count);
866 });
867 CHECK(result.FromJust());
868 CHECK_EQ(0, getter_call_count);
869 for (int i = 0; i < 2; i++) {
870 ExpectInt32("obj.foo", 1);
871 CHECK_EQ(1, getter_call_count);
872 }
873
874 // Setting should overwrite the data property.
875 result = obj->SetLazyDataProperty(
876 env.local(), v8_str("bar"),
877 [](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
878 CHECK(false);
879 });
880 CHECK(result.FromJust());
881 ExpectInt32("obj.bar = -1; obj.bar;", -1);
882 }
883
TEST(ObjectSetLazyDataPropertyForIndex)884 TEST(ObjectSetLazyDataPropertyForIndex) {
885 // Regression test for crbug.com/1136800 .
886 LocalContext env;
887 v8::Isolate* isolate = env->GetIsolate();
888 v8::HandleScope scope(isolate);
889 v8::Local<v8::Object> obj = v8::Object::New(isolate);
890 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
891
892 static int getter_call_count;
893 getter_call_count = 0;
894 auto result = obj->SetLazyDataProperty(
895 env.local(), v8_str("1"),
896 [](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
897 getter_call_count++;
898 info.GetReturnValue().Set(getter_call_count);
899 });
900 CHECK(result.FromJust());
901 CHECK_EQ(0, getter_call_count);
902 for (int i = 0; i < 2; i++) {
903 ExpectInt32("obj[1]", 1);
904 CHECK_EQ(1, getter_call_count);
905 }
906 }
907
TEST(ObjectTemplateSetLazyPropertySurvivesIC)908 TEST(ObjectTemplateSetLazyPropertySurvivesIC) {
909 i::FLAG_allow_natives_syntax = true;
910 LocalContext env;
911 v8::Isolate* isolate = env->GetIsolate();
912 v8::HandleScope scope(isolate);
913 v8::Local<v8::Context> context = isolate->GetCurrentContext();
914
915 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
916 static int getter_call_count = 0;
917 templ->SetLazyDataProperty(
918 v8_str("foo"), [](v8::Local<v8::Name> name,
919 const v8::PropertyCallbackInfo<v8::Value>& info) {
920 getter_call_count++;
921 info.GetReturnValue().Set(getter_call_count);
922 });
923
924 v8::Local<v8::Function> f = CompileRun(
925 "function f(obj) {"
926 " obj.foo;"
927 " obj.foo;"
928 "};"
929 "%PrepareFunctionForOptimization(f);"
930 "f")
931 .As<v8::Function>();
932 v8::Local<v8::Value> obj = templ->NewInstance(context).ToLocalChecked();
933 f->Call(context, context->Global(), 1, &obj).ToLocalChecked();
934 CHECK_EQ(getter_call_count, 1);
935
936 obj = templ->NewInstance(context).ToLocalChecked();
937 f->Call(context, context->Global(), 1, &obj).ToLocalChecked();
938 CHECK_EQ(getter_call_count, 2);
939 }
940