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.
34 #include "frames-inl.h"
35 #include "string-stream.h"
37 using ::v8::ObjectTemplate;
44 using ::v8::Extension;
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));
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));
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));
66 THREADED_TEST(PropertyHandler) {
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);
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();
81 env->Global()->Set(v8_str("Fun"), fun);
84 // check function instance accessors
85 getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
86 CHECK_EQ(900, getter->Run()->Int32Value());
87 setter = v8_compile("obj.instance_foo = 901;");
88 CHECK_EQ(901, setter->Run()->Int32Value());
89 getter = v8_compile("obj.bar;");
90 CHECK_EQ(907, getter->Run()->Int32Value());
91 setter = v8_compile("obj.bar = 908;");
92 CHECK_EQ(908, setter->Run()->Int32Value());
93 // check function static accessors
94 getter = v8_compile("Fun.object_foo;");
95 CHECK_EQ(902, getter->Run()->Int32Value());
96 setter = v8_compile("Fun.object_foo = 903;");
97 CHECK_EQ(903, setter->Run()->Int32Value());
101 static void GetIntValue(Local<String> property,
102 const v8::PropertyCallbackInfo<v8::Value>& info) {
103 ApiTestFuzzer::Fuzz();
105 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
106 info.GetReturnValue().Set(v8_num(*value));
110 static void SetIntValue(Local<String> property,
112 const v8::PropertyCallbackInfo<void>& info) {
114 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
115 *field = value->Int32Value();
120 THREADED_TEST(GlobalVariableAccess) {
124 v8::Isolate* isolate = CcTest::isolate();
125 v8::HandleScope scope(isolate);
126 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
127 templ->InstanceTemplate()->SetAccessor(
128 v8_str("foo"), GetIntValue, SetIntValue,
129 v8::External::New(isolate, &foo));
130 templ->InstanceTemplate()->SetAccessor(
131 v8_str("bar"), GetIntValue, SetIntValue,
132 v8::External::New(isolate, &bar));
133 templ->InstanceTemplate()->SetAccessor(
134 v8_str("baz"), GetIntValue, SetIntValue,
135 v8::External::New(isolate, &baz));
136 LocalContext env(0, templ->InstanceTemplate());
137 v8_compile("foo = (++bar) + baz")->Run();
143 static int x_register[2] = {0, 0};
144 static v8::Handle<v8::Object> x_receiver;
145 static v8::Handle<v8::Object> x_holder;
148 static void XGetter(const Info& info, int offset) {
149 ApiTestFuzzer::Fuzz();
150 v8::Isolate* isolate = CcTest::isolate();
151 CHECK_EQ(isolate, info.GetIsolate());
152 CHECK_EQ(x_receiver, info.This());
153 info.GetReturnValue().Set(v8_num(x_register[offset]));
157 static void XGetter(Local<String> name,
158 const v8::PropertyCallbackInfo<v8::Value>& info) {
159 CHECK_EQ(x_holder, info.Holder());
164 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
165 CHECK_EQ(x_receiver, info.Holder());
171 static void XSetter(Local<Value> value, const Info& info, int offset) {
172 v8::Isolate* isolate = CcTest::isolate();
173 CHECK_EQ(isolate, info.GetIsolate());
174 CHECK_EQ(x_holder, info.This());
175 CHECK_EQ(x_holder, info.Holder());
176 x_register[offset] = value->Int32Value();
180 static void XSetter(Local<String> name,
182 const v8::PropertyCallbackInfo<void>& info) {
183 XSetter(value, info, 0);
187 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
188 CHECK_EQ(1, info.Length());
189 XSetter(info[0], info, 1);
193 THREADED_TEST(AccessorIC) {
194 LocalContext context;
195 v8::Isolate* isolate = context->GetIsolate();
196 v8::HandleScope scope(isolate);
197 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
198 obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
199 obj->SetAccessorProperty(v8_str("x1"),
200 v8::FunctionTemplate::New(isolate, XGetter),
201 v8::FunctionTemplate::New(isolate, XSetter));
202 x_holder = obj->NewInstance();
203 context->Global()->Set(v8_str("holder"), x_holder);
204 x_receiver = v8::Object::New(isolate);
205 context->Global()->Set(v8_str("obj"), x_receiver);
206 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
207 "obj.__proto__ = holder;"
211 "for (var j = 0; j < 10; j++) {"
214 " result.push(obj.x0);"
215 " holder.x1 = i + 1;"
216 " result.push(obj.x1);"
217 " holder[key_0] = i + 2;"
218 " result.push(obj[key_0]);"
219 " holder[key_1] = i + 3;"
220 " result.push(obj[key_1]);"
223 CHECK_EQ(40, array->Length());
224 for (int i = 0; i < 40; i++) {
225 v8::Handle<Value> entry = array->Get(v8::Integer::New(isolate, i));
226 CHECK_EQ(v8::Integer::New(isolate, i), entry);
231 static void AccessorProhibitsOverwritingGetter(
233 const v8::PropertyCallbackInfo<v8::Value>& info) {
234 ApiTestFuzzer::Fuzz();
235 info.GetReturnValue().Set(true);
239 THREADED_TEST(AccessorProhibitsOverwriting) {
240 LocalContext context;
241 v8::Isolate* isolate = context->GetIsolate();
242 v8::HandleScope scope(isolate);
243 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
244 templ->SetAccessor(v8_str("x"),
245 AccessorProhibitsOverwritingGetter,
248 v8::PROHIBITS_OVERWRITING,
250 Local<v8::Object> instance = templ->NewInstance();
251 context->Global()->Set(v8_str("obj"), instance);
252 Local<Value> value = CompileRun(
253 "obj.__defineGetter__('x', function() { return false; });"
255 CHECK(value->BooleanValue());
257 "var setter_called = false;"
258 "obj.__defineSetter__('x', function() { setter_called = true; });"
261 CHECK(!value->BooleanValue());
264 "obj2.__proto__ = obj;"
265 "obj2.__defineGetter__('x', function() { return false; });"
267 CHECK(value->BooleanValue());
269 "var setter_called = false;"
271 "obj2.__proto__ = obj;"
272 "obj2.__defineSetter__('x', function() { setter_called = true; });"
275 CHECK(!value->BooleanValue());
280 static void HandleAllocatingGetter(
282 const v8::PropertyCallbackInfo<v8::Value>& info) {
283 ApiTestFuzzer::Fuzz();
284 for (int i = 0; i < C; i++)
285 v8::String::NewFromUtf8(info.GetIsolate(), "foo");
286 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo"));
290 THREADED_TEST(HandleScopePop) {
291 LocalContext context;
292 v8::Isolate* isolate = context->GetIsolate();
293 v8::HandleScope scope(isolate);
294 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
295 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
296 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
297 v8::Handle<v8::Object> inst = obj->NewInstance();
298 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
300 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
302 v8::HandleScope scope(isolate);
304 "for (var i = 0; i < 1000; i++) {"
310 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
311 CHECK_EQ(count_before, count_after);
314 static void CheckAccessorArgsCorrect(
316 const v8::PropertyCallbackInfo<v8::Value>& info) {
317 CHECK(info.GetIsolate() == CcTest::isolate());
318 CHECK(info.This() == info.Holder());
320 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
321 ApiTestFuzzer::Fuzz();
322 CHECK(info.GetIsolate() == CcTest::isolate());
323 CHECK(info.This() == info.Holder());
325 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
326 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
327 CHECK(info.GetIsolate() == CcTest::isolate());
328 CHECK(info.This() == info.Holder());
330 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
331 info.GetReturnValue().Set(17);
335 THREADED_TEST(DirectCall) {
336 LocalContext context;
337 v8::Isolate* isolate = context->GetIsolate();
338 v8::HandleScope scope(isolate);
339 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
340 obj->SetAccessor(v8_str("xxx"),
341 CheckAccessorArgsCorrect,
343 v8::String::NewFromUtf8(isolate, "data"));
344 v8::Handle<v8::Object> inst = obj->NewInstance();
345 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"),
347 Local<Script> scr = v8::Script::Compile(
348 v8::String::NewFromUtf8(isolate, "obj.xxx"));
349 for (int i = 0; i < 10; i++) {
350 Local<Value> result = scr->Run();
351 CHECK(!result.IsEmpty());
352 CHECK_EQ(17, result->Int32Value());
356 static void EmptyGetter(Local<String> name,
357 const v8::PropertyCallbackInfo<v8::Value>& info) {
358 CheckAccessorArgsCorrect(name, info);
359 ApiTestFuzzer::Fuzz();
360 CheckAccessorArgsCorrect(name, info);
361 info.GetReturnValue().Set(v8::Handle<v8::Value>());
365 THREADED_TEST(EmptyResult) {
366 LocalContext context;
367 v8::Isolate* isolate = context->GetIsolate();
368 v8::HandleScope scope(isolate);
369 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
370 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
371 v8::String::NewFromUtf8(isolate, "data"));
372 v8::Handle<v8::Object> inst = obj->NewInstance();
373 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
375 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
376 for (int i = 0; i < 10; i++) {
377 Local<Value> result = scr->Run();
378 CHECK(result == v8::Undefined(isolate));
383 THREADED_TEST(NoReuseRegress) {
384 // Check that the IC generated for the one test doesn't get reused
386 v8::Isolate* isolate = CcTest::isolate();
387 v8::HandleScope scope(isolate);
389 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
390 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
391 v8::String::NewFromUtf8(isolate, "data"));
392 LocalContext context;
393 v8::Handle<v8::Object> inst = obj->NewInstance();
394 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
396 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
397 for (int i = 0; i < 2; i++) {
398 Local<Value> result = scr->Run();
399 CHECK(result == v8::Undefined(isolate));
403 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
404 obj->SetAccessor(v8_str("xxx"),
405 CheckAccessorArgsCorrect,
407 v8::String::NewFromUtf8(isolate, "data"));
408 LocalContext context;
409 v8::Handle<v8::Object> inst = obj->NewInstance();
410 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
412 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
413 for (int i = 0; i < 10; i++) {
414 Local<Value> result = scr->Run();
415 CHECK(!result.IsEmpty());
416 CHECK_EQ(17, result->Int32Value());
421 static void ThrowingGetAccessor(
423 const v8::PropertyCallbackInfo<v8::Value>& info) {
424 ApiTestFuzzer::Fuzz();
425 info.GetIsolate()->ThrowException(v8_str("g"));
429 static void ThrowingSetAccessor(Local<String> name,
431 const v8::PropertyCallbackInfo<void>& info) {
432 info.GetIsolate()->ThrowException(value);
436 THREADED_TEST(Regress1054726) {
438 v8::Isolate* isolate = env->GetIsolate();
439 v8::HandleScope scope(isolate);
440 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
441 obj->SetAccessor(v8_str("x"),
446 env->Global()->Set(v8_str("obj"), obj->NewInstance());
448 // Use the throwing property setter/getter in a loop to force
449 // the accessor ICs to be initialized.
450 v8::Handle<Value> result;
451 result = Script::Compile(v8_str(
453 "for (var i = 0; i < 5; i++) {"
454 " try { obj.x; } catch (e) { result += e; }"
455 "}; result"))->Run();
456 CHECK_EQ(v8_str("ggggg"), result);
458 result = Script::Compile(String::NewFromUtf8(
461 "for (var i = 0; i < 5; i++) {"
462 " try { obj.x = i; } catch (e) { result += e; }"
463 "}; result"))->Run();
464 CHECK_EQ(v8_str("01234"), result);
468 static void AllocGetter(Local<String> name,
469 const v8::PropertyCallbackInfo<v8::Value>& info) {
470 ApiTestFuzzer::Fuzz();
471 info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
477 v8::Isolate* isolate = env->GetIsolate();
478 v8::HandleScope scope(isolate);
479 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
480 obj->SetAccessor(v8_str("xxx"), AllocGetter);
481 env->Global()->Set(v8_str("obj"), obj->NewInstance());
482 Script::Compile(String::NewFromUtf8(
485 "for (var i = 0; i < 2048; i++) {"
486 " var result = obj.xxx;"
493 static void StackCheck(Local<String> name,
494 const v8::PropertyCallbackInfo<v8::Value>& info) {
495 i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
496 for (int i = 0; !iter.done(); i++) {
497 i::StackFrame* frame = iter.frame();
498 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
499 i::Code* code = frame->LookupCode();
500 CHECK(code->IsCode());
501 i::Address pc = frame->pc();
502 CHECK(code->contains(pc));
508 THREADED_TEST(StackIteration) {
510 v8::Isolate* isolate = env->GetIsolate();
511 v8::HandleScope scope(isolate);
512 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
513 i::StringStream::ClearMentionedObjectCache(
514 reinterpret_cast<i::Isolate*>(isolate));
515 obj->SetAccessor(v8_str("xxx"), StackCheck);
516 env->Global()->Set(v8_str("obj"), obj->NewInstance());
517 Script::Compile(String::NewFromUtf8(
522 "for (var i = 0; i < 100; i++) {"
528 static void AllocateHandles(Local<String> name,
529 const v8::PropertyCallbackInfo<v8::Value>& info) {
530 for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
531 v8::Local<v8::Value>::New(info.GetIsolate(), name);
533 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
537 THREADED_TEST(HandleScopeSegment) {
538 // Check that we can return values past popping of handle scope
541 v8::Isolate* isolate = env->GetIsolate();
542 v8::HandleScope scope(isolate);
543 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
544 obj->SetAccessor(v8_str("xxx"), AllocateHandles);
545 env->Global()->Set(v8_str("obj"), obj->NewInstance());
546 v8::Handle<v8::Value> result = Script::Compile(String::NewFromUtf8(
549 "for (var i = 0; i < 4; i++)"
552 CHECK_EQ(100, result->Int32Value());
556 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
557 v8::Handle<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
558 array->Set(0, v8_str("regress"));
559 info.GetReturnValue().Set(array);
563 void JSONStringifyGetter(Local<String> name,
564 const v8::PropertyCallbackInfo<v8::Value>& info) {
565 info.GetReturnValue().Set(v8_str("crbug-161028"));
569 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
571 v8::Isolate* isolate = env->GetIsolate();
572 v8::HandleScope scope(isolate);
574 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
575 obj->SetNamedPropertyHandler(
576 JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
577 env->Global()->Set(v8_str("obj"), obj->NewInstance());
578 v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
579 CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
583 static v8::Local<v8::Context> expected_current_context;
584 static v8::Local<v8::Context> expected_calling_context;
587 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
588 ApiTestFuzzer::Fuzz();
589 CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
590 CHECK(expected_calling_context == info.GetIsolate()->GetCallingContext());
594 THREADED_TEST(AccessorPropertyCrossContext) {
596 v8::Isolate* isolate = env->GetIsolate();
597 v8::HandleScope scope(isolate);
598 v8::Handle<v8::Function> fun = v8::Function::New(isolate, check_contexts);
599 LocalContext switch_context;
600 switch_context->Global()->Set(v8_str("fun"), fun);
601 v8::TryCatch try_catch;
602 expected_current_context = env.local();
603 expected_calling_context = switch_context.local();
605 "var o = Object.create(null, { n: { get:fun } });"
606 "for (var i = 0; i < 10; i++) o.n;");
607 CHECK(!try_catch.HasCaught());
611 THREADED_TEST(GlobalObjectAccessor) {
613 v8::Isolate* isolate = env->GetIsolate();
614 v8::HandleScope scope(isolate);
617 "Object.defineProperty(this.__proto__, 'x', {"
618 " get : function() { return this; },"
619 " set : function() { set_value = this; }"
621 "function getter() { return x; }"
622 "function setter() { x = 1; }"
623 "for (var i = 0; i < 4; i++) { getter(); setter(); }");
624 CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
625 CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());