| Index: test/cctest/test-api.cc
 | 
| ===================================================================
 | 
| --- test/cctest/test-api.cc	(revision 4791)
 | 
| +++ test/cctest/test-api.cc	(working copy)
 | 
| @@ -7076,6 +7076,163 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +v8::Handle<Value> keyed_call_ic_function;
 | 
| +
 | 
| +static v8::Handle<Value> InterceptorKeyedCallICGetter(
 | 
| +    Local<String> name, const AccessorInfo& info) {
 | 
| +  ApiTestFuzzer::Fuzz();
 | 
| +  if (v8_str("x")->Equals(name)) {
 | 
| +    return keyed_call_ic_function;
 | 
| +  }
 | 
| +  return v8::Handle<Value>();
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Test the case when we stored cacheable lookup into
 | 
| +// a stub, but the function name changed (to another cacheable function).
 | 
| +THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 | 
| +  templ->SetNamedPropertyHandler(NoBlockGetterX);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("o"), templ->NewInstance());
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "proto = new Object();"
 | 
| +    "proto.y = function(x) { return x + 1; };"
 | 
| +    "proto.z = function(x) { return x - 1; };"
 | 
| +    "o.__proto__ = proto;"
 | 
| +    "var result = 0;"
 | 
| +    "var method = 'y';"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) { method = 'z'; };"
 | 
| +    "  result += o[method](41);"
 | 
| +    "}");
 | 
| +  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Test the case when we stored cacheable lookup into
 | 
| +// a stub, but the function name changed (and the new function is present
 | 
| +// both before and after the interceptor in the prototype chain).
 | 
| +THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 | 
| +  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("proto1"), templ->NewInstance());
 | 
| +  keyed_call_ic_function =
 | 
| +      v8_compile("function f(x) { return x - 1; }; f")->Run();
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "o = new Object();"
 | 
| +    "proto2 = new Object();"
 | 
| +    "o.y = function(x) { return x + 1; };"
 | 
| +    "proto2.y = function(x) { return x + 2; };"
 | 
| +    "o.__proto__ = proto1;"
 | 
| +    "proto1.__proto__ = proto2;"
 | 
| +    "var result = 0;"
 | 
| +    "var method = 'x';"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) { method = 'y'; };"
 | 
| +    "  result += o[method](41);"
 | 
| +    "}");
 | 
| +  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
 | 
| +// on the global object.
 | 
| +THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
 | 
| +  templ->SetNamedPropertyHandler(NoBlockGetterX);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("o"), templ->NewInstance());
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "function inc(x) { return x + 1; };"
 | 
| +    "inc(1);"
 | 
| +    "function dec(x) { return x - 1; };"
 | 
| +    "dec(1);"
 | 
| +    "o.__proto__ = this;"
 | 
| +    "this.__proto__.x = inc;"
 | 
| +    "this.__proto__.y = dec;"
 | 
| +    "var result = 0;"
 | 
| +    "var method = 'x';"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) { method = 'y'; };"
 | 
| +    "  result += o[method](41);"
 | 
| +    "}");
 | 
| +  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Test the case when actual function to call sits on global object.
 | 
| +THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 | 
| +  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 | 
| +
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "function len(x) { return x.length; };"
 | 
| +    "o.__proto__ = this;"
 | 
| +    "var m = 'parseFloat';"
 | 
| +    "var result = 0;"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) {"
 | 
| +    "    m = 'len';"
 | 
| +    "    saved_result = result;"
 | 
| +    "  };"
 | 
| +    "  result = o[m]('239');"
 | 
| +    "}");
 | 
| +  CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +  CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +// Test the map transition before the interceptor.
 | 
| +THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 | 
| +  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
 | 
| +
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "var o = new Object();"
 | 
| +    "o.__proto__ = proto;"
 | 
| +    "o.method = function(x) { return x + 1; };"
 | 
| +    "var m = 'method';"
 | 
| +    "var result = 0;"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
 | 
| +    "  result += o[m](41);"
 | 
| +    "}");
 | 
| +  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Test the map transition after the interceptor.
 | 
| +THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
 | 
| +  v8::HandleScope scope;
 | 
| +  v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
 | 
| +  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
 | 
| +  LocalContext context;
 | 
| +  context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 | 
| +
 | 
| +  v8::Handle<Value> value = CompileRun(
 | 
| +    "var proto = new Object();"
 | 
| +    "o.__proto__ = proto;"
 | 
| +    "proto.method = function(x) { return x + 1; };"
 | 
| +    "var m = 'method';"
 | 
| +    "var result = 0;"
 | 
| +    "for (var i = 0; i < 10; i++) {"
 | 
| +    "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
 | 
| +    "  result += o[m](41);"
 | 
| +    "}");
 | 
| +  CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
 | 
| +}
 | 
| +
 | 
| +
 | 
|  static int interceptor_call_count = 0;
 | 
|  
 | 
|  static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
 | 
| 
 |