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
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.
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.
33 #include "src/frames-inl.h"
34 #include "src/string-stream.h"
35 #include "test/cctest/cctest.h"
37 using ::v8::ObjectTemplate;
45 using ::v8::Extension;
47 static void handle_property(Local<String> name,
48 const v8::PropertyCallbackInfo<v8::Value>& info) {
49 ApiTestFuzzer::Fuzz();
50 info.GetReturnValue().Set(v8_num(900));
53 static void handle_property_2(Local<String> name,
54 const v8::PropertyCallbackInfo<v8::Value>& info) {
55 ApiTestFuzzer::Fuzz();
56 info.GetReturnValue().Set(v8_num(902));
60 static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
61 ApiTestFuzzer::Fuzz();
62 CHECK_EQ(0, info.Length());
63 info.GetReturnValue().Set(v8_num(907));
67 THREADED_TEST(PropertyHandler) {
69 v8::Isolate* isolate = env->GetIsolate();
70 v8::HandleScope scope(isolate);
71 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
72 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
73 Local<v8::FunctionTemplate> getter_templ =
74 v8::FunctionTemplate::New(isolate, handle_property);
75 getter_templ->SetLength(0);
77 InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
78 fun_templ->InstanceTemplate()->
79 SetNativeDataProperty(v8_str("instance_foo"), handle_property);
80 fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
81 Local<Function> fun = fun_templ->GetFunction();
82 env->Global()->Set(v8_str("Fun"), fun);
85 // check function instance accessors
86 getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
87 CHECK_EQ(900, getter->Run()->Int32Value());
88 setter = v8_compile("obj.instance_foo = 901;");
89 CHECK_EQ(901, setter->Run()->Int32Value());
90 getter = v8_compile("obj.bar;");
91 CHECK_EQ(907, getter->Run()->Int32Value());
92 setter = v8_compile("obj.bar = 908;");
93 CHECK_EQ(908, setter->Run()->Int32Value());
94 // check function static accessors
95 getter = v8_compile("Fun.object_foo;");
96 CHECK_EQ(902, getter->Run()->Int32Value());
97 setter = v8_compile("Fun.object_foo = 903;");
98 CHECK_EQ(903, setter->Run()->Int32Value());
102 static void GetIntValue(Local<String> property,
103 const v8::PropertyCallbackInfo<v8::Value>& info) {
104 ApiTestFuzzer::Fuzz();
106 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
107 info.GetReturnValue().Set(v8_num(*value));
111 static void SetIntValue(Local<String> property,
113 const v8::PropertyCallbackInfo<void>& info) {
115 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
116 *field = value->Int32Value();
121 THREADED_TEST(GlobalVariableAccess) {
125 v8::Isolate* isolate = CcTest::isolate();
126 v8::HandleScope scope(isolate);
127 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
128 templ->InstanceTemplate()->SetAccessor(
129 v8_str("foo"), GetIntValue, SetIntValue,
130 v8::External::New(isolate, &foo));
131 templ->InstanceTemplate()->SetAccessor(
132 v8_str("bar"), GetIntValue, SetIntValue,
133 v8::External::New(isolate, &bar));
134 templ->InstanceTemplate()->SetAccessor(
135 v8_str("baz"), GetIntValue, SetIntValue,
136 v8::External::New(isolate, &baz));
137 LocalContext env(0, templ->InstanceTemplate());
138 v8_compile("foo = (++bar) + baz")->Run();
144 static int x_register[2] = {0, 0};
145 static v8::Handle<v8::Object> x_receiver;
146 static v8::Handle<v8::Object> x_holder;
149 static void XGetter(const Info& info, int offset) {
150 ApiTestFuzzer::Fuzz();
151 v8::Isolate* isolate = CcTest::isolate();
152 CHECK_EQ(isolate, info.GetIsolate());
153 CHECK(x_receiver->Equals(info.This()));
154 info.GetReturnValue().Set(v8_num(x_register[offset]));
158 static void XGetter(Local<String> name,
159 const v8::PropertyCallbackInfo<v8::Value>& info) {
160 CHECK(x_holder->Equals(info.Holder()));
165 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
166 CHECK(x_receiver->Equals(info.Holder()));
172 static void XSetter(Local<Value> value, const Info& info, int offset) {
173 v8::Isolate* isolate = CcTest::isolate();
174 CHECK_EQ(isolate, info.GetIsolate());
175 CHECK(x_holder->Equals(info.This()));
176 CHECK(x_holder->Equals(info.Holder()));
177 x_register[offset] = value->Int32Value();
178 info.GetReturnValue().Set(v8_num(-1));
182 static void XSetter(Local<String> name,
184 const v8::PropertyCallbackInfo<void>& info) {
185 XSetter(value, info, 0);
189 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
190 CHECK_EQ(1, info.Length());
191 XSetter(info[0], info, 1);
195 THREADED_TEST(AccessorIC) {
196 LocalContext context;
197 v8::Isolate* isolate = context->GetIsolate();
198 v8::HandleScope scope(isolate);
199 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
200 obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
201 obj->SetAccessorProperty(v8_str("x1"),
202 v8::FunctionTemplate::New(isolate, XGetter),
203 v8::FunctionTemplate::New(isolate, XSetter));
204 x_holder = obj->NewInstance();
205 context->Global()->Set(v8_str("holder"), x_holder);
206 x_receiver = v8::Object::New(isolate);
207 context->Global()->Set(v8_str("obj"), x_receiver);
208 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
209 "obj.__proto__ = holder;"
213 "for (var j = 0; j < 10; j++) {"
215 " result.push(holder.x0 = i);"
216 " result.push(obj.x0);"
217 " result.push(holder.x1 = i + 1);"
218 " result.push(obj.x1);"
219 " result.push(holder[key_0] = i + 2);"
220 " result.push(obj[key_0]);"
221 " result.push(holder[key_1] = i + 3);"
222 " result.push(obj[key_1]);"
225 CHECK_EQ(80u, array->Length());
226 for (int i = 0; i < 80; i++) {
227 v8::Handle<Value> entry = array->Get(v8::Integer::New(isolate, i));
228 CHECK(v8::Integer::New(isolate, i / 2)->Equals(entry));
234 static void HandleAllocatingGetter(
236 const v8::PropertyCallbackInfo<v8::Value>& info) {
237 ApiTestFuzzer::Fuzz();
238 for (int i = 0; i < C; i++)
239 v8::String::NewFromUtf8(info.GetIsolate(), "foo");
240 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo"));
244 THREADED_TEST(HandleScopePop) {
245 LocalContext context;
246 v8::Isolate* isolate = context->GetIsolate();
247 v8::HandleScope scope(isolate);
248 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
249 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
250 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
251 v8::Handle<v8::Object> inst = obj->NewInstance();
252 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
254 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
256 v8::HandleScope scope(isolate);
258 "for (var i = 0; i < 1000; i++) {"
264 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
265 CHECK_EQ(count_before, count_after);
268 static void CheckAccessorArgsCorrect(
270 const v8::PropertyCallbackInfo<v8::Value>& info) {
271 CHECK(info.GetIsolate() == CcTest::isolate());
272 CHECK(info.This() == info.Holder());
274 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
275 ApiTestFuzzer::Fuzz();
276 CHECK(info.GetIsolate() == CcTest::isolate());
277 CHECK(info.This() == info.Holder());
279 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
280 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
281 CHECK(info.GetIsolate() == CcTest::isolate());
282 CHECK(info.This() == info.Holder());
284 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
285 info.GetReturnValue().Set(17);
289 THREADED_TEST(DirectCall) {
290 LocalContext context;
291 v8::Isolate* isolate = context->GetIsolate();
292 v8::HandleScope scope(isolate);
293 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
294 obj->SetAccessor(v8_str("xxx"),
295 CheckAccessorArgsCorrect,
297 v8::String::NewFromUtf8(isolate, "data"));
298 v8::Handle<v8::Object> inst = obj->NewInstance();
299 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"),
301 Local<Script> scr = v8::Script::Compile(
302 v8::String::NewFromUtf8(isolate, "obj.xxx"));
303 for (int i = 0; i < 10; i++) {
304 Local<Value> result = scr->Run();
305 CHECK(!result.IsEmpty());
306 CHECK_EQ(17, result->Int32Value());
310 static void EmptyGetter(Local<String> name,
311 const v8::PropertyCallbackInfo<v8::Value>& info) {
312 CheckAccessorArgsCorrect(name, info);
313 ApiTestFuzzer::Fuzz();
314 CheckAccessorArgsCorrect(name, info);
315 info.GetReturnValue().Set(v8::Handle<v8::Value>());
319 THREADED_TEST(EmptyResult) {
320 LocalContext context;
321 v8::Isolate* isolate = context->GetIsolate();
322 v8::HandleScope scope(isolate);
323 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
324 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
325 v8::String::NewFromUtf8(isolate, "data"));
326 v8::Handle<v8::Object> inst = obj->NewInstance();
327 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
329 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
330 for (int i = 0; i < 10; i++) {
331 Local<Value> result = scr->Run();
332 CHECK(result == v8::Undefined(isolate));
337 THREADED_TEST(NoReuseRegress) {
338 // Check that the IC generated for the one test doesn't get reused
340 v8::Isolate* isolate = CcTest::isolate();
341 v8::HandleScope scope(isolate);
343 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
344 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
345 v8::String::NewFromUtf8(isolate, "data"));
346 LocalContext context;
347 v8::Handle<v8::Object> inst = obj->NewInstance();
348 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
350 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
351 for (int i = 0; i < 2; i++) {
352 Local<Value> result = scr->Run();
353 CHECK(result == v8::Undefined(isolate));
357 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
358 obj->SetAccessor(v8_str("xxx"),
359 CheckAccessorArgsCorrect,
361 v8::String::NewFromUtf8(isolate, "data"));
362 LocalContext context;
363 v8::Handle<v8::Object> inst = obj->NewInstance();
364 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
366 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
367 for (int i = 0; i < 10; i++) {
368 Local<Value> result = scr->Run();
369 CHECK(!result.IsEmpty());
370 CHECK_EQ(17, result->Int32Value());
375 static void ThrowingGetAccessor(
377 const v8::PropertyCallbackInfo<v8::Value>& info) {
378 ApiTestFuzzer::Fuzz();
379 info.GetIsolate()->ThrowException(v8_str("g"));
383 static void ThrowingSetAccessor(Local<String> name,
385 const v8::PropertyCallbackInfo<void>& info) {
386 info.GetIsolate()->ThrowException(value);
390 THREADED_TEST(Regress1054726) {
392 v8::Isolate* isolate = env->GetIsolate();
393 v8::HandleScope scope(isolate);
394 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
395 obj->SetAccessor(v8_str("x"),
400 env->Global()->Set(v8_str("obj"), obj->NewInstance());
402 // Use the throwing property setter/getter in a loop to force
403 // the accessor ICs to be initialized.
404 v8::Handle<Value> result;
405 result = Script::Compile(v8_str(
407 "for (var i = 0; i < 5; i++) {"
408 " try { obj.x; } catch (e) { result += e; }"
409 "}; result"))->Run();
410 CHECK(v8_str("ggggg")->Equals(result));
412 result = Script::Compile(String::NewFromUtf8(
415 "for (var i = 0; i < 5; i++) {"
416 " try { obj.x = i; } catch (e) { result += e; }"
417 "}; result"))->Run();
418 CHECK(v8_str("01234")->Equals(result));
422 static void AllocGetter(Local<String> name,
423 const v8::PropertyCallbackInfo<v8::Value>& info) {
424 ApiTestFuzzer::Fuzz();
425 info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
431 v8::Isolate* isolate = env->GetIsolate();
432 v8::HandleScope scope(isolate);
433 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
434 obj->SetAccessor(v8_str("xxx"), AllocGetter);
435 env->Global()->Set(v8_str("obj"), obj->NewInstance());
436 Script::Compile(String::NewFromUtf8(
439 "for (var i = 0; i < 2048; i++) {"
440 " var result = obj.xxx;"
447 static void StackCheck(Local<String> name,
448 const v8::PropertyCallbackInfo<v8::Value>& info) {
449 i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
450 for (int i = 0; !iter.done(); i++) {
451 i::StackFrame* frame = iter.frame();
452 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
453 i::Code* code = frame->LookupCode();
454 CHECK(code->IsCode());
455 i::Address pc = frame->pc();
456 CHECK(code->contains(pc));
462 THREADED_TEST(StackIteration) {
464 v8::Isolate* isolate = env->GetIsolate();
465 v8::HandleScope scope(isolate);
466 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
467 i::StringStream::ClearMentionedObjectCache(
468 reinterpret_cast<i::Isolate*>(isolate));
469 obj->SetAccessor(v8_str("xxx"), StackCheck);
470 env->Global()->Set(v8_str("obj"), obj->NewInstance());
471 Script::Compile(String::NewFromUtf8(
476 "for (var i = 0; i < 100; i++) {"
482 static void AllocateHandles(Local<String> name,
483 const v8::PropertyCallbackInfo<v8::Value>& info) {
484 for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
485 v8::Local<v8::Value>::New(info.GetIsolate(), name);
487 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
491 THREADED_TEST(HandleScopeSegment) {
492 // Check that we can return values past popping of handle scope
495 v8::Isolate* isolate = env->GetIsolate();
496 v8::HandleScope scope(isolate);
497 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
498 obj->SetAccessor(v8_str("xxx"), AllocateHandles);
499 env->Global()->Set(v8_str("obj"), obj->NewInstance());
500 v8::Handle<v8::Value> result = Script::Compile(String::NewFromUtf8(
503 "for (var i = 0; i < 4; i++)"
506 CHECK_EQ(100, result->Int32Value());
510 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
511 v8::Handle<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
512 array->Set(0, v8_str("regress"));
513 info.GetReturnValue().Set(array);
517 void JSONStringifyGetter(Local<Name> name,
518 const v8::PropertyCallbackInfo<v8::Value>& info) {
519 info.GetReturnValue().Set(v8_str("crbug-161028"));
523 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
525 v8::Isolate* isolate = env->GetIsolate();
526 v8::HandleScope scope(isolate);
528 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
529 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
530 JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
531 env->Global()->Set(v8_str("obj"), obj->NewInstance());
532 v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
533 CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
537 static v8::Local<v8::Context> expected_current_context;
538 static v8::Local<v8::Context> expected_calling_context;
541 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
542 ApiTestFuzzer::Fuzz();
543 CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
544 CHECK(expected_calling_context == info.GetIsolate()->GetCallingContext());
548 THREADED_TEST(AccessorPropertyCrossContext) {
550 v8::Isolate* isolate = env->GetIsolate();
551 v8::HandleScope scope(isolate);
552 v8::Handle<v8::Function> fun = v8::Function::New(isolate, check_contexts);
553 LocalContext switch_context;
554 switch_context->Global()->Set(v8_str("fun"), fun);
555 v8::TryCatch try_catch;
556 expected_current_context = env.local();
557 expected_calling_context = switch_context.local();
559 "var o = Object.create(null, { n: { get:fun } });"
560 "for (var i = 0; i < 10; i++) o.n;");
561 CHECK(!try_catch.HasCaught());
565 THREADED_TEST(GlobalObjectAccessor) {
567 v8::Isolate* isolate = env->GetIsolate();
568 v8::HandleScope scope(isolate);
571 "Object.defineProperty(this.__proto__, 'x', {"
572 " get : function() { return this; },"
573 " set : function() { set_value = this; }"
575 "function getter() { return x; }"
576 "function setter() { x = 1; }"
577 "for (var i = 0; i < 4; i++) { getter(); setter(); }");
578 CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
579 CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
583 static void EmptyGetter(Local<Name> name,
584 const v8::PropertyCallbackInfo<v8::Value>& info) {
585 ApiTestFuzzer::Fuzz();
589 static void OneProperty(Local<String> name,
590 const v8::PropertyCallbackInfo<v8::Value>& info) {
591 ApiTestFuzzer::Fuzz();
592 info.GetReturnValue().Set(v8_num(1));
596 THREADED_TEST(Regress433458) {
598 v8::Isolate* isolate = env->GetIsolate();
599 v8::HandleScope scope(isolate);
600 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
601 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
602 obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
603 env->Global()->Set(v8_str("obj"), obj->NewInstance());
605 "Object.defineProperty(obj, 'prop', { writable: false });"
606 "Object.defineProperty(obj, 'prop', { writable: true });");