blob: af1f3a12a28ca72543b1468bd38836f7e4b19f4a [file] [log] [blame]
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 "v8.h"
29
30#include "api.h"
31#include "arguments.h"
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000032#include "ast.h"
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000033#include "code-stubs.h"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000034#include "cpu-profiler.h"
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000035#include "gdb-jit.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "ic-inl.h"
37#include "stub-cache.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
43// -----------------------------------------------------------------------
44// StubCache implementation.
45
46
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000047StubCache::StubCache(Isolate* isolate)
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000048 : isolate_(isolate) { }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
ulan@chromium.org812308e2012-02-29 15:58:45 +000051void StubCache::Initialize() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052 ASSERT(IsPowerOf2(kPrimaryTableSize));
53 ASSERT(IsPowerOf2(kSecondaryTableSize));
ulan@chromium.org812308e2012-02-29 15:58:45 +000054 Clear();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055}
56
57
ulan@chromium.org750145a2013-03-07 15:14:13 +000058Code* StubCache::Set(Name* name, Map* map, Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059 // Get the flags from the code.
60 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
61
62 // Validate that the name does not move on scavenge, and that we
ulan@chromium.org750145a2013-03-07 15:14:13 +000063 // can use identity checks instead of structural equality checks.
lrn@chromium.org7516f052011-03-30 08:52:27 +000064 ASSERT(!heap()->InNewSpace(name));
ulan@chromium.org750145a2013-03-07 15:14:13 +000065 ASSERT(name->IsUniqueName());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67 // The state bits are not important to the hash function because
68 // the stub cache only contains monomorphic stubs. Make sure that
69 // the bits are the least significant so they will be the ones
70 // masked out.
kasper.lund7276f142008-07-30 08:49:36 +000071 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000072 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
74 // Make sure that the code type is not included in the hash.
75 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
76
77 // Compute the primary entry.
78 int primary_offset = PrimaryOffset(name, flags, map);
79 Entry* primary = entry(primary_, primary_offset);
ulan@chromium.org812308e2012-02-29 15:58:45 +000080 Code* old_code = primary->value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081
82 // If the primary entry has useful data in it, we retire it to the
83 // secondary cache before overwriting it.
ulan@chromium.org812308e2012-02-29 15:58:45 +000084 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
85 Map* old_map = primary->map;
86 Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
87 int seed = PrimaryOffset(primary->key, old_flags, old_map);
88 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089 Entry* secondary = entry(secondary_, secondary_offset);
90 *secondary = *primary;
91 }
92
93 // Update primary cache.
94 primary->key = name;
95 primary->value = code;
ulan@chromium.org812308e2012-02-29 15:58:45 +000096 primary->map = map;
97 isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 return code;
99}
100
101
ulan@chromium.org750145a2013-03-07 15:14:13 +0000102Handle<Code> StubCache::FindIC(Handle<Name> name,
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000103 Handle<Map> stub_holder_map,
104 Code::Kind kind,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000105 Code::ExtraICState extra_state,
106 InlineCacheHolderFlag cache_holder) {
107 Code::Flags flags = Code::ComputeMonomorphicFlags(
108 kind, extra_state, cache_holder);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000109 Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags),
110 isolate_);
111 if (probe->IsCode()) return Handle<Code>::cast(probe);
112 return Handle<Code>::null();
113}
114
115
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000116Handle<Code> StubCache::FindHandler(Handle<Name> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000117 Handle<HeapObject> stub_holder,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000118 Code::Kind kind,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000119 InlineCacheHolderFlag cache_holder,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000120 StrictModeFlag strict_mode) {
121 Code::ExtraICState extra_ic_state = Code::kNoExtraICState;
122 if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
123 extra_ic_state = Code::ComputeExtraICState(
124 STANDARD_STORE, strict_mode);
125 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000126 Code::Flags flags = Code::ComputeMonomorphicFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000127 Code::HANDLER, extra_ic_state, cache_holder, Code::NORMAL, kind);
128
129 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
danno@chromium.orgbee51992013-07-10 14:57:15 +0000130 isolate_);
131 if (probe->IsCode()) return Handle<Code>::cast(probe);
132 return Handle<Code>::null();
133}
134
135
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000136Handle<Code> StubCache::ComputeMonomorphicIC(Handle<Name> name,
137 Handle<Object> object,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000138 Handle<Code> handler,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000139 StrictModeFlag strict_mode) {
140 Code::Kind kind = handler->handler_kind();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000141 // Use the same cache holder for the IC as for the handler.
142 InlineCacheHolderFlag cache_holder =
143 Code::ExtractCacheHolderFromFlags(handler->flags());
144 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
145 isolate(), *object, cache_holder));
146 Handle<Map> stub_holder_map(stub_holder->map());
147 Handle<Code> ic = FindIC(
148 name, stub_holder_map, kind, strict_mode, cache_holder);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000149 if (!ic.is_null()) return ic;
150
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000151 Handle<Map> map(object->GetMarkerMap(isolate()));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000152 if (kind == Code::LOAD_IC) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000153 LoadStubCompiler ic_compiler(isolate(), cache_holder);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000154 ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
155 } else if (kind == Code::KEYED_LOAD_IC) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000156 KeyedLoadStubCompiler ic_compiler(isolate(), cache_holder);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000157 ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
158 } else if (kind == Code::STORE_IC) {
159 StoreStubCompiler ic_compiler(isolate(), strict_mode);
160 ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
161 } else {
162 ASSERT(kind == Code::KEYED_STORE_IC);
163 KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
164 ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
165 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000166
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000167 HeapObject::UpdateMapCodeCache(stub_holder, name, ic);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000168 return ic;
169}
170
171
ulan@chromium.org750145a2013-03-07 15:14:13 +0000172Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000173 Handle<Object> object) {
174 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
175 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
176 isolate(), *object, cache_holder));
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000177 // If no global objects are present in the prototype chain, the load
178 // nonexistent IC stub can be shared for all names for a given map
179 // and we use the empty string for the map cache in that case. If
180 // there are global objects involved, we need to check global
181 // property cells in the stub and therefore the stub will be
182 // specific to the name.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000183 Handle<Name> cache_name = factory()->empty_string();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000184 Handle<JSObject> current;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000185 Handle<Object> next = stub_holder;
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000186 Handle<JSGlobalObject> global;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000187 do {
188 current = Handle<JSObject>::cast(next);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000189 next = Handle<Object>(current->GetPrototype(), isolate_);
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000190 if (current->IsJSGlobalObject()) {
191 global = Handle<JSGlobalObject>::cast(current);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000192 cache_name = name;
193 } else if (!current->HasFastProperties()) {
194 cache_name = name;
195 }
196 } while (!next->IsNull());
197
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000198 // Compile the stub that is either shared for all names or
199 // name specific if there are global objects involved.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000200 Handle<Code> handler = FindHandler(
201 cache_name, stub_holder, Code::LOAD_IC, cache_holder);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000202 if (!handler.is_null()) return handler;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000203
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000204 LoadStubCompiler compiler(isolate_, cache_holder);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000205 handler =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000206 compiler.CompileLoadNonexistent(object, current, cache_name, global);
207 HeapObject::UpdateMapCodeCache(stub_holder, cache_name, handler);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000208 return handler;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000209}
210
211
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000212Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000213 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000214 Handle<Name> name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000215 isolate()->factory()->KeyedLoadElementMonomorphic_string();
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000216
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000217 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000218 if (probe->IsCode()) return Handle<Code>::cast(probe);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000219
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000220 KeyedLoadStubCompiler compiler(isolate());
221 Handle<Code> code = compiler.CompileLoadElement(receiver_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000222
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000223 Map::UpdateCodeCache(receiver_map, name, code);
224 return code;
225}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000226
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000227
228Handle<Code> StubCache::ComputeKeyedStoreElement(
229 Handle<Map> receiver_map,
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000230 StrictModeFlag strict_mode,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000231 KeyedAccessStoreMode store_mode) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000232 Code::ExtraICState extra_state =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000233 Code::ComputeExtraICState(store_mode, strict_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000234 Code::Flags flags = Code::ComputeMonomorphicFlags(
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000235 Code::KEYED_STORE_IC, extra_state);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000236
ulan@chromium.org750145a2013-03-07 15:14:13 +0000237 ASSERT(store_mode == STANDARD_STORE ||
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000238 store_mode == STORE_AND_GROW_NO_TRANSITION ||
239 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
240 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000241
ulan@chromium.org750145a2013-03-07 15:14:13 +0000242 Handle<String> name =
243 isolate()->factory()->KeyedStoreElementMonomorphic_string();
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000244 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
245 if (probe->IsCode()) return Handle<Code>::cast(probe);
246
ulan@chromium.org750145a2013-03-07 15:14:13 +0000247 KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000248 Handle<Code> code = compiler.CompileStoreElement(receiver_map);
249
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000250 Map::UpdateCodeCache(receiver_map, name, code);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000251 ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000252 return code;
253}
254
255
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000256#define CALL_LOGGER_TAG(kind, type) \
257 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000259Handle<Code> StubCache::ComputeCallConstant(int argc,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000260 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000261 Code::ExtraICState extra_state,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000262 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000263 Handle<Object> object,
264 Handle<JSObject> holder,
265 Handle<JSFunction> function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266 // Compute the check type and the map.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000267 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
268 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000269 isolate_, *object, cache_holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270
271 // Compute check type based on receiver/holder.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000272 CheckType check = RECEIVER_MAP_CHECK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 if (object->IsString()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000274 check = STRING_CHECK;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000275 } else if (object->IsSymbol()) {
276 check = SYMBOL_CHECK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 } else if (object->IsNumber()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000278 check = NUMBER_CHECK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279 } else if (object->IsBoolean()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000280 check = BOOLEAN_CHECK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281 }
282
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000283 if (check != RECEIVER_MAP_CHECK &&
284 !function->IsBuiltin() &&
285 function->shared()->is_classic_mode()) {
286 // Calling non-strict non-builtins with a value as the receiver
287 // requires boxing.
288 return Handle<Code>::null();
289 }
290
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000291 Code::Flags flags = Code::ComputeMonomorphicFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000292 kind, extra_state, cache_holder, Code::CONSTANT, argc);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000293 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000294 isolate_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000295 if (probe->IsCode()) return Handle<Code>::cast(probe);
296
297 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
298 Handle<Code> code =
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000299 compiler.CompileCallConstant(object, holder, name, check, function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000300 code->set_check_type(check);
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000301 ASSERT(flags == code->flags());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000302 PROFILE(isolate_,
303 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
304 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000305
306 if (CallStubCompiler::CanBeCached(function)) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000307 HeapObject::UpdateMapCodeCache(stub_holder, name, code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000308 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000309 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310}
311
312
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000313Handle<Code> StubCache::ComputeCallField(int argc,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000314 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000315 Code::ExtraICState extra_state,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000316 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000317 Handle<Object> object,
318 Handle<JSObject> holder,
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000319 PropertyIndex index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 // Compute the check type and the map.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000321 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
322 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000323 isolate_, *object, cache_holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
325 // TODO(1233596): We cannot do receiver map check for non-JS objects
326 // because they may be represented as immediates without a
327 // map. Instead, we check against the map in the holder.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000328 if (object->IsNumber() || object->IsSymbol() ||
329 object->IsBoolean() || object->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 object = holder;
331 }
332
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000333 Code::Flags flags = Code::ComputeMonomorphicFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000334 kind, extra_state, cache_holder, Code::FIELD, argc);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000335 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000336 isolate_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000337 if (probe->IsCode()) return Handle<Code>::cast(probe);
338
339 CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
340 Handle<Code> code =
341 compiler.CompileCallField(Handle<JSObject>::cast(object),
342 holder, index, name);
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000343 ASSERT(flags == code->flags());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000344 PROFILE(isolate_,
345 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
346 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000347 HeapObject::UpdateMapCodeCache(stub_holder, name, code);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000348 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349}
350
351
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000352Handle<Code> StubCache::ComputeCallInterceptor(int argc,
353 Code::Kind kind,
354 Code::ExtraICState extra_state,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000355 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000356 Handle<Object> object,
357 Handle<JSObject> holder) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 // Compute the check type and the map.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000359 InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
360 Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000361 isolate_, *object, cache_holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362
363 // TODO(1233596): We cannot do receiver map check for non-JS objects
364 // because they may be represented as immediates without a
365 // map. Instead, we check against the map in the holder.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000366 if (object->IsNumber() || object->IsSymbol() ||
367 object->IsBoolean() || object->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 object = holder;
369 }
370
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000371 Code::Flags flags = Code::ComputeMonomorphicFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000372 kind, extra_state, cache_holder, Code::INTERCEPTOR, argc);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000373 Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000374 isolate_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000375 if (probe->IsCode()) return Handle<Code>::cast(probe);
376
377 CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
378 Handle<Code> code =
379 compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
380 holder, name);
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000381 ASSERT(flags == code->flags());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000382 PROFILE(isolate(),
383 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
384 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000385 HeapObject::UpdateMapCodeCache(stub_holder, name, code);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000386 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387}
388
389
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000390Handle<Code> StubCache::ComputeCallGlobal(int argc,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000391 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000392 Code::ExtraICState extra_state,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000393 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000394 Handle<JSObject> receiver,
395 Handle<GlobalObject> holder,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000396 Handle<PropertyCell> cell,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000397 Handle<JSFunction> function) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000398 Code::Flags flags = Code::ComputeMonomorphicFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000399 kind, extra_state, OWN_MAP, Code::NORMAL, argc);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000400 Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000401 isolate_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000402 if (probe->IsCode()) return Handle<Code>::cast(probe);
403
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000404 CallStubCompiler compiler(isolate(), argc, kind, extra_state);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000405 Handle<Code> code =
406 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000407 ASSERT(flags == code->flags());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000408 PROFILE(isolate(),
409 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
410 GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000411 if (CallStubCompiler::CanBeCached(function)) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000412 HeapObject::UpdateMapCodeCache(receiver, name, code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000413 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000414 return code;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000415}
416
417
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000418static void FillCache(Isolate* isolate, Handle<Code> code) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000419 Handle<UnseededNumberDictionary> dictionary =
420 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
421 code->flags(),
422 code);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000423 isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424}
425
426
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000427Code* StubCache::FindCallInitialize(int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000428 RelocInfo::Mode mode,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000429 Code::Kind kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000430 Code::ExtraICState extra_state =
431 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
432 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000433 Code::Flags flags =
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000434 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000435 UnseededNumberDictionary* dictionary =
danno@chromium.org72204d52012-10-31 10:02:10 +0000436 isolate()->heap()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000437 int entry = dictionary->FindEntry(isolate(), flags);
438 ASSERT(entry != -1);
439 Object* code = dictionary->ValueAt(entry);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 // This might be called during the marking phase of the collector
441 // hence the unchecked cast.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000442 return reinterpret_cast<Code*>(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443}
444
445
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000446Handle<Code> StubCache::ComputeCallInitialize(int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000447 RelocInfo::Mode mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000448 Code::Kind kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000449 Code::ExtraICState extra_state =
450 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
451 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000452 Code::Flags flags =
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000453 Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000454 Handle<UnseededNumberDictionary> cache =
455 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000456 int entry = cache->FindEntry(isolate_, flags);
457 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
458
459 StubCompiler compiler(isolate_);
460 Handle<Code> code = compiler.CompileCallInitialize(flags);
461 FillCache(isolate_, code);
462 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463}
464
465
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000466Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
467 return ComputeCallInitialize(argc, mode, Code::CALL_IC);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000468}
469
470
lrn@chromium.org34e60782011-09-15 07:25:40 +0000471Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000472 return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
473 Code::KEYED_CALL_IC);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000474}
475
476
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000477Handle<Code> StubCache::ComputeCallPreMonomorphic(
danno@chromium.org40cb8782011-05-25 07:58:50 +0000478 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000479 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 Code::ExtraICState extra_state) {
481 Code::Flags flags =
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000482 Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000483 Handle<UnseededNumberDictionary> cache =
484 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000485 int entry = cache->FindEntry(isolate_, flags);
486 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
487
488 StubCompiler compiler(isolate_);
489 Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
490 FillCache(isolate_, code);
491 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492}
493
494
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000495Handle<Code> StubCache::ComputeCallNormal(int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000496 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000497 Code::ExtraICState extra_state) {
498 Code::Flags flags =
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000499 Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000500 Handle<UnseededNumberDictionary> cache =
501 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000502 int entry = cache->FindEntry(isolate_, flags);
503 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
504
505 StubCompiler compiler(isolate_);
506 Handle<Code> code = compiler.CompileCallNormal(flags);
507 FillCache(isolate_, code);
508 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000512Handle<Code> StubCache::ComputeCallArguments(int argc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000513 Code::Flags flags =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000514 Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC,
515 Code::kNoExtraICState, Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000516 Handle<UnseededNumberDictionary> cache =
517 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000518 int entry = cache->FindEntry(isolate_, flags);
519 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
520
521 StubCompiler compiler(isolate_);
522 Handle<Code> code = compiler.CompileCallArguments(flags);
523 FillCache(isolate_, code);
524 return code;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000525}
526
527
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000528Handle<Code> StubCache::ComputeCallMegamorphic(
danno@chromium.org40cb8782011-05-25 07:58:50 +0000529 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000530 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000531 Code::ExtraICState extra_state) {
532 Code::Flags flags =
533 Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000534 Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000535 Handle<UnseededNumberDictionary> cache =
536 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000537 int entry = cache->FindEntry(isolate_, flags);
538 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
539
540 StubCompiler compiler(isolate_);
541 Handle<Code> code = compiler.CompileCallMegamorphic(flags);
542 FillCache(isolate_, code);
543 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000547Handle<Code> StubCache::ComputeCallMiss(int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000548 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000549 Code::ExtraICState extra_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000550 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
551 // and monomorphic stubs are not mixed up together in the stub cache.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000552 Code::Flags flags =
553 Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000554 Code::NORMAL, argc, OWN_MAP);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000555 Handle<UnseededNumberDictionary> cache =
556 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000557 int entry = cache->FindEntry(isolate_, flags);
558 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
559
560 StubCompiler compiler(isolate_);
561 Handle<Code> code = compiler.CompileCallMiss(flags);
562 FillCache(isolate_, code);
563 return code;
564}
565
566
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000567Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000568 CompareNilICStub& stub) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000569 Handle<String> name(isolate_->heap()->empty_string());
570 if (!receiver_map->is_shared()) {
571 Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC,
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000572 stub.GetExtraICState());
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000573 if (!cached_ic.is_null()) return cached_ic;
574 }
575
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000576 Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
577 ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000578
579 if (!receiver_map->is_shared()) {
580 Map::UpdateCodeCache(receiver_map, name, ic);
581 }
582
583 return ic;
584}
585
586
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000587Handle<Code> StubCache::ComputeLoadElementPolymorphic(
588 MapHandleList* receiver_maps) {
589 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
590 Handle<PolymorphicCodeCache> cache =
591 isolate_->factory()->polymorphic_code_cache();
592 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
593 if (probe->IsCode()) return Handle<Code>::cast(probe);
594
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000595 CodeHandleList handlers(receiver_maps->length());
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000596 KeyedLoadStubCompiler compiler(isolate_);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000597 compiler.CompileElementHandlers(receiver_maps, &handlers);
598 Handle<Code> code = compiler.CompilePolymorphicIC(
599 receiver_maps, &handlers, factory()->empty_string(),
600 Code::NORMAL, ELEMENT);
601
602 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
603
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000604 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
605 return code;
606}
607
608
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000609Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
610 CodeHandleList* handlers,
611 int number_of_valid_maps,
612 Handle<Name> name,
613 StrictModeFlag strict_mode) {
614 Handle<Code> handler = handlers->at(0);
615 Code::Kind kind = handler->handler_kind();
616 Code::StubType type = number_of_valid_maps == 1 ? handler->type()
danno@chromium.orgf005df62013-04-30 16:36:45 +0000617 : Code::NORMAL;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000618 if (kind == Code::LOAD_IC) {
619 LoadStubCompiler ic_compiler(isolate_);
620 return ic_compiler.CompilePolymorphicIC(
621 receiver_maps, handlers, name, type, PROPERTY);
622 } else {
623 ASSERT(kind == Code::STORE_IC);
624 StoreStubCompiler ic_compiler(isolate_, strict_mode);
625 return ic_compiler.CompilePolymorphicIC(
626 receiver_maps, handlers, name, type, PROPERTY);
627 }
danno@chromium.orgbee51992013-07-10 14:57:15 +0000628}
629
630
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000631Handle<Code> StubCache::ComputeStoreElementPolymorphic(
632 MapHandleList* receiver_maps,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000633 KeyedAccessStoreMode store_mode,
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000634 StrictModeFlag strict_mode) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000635 ASSERT(store_mode == STANDARD_STORE ||
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000636 store_mode == STORE_AND_GROW_NO_TRANSITION ||
637 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
638 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000639 Handle<PolymorphicCodeCache> cache =
640 isolate_->factory()->polymorphic_code_cache();
ulan@chromium.org750145a2013-03-07 15:14:13 +0000641 Code::ExtraICState extra_state = Code::ComputeExtraICState(store_mode,
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000642 strict_mode);
643 Code::Flags flags =
644 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
645 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
646 if (probe->IsCode()) return Handle<Code>::cast(probe);
647
ulan@chromium.org750145a2013-03-07 15:14:13 +0000648 KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000649 Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
650 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
651 return code;
652}
653
654
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000655#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000656Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
657 Code::Kind kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000658 // Extra IC state is irrelevant for debug break ICs. They jump to
659 // the actual call ic to carry out the work.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000660 Code::Flags flags =
yangguo@chromium.org9768bf12013-01-11 14:51:07 +0000661 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000662 Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000663 Handle<UnseededNumberDictionary> cache =
664 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000665 int entry = cache->FindEntry(isolate_, flags);
666 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
667
668 StubCompiler compiler(isolate_);
669 Handle<Code> code = compiler.CompileCallDebugBreak(flags);
670 FillCache(isolate_, code);
671 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672}
673
674
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000675Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
676 Code::Kind kind) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000677 // Extra IC state is irrelevant for debug break ICs. They jump to
678 // the actual call ic to carry out the work.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000679 Code::Flags flags =
yangguo@chromium.org9768bf12013-01-11 14:51:07 +0000680 Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000681 Code::NORMAL, argc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000682 Handle<UnseededNumberDictionary> cache =
683 isolate_->factory()->non_monomorphic_cache();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000684 int entry = cache->FindEntry(isolate_, flags);
685 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
686
687 StubCompiler compiler(isolate_);
688 Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
689 FillCache(isolate_, code);
690 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000692#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693
694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695void StubCache::Clear() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000696 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 for (int i = 0; i < kPrimaryTableSize; i++) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000698 primary_[i].key = heap()->empty_string();
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000699 primary_[i].map = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000700 primary_[i].value = empty;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 }
702 for (int j = 0; j < kSecondaryTableSize; j++) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000703 secondary_[j].key = heap()->empty_string();
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000704 secondary_[j].map = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000705 secondary_[j].value = empty;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 }
707}
708
709
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000710void StubCache::CollectMatchingMaps(SmallMapList* types,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000711 Handle<Name> name,
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000712 Code::Flags flags,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000713 Handle<Context> native_context,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000714 Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000715 for (int i = 0; i < kPrimaryTableSize; i++) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000716 if (primary_[i].key == *name) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000717 Map* map = primary_[i].map;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000718 // Map can be NULL, if the stub is constant function call
719 // with a primitive receiver.
720 if (map == NULL) continue;
721
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000722 int offset = PrimaryOffset(*name, flags, map);
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000723 if (entry(primary_, offset) == &primary_[i] &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000724 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000725 types->AddMapIfMissing(Handle<Map>(map), zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000726 }
727 }
728 }
729
730 for (int i = 0; i < kSecondaryTableSize; i++) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000731 if (secondary_[i].key == *name) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000732 Map* map = secondary_[i].map;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000733 // Map can be NULL, if the stub is constant function call
734 // with a primitive receiver.
735 if (map == NULL) continue;
736
737 // Lookup in primary table and skip duplicates.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000738 int primary_offset = PrimaryOffset(*name, flags, map);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000739
740 // Lookup in secondary table and add matches.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000741 int offset = SecondaryOffset(*name, flags, primary_offset);
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000742 if (entry(secondary_, offset) == &secondary_[i] &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000743 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000744 types->AddMapIfMissing(Handle<Map>(map), zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745 }
746 }
747 }
748}
749
750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751// ------------------------------------------------------------------------
752// StubCompiler implementation.
753
754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000755RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000756 JSObject* recv = JSObject::cast(args[0]);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000757 ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]);
ager@chromium.org3b45ab52009-03-19 22:21:34 +0000758 Address setter_address = v8::ToCData<Address>(callback->setter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000759 v8::AccessorSetterCallback fun =
760 FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761 ASSERT(fun != NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000762 ASSERT(callback->IsCompatibleReceiver(recv));
ulan@chromium.org750145a2013-03-07 15:14:13 +0000763 Handle<Name> name = args.at<Name>(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 Handle<Object> value = args.at<Object>(3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000765 HandleScope scope(isolate);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000766
767 // TODO(rossberg): Support symbols in the API.
768 if (name->IsSymbol()) return *value;
769 Handle<String> str = Handle<String>::cast(name);
770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000772 PropertyCallbackArguments
773 custom_args(isolate, callback->data(), recv, recv);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000774 custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776 return *value;
777}
778
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000779
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000780/**
781 * Attempts to load a property with an interceptor (which must be present),
782 * but doesn't search the prototype chain.
783 *
784 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
785 * provide any value for the given name.
786 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000787RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000788 ASSERT(args.length() == StubCache::kInterceptorArgsLength);
789 Handle<Name> name_handle =
790 args.at<Name>(StubCache::kInterceptorArgsNameIndex);
791 Handle<InterceptorInfo> interceptor_info =
792 args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793
ulan@chromium.org750145a2013-03-07 15:14:13 +0000794 // TODO(rossberg): Support symbols in the API.
795 if (name_handle->IsSymbol())
796 return isolate->heap()->no_interceptor_result_sentinel();
797 Handle<String> name = Handle<String>::cast(name_handle);
798
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000799 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000800 v8::NamedPropertyGetterCallback getter =
801 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000802 ASSERT(getter != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000804 Handle<JSObject> receiver =
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000805 args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000806 Handle<JSObject> holder =
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000807 args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
808 PropertyCallbackArguments callback_args(
809 isolate, interceptor_info->data(), *receiver, *holder);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000810 {
811 // Use the interceptor getter.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000812 HandleScope scope(isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000813 v8::Handle<v8::Value> r =
814 callback_args.Call(getter, v8::Utils::ToLocal(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000816 if (!r.IsEmpty()) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000817 Handle<Object> result = v8::Utils::OpenHandle(*r);
818 result->VerifyApiCallResultType();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000819 return *v8::Utils::OpenHandle(*r);
820 }
821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 return isolate->heap()->no_interceptor_result_sentinel();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000824}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826
ulan@chromium.org750145a2013-03-07 15:14:13 +0000827static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828 // If the load is non-contextual, just return the undefined result.
829 // Note that both keyed and non-keyed loads may end up here, so we
830 // can't use either LoadIC or KeyedLoadIC constructors.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000831 HandleScope scope(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000832 IC ic(IC::NO_EXTRA_FRAME, isolate);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000833 ASSERT(ic.IsLoadStub());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000834 if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835
836 // Throw a reference error.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000837 Handle<Name> name_handle(name);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000838 Handle<Object> error =
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000839 isolate->factory()->NewReferenceError("not_defined",
840 HandleVector(&name_handle, 1));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000841 return isolate->Throw(*error);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000842}
843
844
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000845static Handle<Object> LoadWithInterceptor(Arguments* args,
846 PropertyAttributes* attrs) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000847 ASSERT(args->length() == StubCache::kInterceptorArgsLength);
848 Handle<Name> name_handle =
849 args->at<Name>(StubCache::kInterceptorArgsNameIndex);
850 Handle<InterceptorInfo> interceptor_info =
851 args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000852 Handle<JSObject> receiver_handle =
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000853 args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000854 Handle<JSObject> holder_handle =
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000855 args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000856
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 Isolate* isolate = receiver_handle->GetIsolate();
858
ulan@chromium.org750145a2013-03-07 15:14:13 +0000859 // TODO(rossberg): Support symbols in the API.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000860 if (name_handle->IsSymbol()) {
861 return JSObject::GetPropertyPostInterceptor(
862 holder_handle, receiver_handle, name_handle, attrs);
863 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000864 Handle<String> name = Handle<String>::cast(name_handle);
865
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000866 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000867 v8::NamedPropertyGetterCallback getter =
868 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000869 ASSERT(getter != NULL);
870
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000871 PropertyCallbackArguments callback_args(isolate,
872 interceptor_info->data(),
873 *receiver_handle,
874 *holder_handle);
ager@chromium.org3b45ab52009-03-19 22:21:34 +0000875 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 HandleScope scope(isolate);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000877 // Use the interceptor getter.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000878 v8::Handle<v8::Value> r =
879 callback_args.Call(getter, v8::Utils::ToLocal(name));
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000880 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000881 if (!r.IsEmpty()) {
882 *attrs = NONE;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000883 Handle<Object> result = v8::Utils::OpenHandle(*r);
884 result->VerifyApiCallResultType();
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000885 return scope.CloseAndEscape(result);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000886 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +0000887 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000888
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000889 Handle<Object> result = JSObject::GetPropertyPostInterceptor(
890 holder_handle, receiver_handle, name_handle, attrs);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000891 return result;
892}
893
894
895/**
896 * Loads a property with an interceptor performing post interceptor
897 * lookup if interceptor failed.
898 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000899RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000900 PropertyAttributes attr = NONE;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000901 HandleScope scope(isolate);
902 Handle<Object> result = LoadWithInterceptor(&args, &attr);
903 RETURN_IF_EMPTY_HANDLE(isolate, result);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000904
905 // If the property is present, return it.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000906 if (attr != ABSENT) return *result;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000907 return ThrowReferenceError(isolate, Name::cast(args[0]));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000908}
909
910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000911RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000912 PropertyAttributes attr;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000913 HandleScope scope(isolate);
914 Handle<Object> result = LoadWithInterceptor(&args, &attr);
915 RETURN_IF_EMPTY_HANDLE(isolate, result);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000916 // This is call IC. In this case, we simply return the undefined result which
917 // will lead to an exception when trying to invoke the result as a
918 // function.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000919 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920}
921
922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000923RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000924 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000925 ASSERT(args.length() == 4);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000926 Handle<JSObject> recv(JSObject::cast(args[0]));
927 Handle<Name> name(Name::cast(args[1]));
928 Handle<Object> value(args[2], isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000929 ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000930 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(recv->HasNamedInterceptor());
932 PropertyAttributes attr = NONE;
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000933 Handle<Object> result = JSObject::SetPropertyWithInterceptor(
934 recv, name, value, attr, strict_mode);
935 RETURN_IF_EMPTY_HANDLE(isolate, result);
936 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937}
938
939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000940RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000941 JSObject* receiver = JSObject::cast(args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000942 ASSERT(args.smi_at(1) >= 0);
943 uint32_t index = args.smi_at(1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000944 return receiver->GetElementWithInterceptor(receiver, index);
945}
946
947
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000948Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 int argc = Code::ExtractArgumentsCountFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000950 Code::Kind kind = Code::ExtractKindFromFlags(flags);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000951 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000952 if (kind == Code::CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000953 CallIC::GenerateInitialize(masm(), argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000954 } else {
955 KeyedCallIC::GenerateInitialize(masm(), argc);
956 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000957 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000958 isolate()->counters()->call_initialize_stubs()->Increment();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 PROFILE(isolate(),
960 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000961 *code, code->arguments_count()));
962 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
963 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964}
965
966
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000967Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 int argc = Code::ExtractArgumentsCountFromFlags(flags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000969 // The code of the PreMonomorphic stub is the same as the code
970 // of the Initialized stub. They just differ on the code object flags.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000971 Code::Kind kind = Code::ExtractKindFromFlags(flags);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000972 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000973 if (kind == Code::CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000974 CallIC::GenerateInitialize(masm(), argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000975 } else {
976 KeyedCallIC::GenerateInitialize(masm(), argc);
977 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000978 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000979 isolate()->counters()->call_premonomorphic_stubs()->Increment();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 PROFILE(isolate(),
981 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000982 *code, code->arguments_count()));
983 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
984 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985}
986
987
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000988Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 int argc = Code::ExtractArgumentsCountFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000990 Code::Kind kind = Code::ExtractKindFromFlags(flags);
991 if (kind == Code::CALL_IC) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000992 // Call normal is always with a explict receiver.
993 ASSERT(!CallIC::Contextual::decode(
994 Code::ExtractExtraICStateFromFlags(flags)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000995 CallIC::GenerateNormal(masm(), argc);
996 } else {
997 KeyedCallIC::GenerateNormal(masm(), argc);
998 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000999 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001000 isolate()->counters()->call_normal_stubs()->Increment();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 PROFILE(isolate(),
1002 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001003 *code, code->arguments_count()));
1004 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
1005 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001009Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 int argc = Code::ExtractArgumentsCountFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001011 Code::Kind kind = Code::ExtractKindFromFlags(flags);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001012 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001013 if (kind == Code::CALL_IC) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001014 CallIC::GenerateMegamorphic(masm(), argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001015 } else {
1016 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1017 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001018 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001019 isolate()->counters()->call_megamorphic_stubs()->Increment();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 PROFILE(isolate(),
1021 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001022 *code, code->arguments_count()));
1023 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1024 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001028Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001029 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1030 KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001031 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
whesse@chromium.org7b260152011-06-20 15:33:18 +00001032 PROFILE(isolate(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1034 CALL_MEGAMORPHIC_TAG),
1035 *code, code->arguments_count()));
1036 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1037 return code;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001038}
1039
1040
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001041Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
1042 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1043 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1044 Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1045 if (kind == Code::CALL_IC) {
1046 CallIC::GenerateMiss(masm(), argc, extra_state);
1047 } else {
1048 KeyedCallIC::GenerateMiss(masm(), argc);
1049 }
1050 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
1051 isolate()->counters()->call_megamorphic_stubs()->Increment();
1052 PROFILE(isolate(),
1053 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1054 *code, code->arguments_count()));
1055 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
1056 return code;
1057}
1058
1059
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001060#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001061Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001062 Debug::GenerateCallICDebugBreak(masm());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 PROFILE(isolate(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001065 CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1066 CALL_DEBUG_BREAK_TAG),
1067 *code, code->arguments_count()));
1068 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069}
1070
1071
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001072Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1073 // Use the same code for the the step in preparations as we do for the
1074 // miss case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 int argc = Code::ExtractArgumentsCountFromFlags(flags);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001076 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1077 if (kind == Code::CALL_IC) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001078 // For the debugger extra ic state is irrelevant.
1079 CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001080 } else {
1081 KeyedCallIC::GenerateMiss(masm(), argc);
1082 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001083 Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001084 PROFILE(isolate(),
1085 CodeCreateEvent(
1086 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001087 *code,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 code->arguments_count()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001089 return code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001091#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001093#undef CALL_LOGGER_TAG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001095
1096Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001097 const char* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001098 // Create code object in the heap.
1099 CodeDesc desc;
1100 masm_.GetCode(&desc);
1101 Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
1102#ifdef ENABLE_DISASSEMBLER
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001103 if (FLAG_print_code_stubs) code->Disassemble(name);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001104#endif
1105 return code;
1106}
1107
1108
1109Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001110 Handle<Name> name) {
1111 return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
1112 ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString())
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001113 : GetCodeWithFlags(flags, NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001114}
1115
1116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001117void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001118 Handle<Name> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001119 LookupResult* lookup) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001120 holder->LocalLookupRealNamedProperty(*name, lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001121 if (lookup->IsFound()) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001122 if (holder->GetPrototype()->IsNull()) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001123 holder->GetPrototype()->Lookup(*name, lookup);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001124}
1125
1126
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001127#define __ ACCESS_MASM(masm())
1128
1129
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001130Register LoadStubCompiler::HandlerFrontendHeader(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001131 Handle<Object> object,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001132 Register object_reg,
1133 Handle<JSObject> holder,
1134 Handle<Name> name,
1135 Label* miss) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001136 Handle<JSObject> receiver;
1137 PrototypeCheckType check_type = CHECK_ALL_MAPS;
1138 int function_index = -1;
1139 if (object->IsJSObject()) {
1140 receiver = Handle<JSObject>::cast(object);
1141 check_type = SKIP_RECEIVER;
1142 } else {
1143 if (object->IsString()) {
1144 function_index = Context::STRING_FUNCTION_INDEX;
1145 } else if (object->IsSymbol()) {
1146 function_index = Context::SYMBOL_FUNCTION_INDEX;
1147 } else if (object->IsNumber()) {
1148 function_index = Context::NUMBER_FUNCTION_INDEX;
1149 } else {
1150 ASSERT(object->IsBoolean());
1151 // Booleans use the generic oddball map, so an additional check is
1152 // needed to ensure the receiver is really a boolean.
1153 GenerateBooleanCheck(object_reg, miss);
1154 function_index = Context::BOOLEAN_FUNCTION_INDEX;
1155 }
1156
1157 GenerateDirectLoadGlobalFunctionPrototype(
1158 masm(), function_index, scratch1(), miss);
1159 receiver = handle(JSObject::cast(object->GetPrototype(isolate())));
1160 object_reg = scratch1();
1161 }
1162
1163 // Check that the maps starting from the prototype haven't changed.
1164 return CheckPrototypes(receiver, object_reg, holder,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001165 scratch1(), scratch2(), scratch3(),
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001166 name, miss, check_type);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001167}
1168
1169
danno@chromium.orgbee51992013-07-10 14:57:15 +00001170// HandlerFrontend for store uses the name register. It has to be restored
1171// before a miss.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001172Register StoreStubCompiler::HandlerFrontendHeader(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001173 Handle<Object> object,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001174 Register object_reg,
1175 Handle<JSObject> holder,
1176 Handle<Name> name,
1177 Label* miss) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001178 return CheckPrototypes(Handle<JSObject>::cast(object), object_reg, holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001179 this->name(), scratch1(), scratch2(),
1180 name, miss, SKIP_RECEIVER);
1181}
1182
1183
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001184bool BaseLoadStoreStubCompiler::HasHeapNumberMap(MapHandleList* receiver_maps) {
1185 for (int i = 0; i < receiver_maps->length(); ++i) {
1186 Handle<Map> map = receiver_maps->at(i);
1187 if (map.is_identical_to(isolate()->factory()->heap_number_map())) {
1188 return true;
1189 }
1190 }
1191 return false;
1192}
1193
1194
1195Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<Object> object,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001196 Register object_reg,
1197 Handle<JSObject> holder,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001198 Handle<Name> name) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001199 Label miss;
1200
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001201 Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001202
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001203 HandlerFrontendFooter(name, &miss);
1204
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001205 return reg;
1206}
1207
1208
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001209void LoadStubCompiler::NonexistentHandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001210 Handle<Object> object,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001211 Handle<JSObject> last,
1212 Handle<Name> name,
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001213 Handle<JSGlobalObject> global) {
1214 Label miss;
1215
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001216 Register holder = HandlerFrontendHeader(
1217 object, receiver(), last, name, &miss);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001218
1219 if (!last->HasFastProperties() &&
1220 !last->IsJSGlobalObject() &&
1221 !last->IsJSGlobalProxy()) {
1222 if (!name->IsUniqueName()) {
1223 ASSERT(name->IsString());
1224 name = factory()->InternalizeString(Handle<String>::cast(name));
1225 }
1226 ASSERT(last->property_dictionary()->FindEntry(*name) ==
1227 NameDictionary::kNotFound);
1228 GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
1229 scratch2(), scratch3());
1230 }
1231
1232 // If the last object in the prototype chain is a global object,
1233 // check that the global property cell is empty.
1234 if (!global.is_null()) {
1235 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1236 }
1237
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001238 HandlerFrontendFooter(name, &miss);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001239}
1240
1241
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001242Handle<Code> LoadStubCompiler::CompileLoadField(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001243 Handle<Object> object,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001244 Handle<JSObject> holder,
1245 Handle<Name> name,
1246 PropertyIndex field,
1247 Representation representation) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001248 Label miss;
1249
1250 Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss);
1251
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001252 GenerateLoadField(reg, holder, field, representation);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001253
1254 __ bind(&miss);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001255 TailCallBuiltin(masm(), MissBuiltin(kind()));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001256
1257 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001258 return GetCode(kind(), Code::FIELD, name);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001259}
1260
1261
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001262Handle<Code> LoadStubCompiler::CompileLoadConstant(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001263 Handle<Object> object,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001264 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001265 Handle<Name> name,
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001266 Handle<Object> value) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001267 HandlerFrontend(object, receiver(), holder, name);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001268 GenerateLoadConstant(value);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001269
1270 // Return the generated code.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001271 return GetCode(kind(), Code::CONSTANT, name);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001272}
1273
1274
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001275Handle<Code> LoadStubCompiler::CompileLoadCallback(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001276 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001277 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001278 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001279 Handle<ExecutableAccessorInfo> callback) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001280 Register reg = CallbackHandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001281 object, receiver(), holder, name, callback);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001282 GenerateLoadCallback(reg, callback);
1283
1284 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001285 return GetCode(kind(), Code::CALLBACKS, name);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001286}
1287
1288
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001289Handle<Code> LoadStubCompiler::CompileLoadCallback(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001290 Handle<Object> object,
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001291 Handle<JSObject> holder,
1292 Handle<Name> name,
1293 const CallOptimization& call_optimization) {
1294 ASSERT(call_optimization.is_simple_api_call());
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001295 Handle<JSFunction> callback = call_optimization.constant_function();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001296 CallbackHandlerFrontend(object, receiver(), holder, name, callback);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001297 GenerateLoadCallback(call_optimization);
1298
1299 // Return the generated code.
1300 return GetCode(kind(), Code::CALLBACKS, name);
1301}
1302
1303
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001304Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001305 Handle<Object> object,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001306 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001307 Handle<Name> name) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001308 LookupResult lookup(isolate());
1309 LookupPostInterceptor(holder, name, &lookup);
1310
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001311 Register reg = HandlerFrontend(object, receiver(), holder, name);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001312 // TODO(368): Compile in the whole chain: all the interceptors in
1313 // prototypes and ultimate answer.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001314 GenerateLoadInterceptor(reg, object, holder, &lookup, name);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001315
1316 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001317 return GetCode(kind(), Code::INTERCEPTOR, name);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001318}
1319
1320
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001321void LoadStubCompiler::GenerateLoadPostInterceptor(
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001322 Register interceptor_reg,
1323 Handle<JSObject> interceptor_holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001324 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001325 LookupResult* lookup) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001326 Handle<JSObject> holder(lookup->holder());
1327 if (lookup->IsField()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001328 PropertyIndex field = lookup->GetFieldIndex();
1329 if (interceptor_holder.is_identical_to(holder)) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001330 GenerateLoadField(
1331 interceptor_reg, holder, field, lookup->representation());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001332 } else {
1333 // We found FIELD property in prototype chain of interceptor's holder.
1334 // Retrieve a field from field's holder.
1335 Register reg = HandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001336 interceptor_holder, interceptor_reg, holder, name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001337 GenerateLoadField(
1338 reg, holder, field, lookup->representation());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001339 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001340 } else {
1341 // We found CALLBACKS property in prototype chain of interceptor's
1342 // holder.
1343 ASSERT(lookup->type() == CALLBACKS);
1344 Handle<ExecutableAccessorInfo> callback(
1345 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
1346 ASSERT(callback->getter() != NULL);
1347
1348 Register reg = CallbackHandlerFrontend(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001349 interceptor_holder, interceptor_reg, holder, name, callback);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001350 GenerateLoadCallback(reg, callback);
1351 }
1352}
1353
1354
danno@chromium.orgbee51992013-07-10 14:57:15 +00001355Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001356 Handle<Map> receiver_map,
1357 Handle<Code> handler,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001358 Handle<Name> name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001359 MapHandleList receiver_maps(1);
1360 receiver_maps.Add(receiver_map);
1361 CodeHandleList handlers(1);
1362 handlers.Add(handler);
1363 Code::StubType type = handler->type();
1364 return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
1365}
1366
1367
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001368Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001369 Handle<Object> object,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001370 Handle<JSObject> holder,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001371 Handle<Name> name,
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001372 Handle<JSFunction> getter) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001373 HandlerFrontend(object, receiver(), holder, name);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001374 GenerateLoadViaGetter(masm(), receiver(), getter);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001375
1376 // Return the generated code.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001377 return GetCode(kind(), Code::CALLBACKS, name);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001378}
1379
1380
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001381Handle<Code> StoreStubCompiler::CompileStoreTransition(
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001382 Handle<JSObject> object,
1383 LookupResult* lookup,
1384 Handle<Map> transition,
1385 Handle<Name> name) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001386 Label miss, slow;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001387
danno@chromium.orgbee51992013-07-10 14:57:15 +00001388 // Ensure no transitions to deprecated maps are followed.
1389 __ CheckMapDeprecated(transition, scratch1(), &miss);
1390
1391 // Check that we are allowed to write this.
1392 if (object->GetPrototype()->IsJSObject()) {
1393 Handle<JSObject> holder;
1394 // holder == object indicates that no property was found.
1395 if (lookup->holder() != *object) {
1396 holder = Handle<JSObject>(lookup->holder());
1397 } else {
1398 // Find the top object.
1399 holder = object;
1400 do {
1401 holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
1402 } while (holder->GetPrototype()->IsJSObject());
1403 }
1404
1405 Register holder_reg =
1406 HandlerFrontendHeader(object, receiver(), holder, name, &miss);
1407
1408 // If no property was found, and the holder (the last object in the
1409 // prototype chain) is in slow mode, we need to do a negative lookup on the
1410 // holder.
1411 if (lookup->holder() == *object) {
1412 GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
1413 }
1414 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001415
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001416 GenerateStoreTransition(masm(),
1417 object,
1418 lookup,
1419 transition,
1420 name,
1421 receiver(), this->name(), value(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001422 scratch1(), scratch2(), scratch3(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001423 &miss,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001424 &slow);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001425
1426 // Handle store cache miss.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001427 GenerateRestoreName(masm(), &miss, name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001428 TailCallBuiltin(masm(), MissBuiltin(kind()));
1429
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001430 GenerateRestoreName(masm(), &slow, name);
1431 TailCallBuiltin(masm(), SlowBuiltin(kind()));
1432
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001433 // Return the generated code.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001434 return GetCode(kind(), Code::TRANSITION, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001435}
1436
1437
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001438Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
1439 LookupResult* lookup,
1440 Handle<Name> name) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001441 Label miss;
1442
danno@chromium.orgbee51992013-07-10 14:57:15 +00001443 HandlerFrontendHeader(object, receiver(), object, name, &miss);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001444
1445 // Generate store field code.
1446 GenerateStoreField(masm(),
1447 object,
1448 lookup,
1449 receiver(), this->name(), value(), scratch1(), scratch2(),
1450 &miss);
1451
1452 // Handle store cache miss.
1453 __ bind(&miss);
1454 TailCallBuiltin(masm(), MissBuiltin(kind()));
1455
1456 // Return the generated code.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001457 return GetCode(kind(), Code::FIELD, name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001458}
1459
1460
1461Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001462 Handle<JSObject> object,
1463 Handle<JSObject> holder,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001464 Handle<Name> name,
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001465 Handle<JSFunction> setter) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001466 HandlerFrontend(object, receiver(), holder, name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001467 GenerateStoreViaSetter(masm(), setter);
1468
danno@chromium.orgbee51992013-07-10 14:57:15 +00001469 return GetCode(kind(), Code::CALLBACKS, name);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001470}
1471
1472
1473Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
1474 Handle<Map> receiver_map) {
1475 ElementsKind elements_kind = receiver_map->elements_kind();
1476 if (receiver_map->has_fast_elements() ||
1477 receiver_map->has_external_array_elements()) {
1478 Handle<Code> stub = KeyedLoadFastElementStub(
1479 receiver_map->instance_type() == JS_ARRAY_TYPE,
1480 elements_kind).GetCode(isolate());
1481 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1482 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00001483 Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
1484 ? KeyedLoadDictionaryElementStub().GetCode(isolate())
1485 : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001486 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1487 }
1488
1489 TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
1490
1491 // Return the generated code.
1492 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1493}
1494
1495
1496Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
1497 Handle<Map> receiver_map) {
1498 ElementsKind elements_kind = receiver_map->elements_kind();
1499 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001500 Handle<Code> stub;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001501 if (receiver_map->has_fast_elements() ||
1502 receiver_map->has_external_array_elements()) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001503 stub = KeyedStoreFastElementStub(
1504 is_jsarray,
1505 elements_kind,
1506 store_mode_).GetCode(isolate());
1507 } else {
1508 stub = KeyedStoreElementStub(is_jsarray,
1509 elements_kind,
1510 store_mode_).GetCode(isolate());
1511 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001512
1513 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1514
1515 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1516
1517 // Return the generated code.
1518 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1519}
1520
1521
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001522#undef __
1523
1524
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001525void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1526 Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1527 GenerateTailCall(masm, code);
1528}
1529
1530
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001531void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
1532#ifdef ENABLE_GDB_JIT_INTERFACE
1533 GDBJITInterface::CodeTag tag;
1534 if (kind_ == Code::LOAD_IC) {
1535 tag = GDBJITInterface::LOAD_IC;
1536 } else if (kind_ == Code::KEYED_LOAD_IC) {
1537 tag = GDBJITInterface::KEYED_LOAD_IC;
1538 } else if (kind_ == Code::STORE_IC) {
1539 tag = GDBJITInterface::STORE_IC;
1540 } else {
1541 tag = GDBJITInterface::KEYED_STORE_IC;
1542 }
1543 GDBJIT(AddCode(tag, *name, *code));
1544#endif
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001545}
1546
1547
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001548void BaseLoadStoreStubCompiler::InitializeRegisters() {
1549 if (kind_ == Code::LOAD_IC) {
1550 registers_ = LoadStubCompiler::registers();
1551 } else if (kind_ == Code::KEYED_LOAD_IC) {
1552 registers_ = KeyedLoadStubCompiler::registers();
1553 } else if (kind_ == Code::STORE_IC) {
1554 registers_ = StoreStubCompiler::registers();
1555 } else {
1556 registers_ = KeyedStoreStubCompiler::registers();
1557 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001558}
1559
1560
danno@chromium.orgbee51992013-07-10 14:57:15 +00001561Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
1562 Code::StubType type,
1563 Handle<Name> name,
1564 InlineCacheState state) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001565 Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001566 Handle<Code> code = GetCodeWithFlags(flags, name);
1567 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1568 JitEvent(name, code);
1569 return code;
1570}
1571
1572
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001573Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
1574 Code::StubType type,
1575 Handle<Name> name) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001576 Code::Flags flags = Code::ComputeFlags(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001577 Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001578 Handle<Code> code = GetCodeWithFlags(flags, name);
1579 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1580 JitEvent(name, code);
1581 return code;
1582}
1583
1584
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001585void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
1586 CodeHandleList* handlers) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001587 for (int i = 0; i < receiver_maps->length(); ++i) {
1588 Handle<Map> receiver_map = receiver_maps->at(i);
1589 Handle<Code> cached_stub;
1590
1591 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1592 cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1593 } else {
1594 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1595 ElementsKind elements_kind = receiver_map->elements_kind();
1596
1597 if (IsFastElementsKind(elements_kind) ||
1598 IsExternalArrayElementsKind(elements_kind)) {
1599 cached_stub =
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001600 KeyedLoadFastElementStub(is_js_array,
1601 elements_kind).GetCode(isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001602 } else {
1603 ASSERT(elements_kind == DICTIONARY_ELEMENTS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001604 cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001605 }
1606 }
1607
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001608 handlers->Add(cached_stub);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001609 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001610}
1611
1612
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001613Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
1614 MapHandleList* receiver_maps) {
1615 // Collect MONOMORPHIC stubs for all |receiver_maps|.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001616 CodeHandleList handlers(receiver_maps->length());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001617 MapHandleList transitioned_maps(receiver_maps->length());
1618 for (int i = 0; i < receiver_maps->length(); ++i) {
1619 Handle<Map> receiver_map(receiver_maps->at(i));
1620 Handle<Code> cached_stub;
1621 Handle<Map> transitioned_map =
1622 receiver_map->FindTransitionedMap(receiver_maps);
1623
1624 // TODO(mvstanton): The code below is doing pessimistic elements
1625 // transitions. I would like to stop doing that and rely on Allocation Site
1626 // Tracking to do a better job of ensuring the data types are what they need
1627 // to be. Not all the elements are in place yet, pessimistic elements
1628 // transitions are still important for performance.
1629 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1630 ElementsKind elements_kind = receiver_map->elements_kind();
1631 if (!transitioned_map.is_null()) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001632 cached_stub = ElementsTransitionAndStoreStub(
1633 elements_kind,
1634 transitioned_map->elements_kind(),
1635 is_js_array,
1636 store_mode_).GetCode(isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001637 } else {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001638 if (receiver_map->has_fast_elements() ||
1639 receiver_map->has_external_array_elements()) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001640 cached_stub = KeyedStoreFastElementStub(
1641 is_js_array,
1642 elements_kind,
1643 store_mode_).GetCode(isolate());
1644 } else {
1645 cached_stub = KeyedStoreElementStub(
1646 is_js_array,
1647 elements_kind,
1648 store_mode_).GetCode(isolate());
1649 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001650 }
1651 ASSERT(!cached_stub.is_null());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001652 handlers.Add(cached_stub);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001653 transitioned_maps.Add(transitioned_map);
1654 }
1655 Handle<Code> code =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001656 CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001657 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1658 PROFILE(isolate(),
1659 CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
1660 return code;
1661}
1662
1663
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001664void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1665 MacroAssembler* masm) {
1666 KeyedStoreIC::GenerateSlow(masm);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001667}
1668
1669
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001670CallStubCompiler::CallStubCompiler(Isolate* isolate,
1671 int argc,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001672 Code::Kind kind,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001673 Code::ExtraICState extra_state,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001674 InlineCacheHolderFlag cache_holder)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001675 : StubCompiler(isolate),
1676 arguments_(argc),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001677 kind_(kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 extra_state_(extra_state),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001679 cache_holder_(cache_holder) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001680}
1681
1682
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001683bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
1684 if (function->shared()->HasBuiltinFunctionId()) {
1685 BuiltinFunctionId id = function->shared()->builtin_function_id();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001688#undef CALL_GENERATOR_CASE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 CallOptimization optimization(function);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001692 return optimization.is_simple_api_call();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001693}
1694
1695
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001696bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) {
1697 if (function->shared()->HasBuiltinFunctionId()) {
1698 BuiltinFunctionId id = function->shared()->builtin_function_id();
1699#define CALL_GENERATOR_CASE(name) if (id == k##name) return false;
1700 SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE)
1701#undef CALL_GENERATOR_CASE
1702 }
1703
1704 return true;
1705}
1706
1707
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001708Handle<Code> CallStubCompiler::CompileCustomCall(
1709 Handle<Object> object,
1710 Handle<JSObject> holder,
danno@chromium.org41728482013-06-12 22:31:22 +00001711 Handle<Cell> cell,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001712 Handle<JSFunction> function,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001713 Handle<String> fname,
1714 Code::StubType type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 ASSERT(HasCustomCallGenerator(function));
1716
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001717 if (function->shared()->HasBuiltinFunctionId()) {
1718 BuiltinFunctionId id = function->shared()->builtin_function_id();
1719#define CALL_GENERATOR_CASE(name) \
1720 if (id == k##name) { \
1721 return CallStubCompiler::Compile##name##Call(object, \
1722 holder, \
1723 cell, \
1724 function, \
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001725 fname, \
1726 type); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 }
1728 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001729#undef CALL_GENERATOR_CASE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 }
1731 CallOptimization optimization(function);
1732 ASSERT(optimization.is_simple_api_call());
1733 return CompileFastApiCall(optimization,
1734 object,
1735 holder,
1736 cell,
1737 function,
1738 fname);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001739}
1740
1741
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001742Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001743 Handle<Name> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001744 int argc = arguments_.immediate();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001745 Code::Flags flags = Code::ComputeMonomorphicFlags(
1746 kind_, extra_state_, cache_holder_, type, argc);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001747 return GetCodeWithFlags(flags, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748}
1749
1750
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001751Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
1752 Handle<String> function_name;
1753 if (function->shared()->name()->IsString()) {
1754 function_name = Handle<String>(String::cast(function->shared()->name()));
1755 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001756 return GetCode(Code::CONSTANT, function_name);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001757}
1758
1759
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001760CallOptimization::CallOptimization(LookupResult* lookup) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001761 if (lookup->IsFound() &&
1762 lookup->IsCacheable() &&
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001763 lookup->IsConstantFunction()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001764 // We only optimize constant function calls.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001765 Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001766 } else {
1767 Initialize(Handle<JSFunction>::null());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001768 }
1769}
1770
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001771
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001772CallOptimization::CallOptimization(Handle<JSFunction> function) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001773 Initialize(function);
1774}
1775
1776
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001777int CallOptimization::GetPrototypeDepthOfExpectedType(
1778 Handle<JSObject> object,
1779 Handle<JSObject> holder) const {
1780 ASSERT(is_simple_api_call());
1781 if (expected_receiver_type_.is_null()) return 0;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001782 int depth = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001783 while (!object.is_identical_to(holder)) {
1784 if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
1785 object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001786 if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001787 ++depth;
1788 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001789 if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001790 return kInvalidProtoDepth;
1791}
1792
1793
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001794void CallOptimization::Initialize(Handle<JSFunction> function) {
1795 constant_function_ = Handle<JSFunction>::null();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001796 is_simple_api_call_ = false;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001797 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1798 api_call_info_ = Handle<CallHandlerInfo>::null();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001799
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001800 if (function.is_null() || !function->is_compiled()) return;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001801
1802 constant_function_ = function;
1803 AnalyzePossibleApiFunction(function);
1804}
1805
1806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1808 if (!function->shared()->IsApiFunction()) return;
1809 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001810
1811 // Require a C++ callback.
1812 if (info->call_code()->IsUndefined()) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001813 api_call_info_ =
1814 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001815
1816 // Accept signatures that either have no restrictions at all or
1817 // only have restrictions on the receiver.
1818 if (!info->signature()->IsUndefined()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001819 Handle<SignatureInfo> signature =
1820 Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001821 if (!signature->args()->IsUndefined()) return;
1822 if (!signature->receiver()->IsUndefined()) {
1823 expected_receiver_type_ =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 Handle<FunctionTemplateInfo>(
1825 FunctionTemplateInfo::cast(signature->receiver()));
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001826 }
1827 }
1828
1829 is_simple_api_call_ = true;
1830}
1831
1832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833} } // namespace v8::internal