OLD | NEW |
1 // Copyright 2007-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2007-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 7058 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7069 " receiver = 333;" | 7069 " receiver = 333;" |
7070 " }" | 7070 " }" |
7071 "}"); | 7071 "}"); |
7072 CHECK(try_catch.HasCaught()); | 7072 CHECK(try_catch.HasCaught()); |
7073 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), | 7073 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), |
7074 try_catch.Exception()->ToString()); | 7074 try_catch.Exception()->ToString()); |
7075 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); | 7075 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); |
7076 } | 7076 } |
7077 | 7077 |
7078 | 7078 |
| 7079 v8::Handle<Value> keyed_call_ic_function; |
| 7080 |
| 7081 static v8::Handle<Value> InterceptorKeyedCallICGetter( |
| 7082 Local<String> name, const AccessorInfo& info) { |
| 7083 ApiTestFuzzer::Fuzz(); |
| 7084 if (v8_str("x")->Equals(name)) { |
| 7085 return keyed_call_ic_function; |
| 7086 } |
| 7087 return v8::Handle<Value>(); |
| 7088 } |
| 7089 |
| 7090 |
| 7091 // Test the case when we stored cacheable lookup into |
| 7092 // a stub, but the function name changed (to another cacheable function). |
| 7093 THREADED_TEST(InterceptorKeyedCallICKeyChange1) { |
| 7094 v8::HandleScope scope; |
| 7095 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); |
| 7096 templ->SetNamedPropertyHandler(NoBlockGetterX); |
| 7097 LocalContext context; |
| 7098 context->Global()->Set(v8_str("o"), templ->NewInstance()); |
| 7099 v8::Handle<Value> value = CompileRun( |
| 7100 "proto = new Object();" |
| 7101 "proto.y = function(x) { return x + 1; };" |
| 7102 "proto.z = function(x) { return x - 1; };" |
| 7103 "o.__proto__ = proto;" |
| 7104 "var result = 0;" |
| 7105 "var method = 'y';" |
| 7106 "for (var i = 0; i < 10; i++) {" |
| 7107 " if (i == 5) { method = 'z'; };" |
| 7108 " result += o[method](41);" |
| 7109 "}"); |
| 7110 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7111 } |
| 7112 |
| 7113 |
| 7114 // Test the case when we stored cacheable lookup into |
| 7115 // a stub, but the function name changed (and the new function is present |
| 7116 // both before and after the interceptor in the prototype chain). |
| 7117 THREADED_TEST(InterceptorKeyedCallICKeyChange2) { |
| 7118 v8::HandleScope scope; |
| 7119 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); |
| 7120 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); |
| 7121 LocalContext context; |
| 7122 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); |
| 7123 keyed_call_ic_function = |
| 7124 v8_compile("function f(x) { return x - 1; }; f")->Run(); |
| 7125 v8::Handle<Value> value = CompileRun( |
| 7126 "o = new Object();" |
| 7127 "proto2 = new Object();" |
| 7128 "o.y = function(x) { return x + 1; };" |
| 7129 "proto2.y = function(x) { return x + 2; };" |
| 7130 "o.__proto__ = proto1;" |
| 7131 "proto1.__proto__ = proto2;" |
| 7132 "var result = 0;" |
| 7133 "var method = 'x';" |
| 7134 "for (var i = 0; i < 10; i++) {" |
| 7135 " if (i == 5) { method = 'y'; };" |
| 7136 " result += o[method](41);" |
| 7137 "}"); |
| 7138 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7139 } |
| 7140 |
| 7141 |
| 7142 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit |
| 7143 // on the global object. |
| 7144 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { |
| 7145 v8::HandleScope scope; |
| 7146 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); |
| 7147 templ->SetNamedPropertyHandler(NoBlockGetterX); |
| 7148 LocalContext context; |
| 7149 context->Global()->Set(v8_str("o"), templ->NewInstance()); |
| 7150 v8::Handle<Value> value = CompileRun( |
| 7151 "function inc(x) { return x + 1; };" |
| 7152 "inc(1);" |
| 7153 "function dec(x) { return x - 1; };" |
| 7154 "dec(1);" |
| 7155 "o.__proto__ = this;" |
| 7156 "this.__proto__.x = inc;" |
| 7157 "this.__proto__.y = dec;" |
| 7158 "var result = 0;" |
| 7159 "var method = 'x';" |
| 7160 "for (var i = 0; i < 10; i++) {" |
| 7161 " if (i == 5) { method = 'y'; };" |
| 7162 " result += o[method](41);" |
| 7163 "}"); |
| 7164 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7165 } |
| 7166 |
| 7167 |
| 7168 // Test the case when actual function to call sits on global object. |
| 7169 THREADED_TEST(InterceptorKeyedCallICFromGlobal) { |
| 7170 v8::HandleScope scope; |
| 7171 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); |
| 7172 templ_o->SetNamedPropertyHandler(NoBlockGetterX); |
| 7173 LocalContext context; |
| 7174 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); |
| 7175 |
| 7176 v8::Handle<Value> value = CompileRun( |
| 7177 "function len(x) { return x.length; };" |
| 7178 "o.__proto__ = this;" |
| 7179 "var m = 'parseFloat';" |
| 7180 "var result = 0;" |
| 7181 "for (var i = 0; i < 10; i++) {" |
| 7182 " if (i == 5) {" |
| 7183 " m = 'len';" |
| 7184 " saved_result = result;" |
| 7185 " };" |
| 7186 " result = o[m]('239');" |
| 7187 "}"); |
| 7188 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7189 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); |
| 7190 } |
| 7191 |
| 7192 // Test the map transition before the interceptor. |
| 7193 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { |
| 7194 v8::HandleScope scope; |
| 7195 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); |
| 7196 templ_o->SetNamedPropertyHandler(NoBlockGetterX); |
| 7197 LocalContext context; |
| 7198 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); |
| 7199 |
| 7200 v8::Handle<Value> value = CompileRun( |
| 7201 "var o = new Object();" |
| 7202 "o.__proto__ = proto;" |
| 7203 "o.method = function(x) { return x + 1; };" |
| 7204 "var m = 'method';" |
| 7205 "var result = 0;" |
| 7206 "for (var i = 0; i < 10; i++) {" |
| 7207 " if (i == 5) { o.method = function(x) { return x - 1; }; };" |
| 7208 " result += o[m](41);" |
| 7209 "}"); |
| 7210 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7211 } |
| 7212 |
| 7213 |
| 7214 // Test the map transition after the interceptor. |
| 7215 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { |
| 7216 v8::HandleScope scope; |
| 7217 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); |
| 7218 templ_o->SetNamedPropertyHandler(NoBlockGetterX); |
| 7219 LocalContext context; |
| 7220 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); |
| 7221 |
| 7222 v8::Handle<Value> value = CompileRun( |
| 7223 "var proto = new Object();" |
| 7224 "o.__proto__ = proto;" |
| 7225 "proto.method = function(x) { return x + 1; };" |
| 7226 "var m = 'method';" |
| 7227 "var result = 0;" |
| 7228 "for (var i = 0; i < 10; i++) {" |
| 7229 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" |
| 7230 " result += o[m](41);" |
| 7231 "}"); |
| 7232 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); |
| 7233 } |
| 7234 |
| 7235 |
7079 static int interceptor_call_count = 0; | 7236 static int interceptor_call_count = 0; |
7080 | 7237 |
7081 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name, | 7238 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name, |
7082 const AccessorInfo& info) { | 7239 const AccessorInfo& info) { |
7083 ApiTestFuzzer::Fuzz(); | 7240 ApiTestFuzzer::Fuzz(); |
7084 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { | 7241 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { |
7085 return call_ic_function2; | 7242 return call_ic_function2; |
7086 } | 7243 } |
7087 return v8::Handle<Value>(); | 7244 return v8::Handle<Value>(); |
7088 } | 7245 } |
(...skipping 3530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10619 const char* code = | 10776 const char* code = |
10620 "(function() {" | 10777 "(function() {" |
10621 " for (var i = 0; i < 2*16; i++) {" | 10778 " for (var i = 0; i < 2*16; i++) {" |
10622 " %_GetFromCache(0, 'a' + i);" | 10779 " %_GetFromCache(0, 'a' + i);" |
10623 " };" | 10780 " };" |
10624 " return 'PASSED';" | 10781 " return 'PASSED';" |
10625 "})()"; | 10782 "})()"; |
10626 v8::internal::Heap::ClearJSFunctionResultCaches(); | 10783 v8::internal::Heap::ClearJSFunctionResultCaches(); |
10627 ExpectString(code, "PASSED"); | 10784 ExpectString(code, "PASSED"); |
10628 } | 10785 } |
OLD | NEW |