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 "v8.h" 31 32#include "api.h" 33#include "cctest.h" 34#include "frames-inl.h" 35#include "string-stream.h" 36 37using ::v8::ObjectTemplate; 38using ::v8::Value; 39using ::v8::Context; 40using ::v8::Local; 41using ::v8::String; 42using ::v8::Script; 43using ::v8::Function; 44using ::v8::Extension; 45 46static 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 52static 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 59static 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 66THREADED_TEST(PropertyHandler) { 67 LocalContext env; 68 v8::HandleScope scope(env->GetIsolate()); 69 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 70 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property); 71 Local<v8::FunctionTemplate> getter_templ = 72 v8::FunctionTemplate::New(handle_property); 73 getter_templ->SetLength(0); 74 fun_templ-> 75 InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ); 76 fun_templ->InstanceTemplate()-> 77 SetNativeDataProperty(v8_str("instance_foo"), handle_property); 78 fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2); 79 Local<Function> fun = fun_templ->GetFunction(); 80 env->Global()->Set(v8_str("Fun"), fun); 81 Local<Script> getter; 82 Local<Script> setter; 83 // check function instance accessors 84 getter = v8_compile("var obj = new Fun(); obj.instance_foo;"); 85 CHECK_EQ(900, getter->Run()->Int32Value()); 86 setter = v8_compile("obj.instance_foo = 901;"); 87 CHECK_EQ(901, setter->Run()->Int32Value()); 88 getter = v8_compile("obj.bar;"); 89 CHECK_EQ(907, getter->Run()->Int32Value()); 90 setter = v8_compile("obj.bar = 908;"); 91 CHECK_EQ(908, setter->Run()->Int32Value()); 92 // check function static accessors 93 getter = v8_compile("Fun.object_foo;"); 94 CHECK_EQ(902, getter->Run()->Int32Value()); 95 setter = v8_compile("Fun.object_foo = 903;"); 96 CHECK_EQ(903, setter->Run()->Int32Value()); 97} 98 99 100static void GetIntValue(Local<String> property, 101 const v8::PropertyCallbackInfo<v8::Value>& info) { 102 ApiTestFuzzer::Fuzz(); 103 int* value = 104 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); 105 info.GetReturnValue().Set(v8_num(*value)); 106} 107 108 109static void SetIntValue(Local<String> property, 110 Local<Value> value, 111 const v8::PropertyCallbackInfo<void>& info) { 112 int* field = 113 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); 114 *field = value->Int32Value(); 115} 116 117int foo, bar, baz; 118 119THREADED_TEST(GlobalVariableAccess) { 120 foo = 0; 121 bar = -4; 122 baz = 10; 123 v8::HandleScope scope(CcTest::isolate()); 124 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 125 templ->InstanceTemplate()->SetAccessor( 126 v8_str("foo"), GetIntValue, SetIntValue, 127 v8::External::New(CcTest::isolate(), &foo)); 128 templ->InstanceTemplate()->SetAccessor( 129 v8_str("bar"), GetIntValue, SetIntValue, 130 v8::External::New(CcTest::isolate(), &bar)); 131 templ->InstanceTemplate()->SetAccessor( 132 v8_str("baz"), GetIntValue, SetIntValue, 133 v8::External::New(CcTest::isolate(), &baz)); 134 LocalContext env(0, templ->InstanceTemplate()); 135 v8_compile("foo = (++bar) + baz")->Run(); 136 CHECK_EQ(bar, -3); 137 CHECK_EQ(foo, 7); 138} 139 140 141static int x_register[2] = {0, 0}; 142static v8::Handle<v8::Object> x_receiver; 143static v8::Handle<v8::Object> x_holder; 144 145template<class Info> 146static void XGetter(const Info& info, int offset) { 147 ApiTestFuzzer::Fuzz(); 148 v8::Isolate* isolate = CcTest::isolate(); 149 CHECK_EQ(isolate, info.GetIsolate()); 150 CHECK_EQ(x_receiver, info.This()); 151 info.GetReturnValue().Set(v8_num(x_register[offset])); 152} 153 154 155static void XGetter(Local<String> name, 156 const v8::PropertyCallbackInfo<v8::Value>& info) { 157 CHECK_EQ(x_holder, info.Holder()); 158 XGetter(info, 0); 159} 160 161 162static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 163 CHECK_EQ(x_receiver, info.Holder()); 164 XGetter(info, 1); 165} 166 167 168template<class Info> 169static void XSetter(Local<Value> value, const Info& info, int offset) { 170 v8::Isolate* isolate = CcTest::isolate(); 171 CHECK_EQ(isolate, info.GetIsolate()); 172 CHECK_EQ(x_holder, info.This()); 173 CHECK_EQ(x_holder, info.Holder()); 174 x_register[offset] = value->Int32Value(); 175} 176 177 178static void XSetter(Local<String> name, 179 Local<Value> value, 180 const v8::PropertyCallbackInfo<void>& info) { 181 XSetter(value, info, 0); 182} 183 184 185static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 186 CHECK_EQ(1, info.Length()); 187 XSetter(info[0], info, 1); 188} 189 190 191THREADED_TEST(AccessorIC) { 192 LocalContext context; 193 v8::HandleScope scope(context->GetIsolate()); 194 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 195 obj->SetAccessor(v8_str("x0"), XGetter, XSetter); 196 obj->SetAccessorProperty(v8_str("x1"), 197 v8::FunctionTemplate::New(XGetter), 198 v8::FunctionTemplate::New(XSetter)); 199 x_holder = obj->NewInstance(); 200 context->Global()->Set(v8_str("holder"), x_holder); 201 x_receiver = v8::Object::New(); 202 context->Global()->Set(v8_str("obj"), x_receiver); 203 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun( 204 "obj.__proto__ = holder;" 205 "var result = [];" 206 "var key_0 = 'x0';" 207 "var key_1 = 'x1';" 208 "for (var i = 0; i < 10; i++) {" 209 " holder.x0 = i;" 210 " result.push(obj.x0);" 211 " holder.x1 = i;" 212 " result.push(obj.x1);" 213 " holder[key_0] = i;" 214 " result.push(obj[key_0]);" 215 " holder[key_1] = i;" 216 " result.push(obj[key_1]);" 217 "}" 218 "result")); 219 CHECK_EQ(40, array->Length()); 220 for (int i = 0; i < 40; i++) { 221 v8::Handle<Value> entry = array->Get(v8::Integer::New(i)); 222 CHECK_EQ(v8::Integer::New(i/4), entry); 223 } 224} 225 226 227static void AccessorProhibitsOverwritingGetter( 228 Local<String> name, 229 const v8::PropertyCallbackInfo<v8::Value>& info) { 230 ApiTestFuzzer::Fuzz(); 231 info.GetReturnValue().Set(true); 232} 233 234 235THREADED_TEST(AccessorProhibitsOverwriting) { 236 LocalContext context; 237 v8::HandleScope scope(context->GetIsolate()); 238 Local<ObjectTemplate> templ = ObjectTemplate::New(); 239 templ->SetAccessor(v8_str("x"), 240 AccessorProhibitsOverwritingGetter, 241 0, 242 v8::Handle<Value>(), 243 v8::PROHIBITS_OVERWRITING, 244 v8::ReadOnly); 245 Local<v8::Object> instance = templ->NewInstance(); 246 context->Global()->Set(v8_str("obj"), instance); 247 Local<Value> value = CompileRun( 248 "obj.__defineGetter__('x', function() { return false; });" 249 "obj.x"); 250 CHECK(value->BooleanValue()); 251 value = CompileRun( 252 "var setter_called = false;" 253 "obj.__defineSetter__('x', function() { setter_called = true; });" 254 "obj.x = 42;" 255 "setter_called"); 256 CHECK(!value->BooleanValue()); 257 value = CompileRun( 258 "obj2 = {};" 259 "obj2.__proto__ = obj;" 260 "obj2.__defineGetter__('x', function() { return false; });" 261 "obj2.x"); 262 CHECK(value->BooleanValue()); 263 value = CompileRun( 264 "var setter_called = false;" 265 "obj2 = {};" 266 "obj2.__proto__ = obj;" 267 "obj2.__defineSetter__('x', function() { setter_called = true; });" 268 "obj2.x = 42;" 269 "setter_called"); 270 CHECK(!value->BooleanValue()); 271} 272 273 274template <int C> 275static void HandleAllocatingGetter( 276 Local<String> name, 277 const v8::PropertyCallbackInfo<v8::Value>& info) { 278 ApiTestFuzzer::Fuzz(); 279 for (int i = 0; i < C; i++) 280 v8::String::NewFromUtf8(info.GetIsolate(), "foo"); 281 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo")); 282} 283 284 285THREADED_TEST(HandleScopePop) { 286 LocalContext context; 287 v8::HandleScope scope(context->GetIsolate()); 288 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 289 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>); 290 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>); 291 v8::Handle<v8::Object> inst = obj->NewInstance(); 292 context->Global()->Set(v8::String::NewFromUtf8(context->GetIsolate(), "obj"), 293 inst); 294 i::Isolate* isolate = CcTest::i_isolate(); 295 int count_before = i::HandleScope::NumberOfHandles(isolate); 296 { 297 v8::HandleScope scope(context->GetIsolate()); 298 CompileRun( 299 "for (var i = 0; i < 1000; i++) {" 300 " obj.one;" 301 " obj.many;" 302 "}"); 303 } 304 int count_after = i::HandleScope::NumberOfHandles(isolate); 305 CHECK_EQ(count_before, count_after); 306} 307 308static void CheckAccessorArgsCorrect( 309 Local<String> name, 310 const v8::PropertyCallbackInfo<v8::Value>& info) { 311 CHECK(info.GetIsolate() == CcTest::isolate()); 312 CHECK(info.This() == info.Holder()); 313 CHECK( 314 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data"))); 315 ApiTestFuzzer::Fuzz(); 316 CHECK(info.GetIsolate() == CcTest::isolate()); 317 CHECK(info.This() == info.Holder()); 318 CHECK( 319 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data"))); 320 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 321 CHECK(info.GetIsolate() == CcTest::isolate()); 322 CHECK(info.This() == info.Holder()); 323 CHECK( 324 info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data"))); 325 info.GetReturnValue().Set(17); 326} 327 328 329THREADED_TEST(DirectCall) { 330 LocalContext context; 331 v8::HandleScope scope(context->GetIsolate()); 332 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 333 obj->SetAccessor(v8_str("xxx"), 334 CheckAccessorArgsCorrect, 335 NULL, 336 v8::String::NewFromUtf8(context->GetIsolate(), "data")); 337 v8::Handle<v8::Object> inst = obj->NewInstance(); 338 context->Global()->Set(v8::String::NewFromUtf8(context->GetIsolate(), "obj"), 339 inst); 340 Local<Script> scr = v8::Script::Compile( 341 v8::String::NewFromUtf8(context->GetIsolate(), "obj.xxx")); 342 for (int i = 0; i < 10; i++) { 343 Local<Value> result = scr->Run(); 344 CHECK(!result.IsEmpty()); 345 CHECK_EQ(17, result->Int32Value()); 346 } 347} 348 349static void EmptyGetter(Local<String> name, 350 const v8::PropertyCallbackInfo<v8::Value>& info) { 351 CheckAccessorArgsCorrect(name, info); 352 ApiTestFuzzer::Fuzz(); 353 CheckAccessorArgsCorrect(name, info); 354 info.GetReturnValue().Set(v8::Handle<v8::Value>()); 355} 356 357 358THREADED_TEST(EmptyResult) { 359 LocalContext context; 360 v8::Isolate* isolate = context->GetIsolate(); 361 v8::HandleScope scope(isolate); 362 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 363 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, 364 v8::String::NewFromUtf8(isolate, "data")); 365 v8::Handle<v8::Object> inst = obj->NewInstance(); 366 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst); 367 Local<Script> scr = 368 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx")); 369 for (int i = 0; i < 10; i++) { 370 Local<Value> result = scr->Run(); 371 CHECK(result == v8::Undefined(isolate)); 372 } 373} 374 375 376THREADED_TEST(NoReuseRegress) { 377 // Check that the IC generated for the one test doesn't get reused 378 // for the other. 379 v8::Isolate* isolate = CcTest::isolate(); 380 v8::HandleScope scope(isolate); 381 { 382 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 383 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, 384 v8::String::NewFromUtf8(isolate, "data")); 385 LocalContext context; 386 v8::Handle<v8::Object> inst = obj->NewInstance(); 387 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst); 388 Local<Script> scr = 389 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx")); 390 for (int i = 0; i < 2; i++) { 391 Local<Value> result = scr->Run(); 392 CHECK(result == v8::Undefined(isolate)); 393 } 394 } 395 { 396 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 397 obj->SetAccessor(v8_str("xxx"), 398 CheckAccessorArgsCorrect, 399 NULL, 400 v8::String::NewFromUtf8(isolate, "data")); 401 LocalContext context; 402 v8::Handle<v8::Object> inst = obj->NewInstance(); 403 context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst); 404 Local<Script> scr = 405 v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx")); 406 for (int i = 0; i < 10; i++) { 407 Local<Value> result = scr->Run(); 408 CHECK(!result.IsEmpty()); 409 CHECK_EQ(17, result->Int32Value()); 410 } 411 } 412} 413 414static void ThrowingGetAccessor( 415 Local<String> name, 416 const v8::PropertyCallbackInfo<v8::Value>& info) { 417 ApiTestFuzzer::Fuzz(); 418 info.GetIsolate()->ThrowException(v8_str("g")); 419} 420 421 422static void ThrowingSetAccessor(Local<String> name, 423 Local<Value> value, 424 const v8::PropertyCallbackInfo<void>& info) { 425 info.GetIsolate()->ThrowException(value); 426} 427 428 429THREADED_TEST(Regress1054726) { 430 LocalContext env; 431 v8::HandleScope scope(env->GetIsolate()); 432 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 433 obj->SetAccessor(v8_str("x"), 434 ThrowingGetAccessor, 435 ThrowingSetAccessor, 436 Local<Value>()); 437 438 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 439 440 // Use the throwing property setter/getter in a loop to force 441 // the accessor ICs to be initialized. 442 v8::Handle<Value> result; 443 result = Script::Compile(v8_str( 444 "var result = '';" 445 "for (var i = 0; i < 5; i++) {" 446 " try { obj.x; } catch (e) { result += e; }" 447 "}; result"))->Run(); 448 CHECK_EQ(v8_str("ggggg"), result); 449 450 result = Script::Compile(String::NewFromUtf8( 451 env->GetIsolate(), 452 "var result = '';" 453 "for (var i = 0; i < 5; i++) {" 454 " try { obj.x = i; } catch (e) { result += e; }" 455 "}; result"))->Run(); 456 CHECK_EQ(v8_str("01234"), result); 457} 458 459 460static void AllocGetter(Local<String> name, 461 const v8::PropertyCallbackInfo<v8::Value>& info) { 462 ApiTestFuzzer::Fuzz(); 463 info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000)); 464} 465 466 467THREADED_TEST(Gc) { 468 LocalContext env; 469 v8::HandleScope scope(env->GetIsolate()); 470 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 471 obj->SetAccessor(v8_str("xxx"), AllocGetter); 472 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 473 Script::Compile(String::NewFromUtf8( 474 env->GetIsolate(), 475 "var last = [];" 476 "for (var i = 0; i < 2048; i++) {" 477 " var result = obj.xxx;" 478 " result[0] = last;" 479 " last = result;" 480 "}"))->Run(); 481} 482 483 484static void StackCheck(Local<String> name, 485 const v8::PropertyCallbackInfo<v8::Value>& info) { 486 i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate())); 487 for (int i = 0; !iter.done(); i++) { 488 i::StackFrame* frame = iter.frame(); 489 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT)); 490 i::Code* code = frame->LookupCode(); 491 CHECK(code->IsCode()); 492 i::Address pc = frame->pc(); 493 CHECK(code->contains(pc)); 494 iter.Advance(); 495 } 496} 497 498 499THREADED_TEST(StackIteration) { 500 LocalContext env; 501 v8::HandleScope scope(env->GetIsolate()); 502 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 503 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate()); 504 i::StringStream::ClearMentionedObjectCache(isolate); 505 obj->SetAccessor(v8_str("xxx"), StackCheck); 506 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 507 Script::Compile(String::NewFromUtf8( 508 env->GetIsolate(), 509 "function foo() {" 510 " return obj.xxx;" 511 "}" 512 "for (var i = 0; i < 100; i++) {" 513 " foo();" 514 "}"))->Run(); 515} 516 517 518static void AllocateHandles(Local<String> name, 519 const v8::PropertyCallbackInfo<v8::Value>& info) { 520 for (int i = 0; i < i::kHandleBlockSize + 1; i++) { 521 v8::Local<v8::Value>::New(info.GetIsolate(), name); 522 } 523 info.GetReturnValue().Set(v8::Integer::New(100)); 524} 525 526 527THREADED_TEST(HandleScopeSegment) { 528 // Check that we can return values past popping of handle scope 529 // segments. 530 LocalContext env; 531 v8::HandleScope scope(env->GetIsolate()); 532 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 533 obj->SetAccessor(v8_str("xxx"), AllocateHandles); 534 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 535 v8::Handle<v8::Value> result = Script::Compile(String::NewFromUtf8( 536 env->GetIsolate(), 537 "var result;" 538 "for (var i = 0; i < 4; i++)" 539 " result = obj.xxx;" 540 "result;"))->Run(); 541 CHECK_EQ(100, result->Int32Value()); 542} 543 544 545void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 546 v8::Handle<v8::Array> array = v8::Array::New(info.GetIsolate(), 1); 547 array->Set(0, v8_str("regress")); 548 info.GetReturnValue().Set(array); 549} 550 551 552void JSONStringifyGetter(Local<String> name, 553 const v8::PropertyCallbackInfo<v8::Value>& info) { 554 info.GetReturnValue().Set(v8_str("crbug-161028")); 555} 556 557 558THREADED_TEST(JSONStringifyNamedInterceptorObject) { 559 LocalContext env; 560 v8::HandleScope scope(env->GetIsolate()); 561 562 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 563 obj->SetNamedPropertyHandler( 564 JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator); 565 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 566 v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}"); 567 CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected)); 568} 569 570 571THREADED_TEST(AccessorPropertyCrossContext) { 572 LocalContext env; 573 v8::Isolate* isolate = env->GetIsolate(); 574 v8::HandleScope scope(isolate); 575 v8::Handle<v8::Function> fun = v8::Function::New(isolate, handle_property); 576 LocalContext switch_context; 577 switch_context->Global()->Set(v8_str("fun"), fun); 578 v8::TryCatch try_catch; 579 CompileRun( 580 "var o = Object.create(null, { n: { get:fun } });" 581 "for (var i = 0; i < 10; i++) o.n;"); 582 CHECK(!try_catch.HasCaught()); 583} 584