| 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,
|
|
|