blob: 498a6952dea5651990219e4611486806f9e73533 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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#ifndef V8_STUB_CACHE_H_
29#define V8_STUB_CACHE_H_
30
31#include "macro-assembler.h"
32
33namespace v8 { namespace internal {
34
35
36// The stub cache is used for megamorphic calls and property accesses.
37// It maps (map, name, type)->Code*
38
39// The design of the table uses the inline cache stubs used for
40// mono-morphic calls. The beauty of this, we do not have to
41// invalidate the cache whenever a prototype map is changed. The stub
42// validates the map chain as in the mono-morphic case.
43
44class SCTableReference;
45
46class StubCache : public AllStatic {
47 public:
48 struct Entry {
49 String* key;
50 Code* value;
51 };
52
53
54 static void Initialize(bool create_heap_objects);
55
56 // Computes the right stub matching. Inserts the result in the
57 // cache before returning. This might compile a stub if needed.
58 static Object* ComputeLoadField(String* name,
59 JSObject* receiver,
60 JSObject* holder,
61 int field_index);
62
63 static Object* ComputeLoadCallback(String* name,
64 JSObject* receiver,
65 JSObject* holder,
66 AccessorInfo* callback);
67
68 static Object* ComputeLoadConstant(String* name,
69 JSObject* receiver,
70 JSObject* holder,
71 Object* value);
72
73 static Object* ComputeLoadInterceptor(String* name,
74 JSObject* receiver,
75 JSObject* holder);
76
77 static Object* ComputeLoadNormal(String* name, JSObject* receiver);
78
79
80 // ---
81
82 static Object* ComputeKeyedLoadField(String* name,
83 JSObject* receiver,
84 JSObject* holder,
85 int field_index);
86
87 static Object* ComputeKeyedLoadCallback(String* name,
88 JSObject* receiver,
89 JSObject* holder,
90 AccessorInfo* callback);
91
92 static Object* ComputeKeyedLoadConstant(String* name, JSObject* receiver,
93 JSObject* holder, Object* value);
94
95 static Object* ComputeKeyedLoadInterceptor(String* name,
96 JSObject* receiver,
97 JSObject* holder);
98
99 static Object* ComputeKeyedLoadArrayLength(String* name, JSArray* receiver);
100
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000101 static Object* ComputeKeyedLoadStringLength(String* name,
102 String* receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104 static Object* ComputeKeyedLoadFunctionPrototype(String* name,
105 JSFunction* receiver);
106
107 // ---
108
109 static Object* ComputeStoreField(String* name,
110 JSObject* receiver,
111 int field_index,
112 Map* transition = NULL);
113
114 static Object* ComputeStoreCallback(String* name,
115 JSObject* receiver,
116 AccessorInfo* callback);
117
118 static Object* ComputeStoreInterceptor(String* name, JSObject* receiver);
119
120 // ---
121
122 static Object* ComputeKeyedStoreField(String* name,
123 JSObject* receiver,
124 int field_index,
125 Map* transition = NULL);
126
127 // ---
128
129 static Object* ComputeCallField(int argc,
130 String* name,
131 Object* object,
132 JSObject* holder,
133 int index);
134
135 static Object* ComputeCallConstant(int argc,
136 String* name,
137 Object* object,
138 JSObject* holder,
139 JSFunction* function);
140
141 static Object* ComputeCallNormal(int argc, String* name, JSObject* receiver);
142
143 static Object* ComputeCallInterceptor(int argc,
144 String* name,
145 Object* object,
146 JSObject* holder);
147
148 // ---
149
150 static Object* ComputeCallInitialize(int argc);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000151 static Object* ComputeCallInitializeInLoop(int argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152 static Object* ComputeCallPreMonomorphic(int argc);
153 static Object* ComputeCallNormal(int argc);
154 static Object* ComputeCallMegamorphic(int argc);
155 static Object* ComputeCallMiss(int argc);
156
157 // Finds the Code object stored in the Heap::non_monomorphic_cache().
158 static Code* FindCallInitialize(int argc);
159
160 static Object* ComputeCallDebugBreak(int argc);
161 static Object* ComputeCallDebugPrepareStepIn(int argc);
162
163 static Object* ComputeLazyCompile(int argc);
164
165
166 // Update cache for entry hash(name, map).
167 static Code* Set(String* name, Map* map, Code* code);
168
169 // Clear the lookup table (@ mark compact collection).
170 static void Clear();
171
172 // Functions for generating stubs at startup.
173 static void GenerateMiss(MacroAssembler* masm);
174
175 // Generate code for probing the stub cache table.
176 static void GenerateProbe(MacroAssembler* masm,
177 Code::Flags flags,
178 Register receiver,
179 Register name,
180 Register scratch);
181
182 enum Table {
183 kPrimary,
184 kSecondary
185 };
186
187 private:
188 friend class SCTableReference;
189 static const int kPrimaryTableSize = 2048;
190 static const int kSecondaryTableSize = 512;
191 static Entry primary_[];
192 static Entry secondary_[];
193
194 // Computes the hashed offsets for primary and secondary caches.
195 static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000196 // This works well because the heap object tag size and the hash
197 // shift are equal. Shifting down the length field to get the
198 // hash code would effectively throw away two bits of the hash
199 // code.
200 ASSERT(kHeapObjectTagSize == String::kHashShift);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 // Compute the hash of the name (use entire length field).
ager@chromium.org7c537e22008-10-16 08:43:32 +0000202 ASSERT(name->HasHashCode());
203 uint32_t field = name->length_field();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 // Base the offset on a simple combination of name, flags, and map.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000205 uint32_t key = (reinterpret_cast<uint32_t>(map) + field) ^ flags;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
207 }
208
209 static int SecondaryOffset(String* name, Code::Flags flags, int seed) {
210 // Use the seed from the primary cache in the secondary cache.
211 uint32_t key = seed - reinterpret_cast<uint32_t>(name) + flags;
212 return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
213 }
214
215 // Compute the entry for a given offset in exactly the same way as
216 // we done in generated code. This makes it a lot easier to avoid
217 // making mistakes in the hashed offset computations.
218 static Entry* entry(Entry* table, int offset) {
219 return reinterpret_cast<Entry*>(
220 reinterpret_cast<Address>(table) + (offset << 1));
221 }
222};
223
224
225class SCTableReference {
226 public:
227 static SCTableReference keyReference(StubCache::Table table) {
228 return SCTableReference(
229 reinterpret_cast<Address>(&first_entry(table)->key));
230 }
231
232
233 static SCTableReference valueReference(StubCache::Table table) {
234 return SCTableReference(
235 reinterpret_cast<Address>(&first_entry(table)->value));
236 }
237
238 Address address() const { return address_; }
239
240 private:
241 explicit SCTableReference(Address address) : address_(address) {}
242
243 static StubCache::Entry* first_entry(StubCache::Table table) {
244 switch (table) {
245 case StubCache::kPrimary: return StubCache::primary_;
246 case StubCache::kSecondary: return StubCache::secondary_;
247 }
248 UNREACHABLE();
249 return NULL;
250 }
251
252 Address address_;
253};
254
255// ------------------------------------------------------------------------
256
257
258// Support functions for IC stubs for callbacks.
259Object* LoadCallbackProperty(Arguments args);
260Object* StoreCallbackProperty(Arguments args);
261
262
263// Support functions for IC stubs for interceptors.
264Object* LoadInterceptorProperty(Arguments args);
265Object* StoreInterceptorProperty(Arguments args);
266Object* CallInterceptorProperty(Arguments args);
267
268
269// Support function for computing call IC miss stubs.
270Handle<Code> ComputeCallMiss(int argc);
271
272
273// The stub compiler compiles stubs for the stub cache.
274class StubCompiler BASE_EMBEDDED {
275 public:
276 enum CheckType {
277 RECEIVER_MAP_CHECK,
278 STRING_CHECK,
279 NUMBER_CHECK,
280 BOOLEAN_CHECK,
281 JSARRAY_HAS_FAST_ELEMENTS_CHECK
282 };
283
284 StubCompiler() : masm_(NULL, 256) { }
285
286 Object* CompileCallInitialize(Code::Flags flags);
287 Object* CompileCallPreMonomorphic(Code::Flags flags);
288 Object* CompileCallNormal(Code::Flags flags);
289 Object* CompileCallMegamorphic(Code::Flags flags);
290 Object* CompileCallMiss(Code::Flags flags);
291 Object* CompileCallDebugBreak(Code::Flags flags);
292 Object* CompileCallDebugPrepareStepIn(Code::Flags flags);
293 Object* CompileLazyCompile(Code::Flags flags);
294
295 // Static functions for generating parts of stubs.
296 static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
297 int index,
298 Register prototype);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000299 static void GenerateFastPropertyLoad(MacroAssembler* masm,
300 Register dst, Register src,
301 JSObject* holder, int index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 static void GenerateLoadField(MacroAssembler* masm,
303 JSObject* object,
304 JSObject* holder,
305 Register receiver,
306 Register scratch1,
307 Register scratch2,
308 int index,
309 Label* miss_label);
310 static void GenerateLoadCallback(MacroAssembler* masm,
311 JSObject* object,
312 JSObject* holder,
313 Register receiver,
314 Register name,
315 Register scratch1,
316 Register scratch2,
317 AccessorInfo* callback,
318 Label* miss_label);
319 static void GenerateLoadConstant(MacroAssembler* masm,
320 JSObject* object,
321 JSObject* holder,
322 Register receiver,
323 Register scratch1,
324 Register scratch2,
325 Object* value,
326 Label* miss_label);
327 static void GenerateLoadInterceptor(MacroAssembler* masm,
328 JSObject* object,
329 JSObject* holder,
330 Register receiver,
331 Register name,
332 Register scratch1,
333 Register scratch2,
334 Label* miss_label);
335 static void GenerateLoadArrayLength(MacroAssembler* masm,
336 Register receiver,
337 Register scratch,
338 Label* miss_label);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000339 static void GenerateLoadStringLength(MacroAssembler* masm,
340 Register receiver,
341 Register scratch,
342 Label* miss_label);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000343 static void GenerateLoadStringLength2(MacroAssembler* masm,
344 Register receiver,
345 Register scratch1,
346 Register scratch2,
347 Label* miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
349 Register receiver,
350 Register scratch1,
351 Register scratch2,
352 Label* miss_label);
353 static void GenerateStoreField(MacroAssembler* masm,
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000354 Builtins::Name storage_extend,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 JSObject* object,
356 int index,
357 Map* transition,
358 Register receiver_reg,
359 Register name_reg,
360 Register scratch,
361 Label* miss_label);
362 static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind);
363
364 protected:
365 Object* GetCodeWithFlags(Code::Flags flags);
366
367 MacroAssembler* masm() { return &masm_; }
368
369 private:
370 MacroAssembler masm_;
371};
372
373
374class LoadStubCompiler: public StubCompiler {
375 public:
376 Object* CompileLoadField(JSObject* object, JSObject* holder, int index);
377 Object* CompileLoadCallback(JSObject* object,
378 JSObject* holder,
379 AccessorInfo* callback);
380 Object* CompileLoadConstant(JSObject* object,
381 JSObject* holder,
382 Object* value);
383 Object* CompileLoadInterceptor(JSObject* object,
384 JSObject* holder,
385 String* name);
386
387 private:
388 Object* GetCode(PropertyType);
389};
390
391
392class KeyedLoadStubCompiler: public StubCompiler {
393 public:
394 Object* CompileLoadField(String* name,
395 JSObject* object,
396 JSObject* holder,
397 int index);
398 Object* CompileLoadCallback(String* name,
399 JSObject* object,
400 JSObject* holder,
401 AccessorInfo* callback);
402 Object* CompileLoadConstant(String* name,
403 JSObject* object,
404 JSObject* holder,
405 Object* value);
406 Object* CompileLoadInterceptor(JSObject* object,
407 JSObject* holder,
408 String* name);
409 Object* CompileLoadArrayLength(String* name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000410 Object* CompileLoadStringLength(String* name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411 Object* CompileLoadFunctionPrototype(String* name);
412
413 private:
414 Object* GetCode(PropertyType);
415};
416
417
418class StoreStubCompiler: public StubCompiler {
419 public:
420 Object* CompileStoreField(JSObject* object,
421 int index,
422 Map* transition,
423 String* name);
424 Object* CompileStoreCallback(JSObject* object,
425 AccessorInfo* callbacks,
426 String* name);
427 Object* CompileStoreInterceptor(JSObject* object, String* name);
428
429 private:
430 Object* GetCode(PropertyType type);
431};
432
433
434class KeyedStoreStubCompiler: public StubCompiler {
435 public:
436 Object* CompileStoreField(JSObject* object,
437 int index,
438 Map* transition,
439 String* name);
440
441 private:
442 Object* GetCode(PropertyType type);
443};
444
445
446class CallStubCompiler: public StubCompiler {
447 public:
448 explicit CallStubCompiler(int argc) : arguments_(argc) { }
449
450 Object* CompileCallField(Object* object, JSObject* holder, int index);
451 Object* CompileCallConstant(Object* object,
452 JSObject* holder,
453 JSFunction* function,
454 CheckType check);
455 Object* CompileCallInterceptor(Object* object,
456 JSObject* holder,
457 String* name);
458
459 private:
460 const ParameterCount arguments_;
461
462 const ParameterCount& arguments() { return arguments_; }
463
464 Object* GetCode(PropertyType type);
465};
466
467
468} } // namespace v8::internal
469
470#endif // V8_STUB_CACHE_H_