The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / src / stub-cache.h @ f230a1cf
History | View | Annotate | Download (42.2 KB)
1 |
// Copyright 2012 the V8 project authors. All rights reserved.
|
---|---|
2 |
// 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 "allocation.h" |
32 |
#include "arguments.h" |
33 |
#include "code-stubs.h" |
34 |
#include "ic-inl.h" |
35 |
#include "macro-assembler.h" |
36 |
#include "objects.h" |
37 |
#include "zone-inl.h" |
38 |
|
39 |
namespace v8 { |
40 |
namespace internal { |
41 |
|
42 |
|
43 |
// The stub cache is used for megamorphic calls and property accesses.
|
44 |
// It maps (map, name, type)->Code*
|
45 |
|
46 |
// The design of the table uses the inline cache stubs used for
|
47 |
// mono-morphic calls. The beauty of this, we do not have to
|
48 |
// invalidate the cache whenever a prototype map is changed. The stub
|
49 |
// validates the map chain as in the mono-morphic case.
|
50 |
|
51 |
|
52 |
class CallOptimization; |
53 |
class SmallMapList; |
54 |
class StubCache; |
55 |
|
56 |
|
57 |
class SCTableReference { |
58 |
public:
|
59 |
Address address() const { return address_; } |
60 |
|
61 |
private:
|
62 |
explicit SCTableReference(Address address) : address_(address) {} |
63 |
|
64 |
Address address_; |
65 |
|
66 |
friend class StubCache; |
67 |
}; |
68 |
|
69 |
|
70 |
class StubCache { |
71 |
public:
|
72 |
struct Entry {
|
73 |
Name* key; |
74 |
Code* value; |
75 |
Map* map; |
76 |
}; |
77 |
|
78 |
void Initialize();
|
79 |
|
80 |
Handle<JSObject> StubHolder(Handle<JSObject> receiver, |
81 |
Handle<JSObject> holder); |
82 |
|
83 |
Handle<Code> FindIC(Handle<Name> name, |
84 |
Handle<Map> stub_holder_map, |
85 |
Code::Kind kind, |
86 |
Code::ExtraICState extra_state = Code::kNoExtraICState); |
87 |
|
88 |
Handle<Code> FindIC(Handle<Name> name, |
89 |
Handle<JSObject> stub_holder, |
90 |
Code::Kind kind, |
91 |
Code::ExtraICState extra_state = Code::kNoExtraICState); |
92 |
|
93 |
Handle<Code> FindHandler(Handle<Name> name, |
94 |
Handle<JSObject> receiver, |
95 |
Code::Kind kind, |
96 |
StrictModeFlag strict_mode = kNonStrictMode); |
97 |
|
98 |
Handle<Code> ComputeMonomorphicIC(Handle<HeapObject> receiver, |
99 |
Handle<Code> handler, |
100 |
Handle<Name> name, |
101 |
StrictModeFlag strict_mode); |
102 |
|
103 |
// Computes the right stub matching. Inserts the result in the
|
104 |
// cache before returning. This might compile a stub if needed.
|
105 |
Handle<Code> ComputeLoadNonexistent(Handle<Name> name, |
106 |
Handle<JSObject> object); |
107 |
|
108 |
Handle<Code> ComputeLoadGlobal(Handle<Name> name, |
109 |
Handle<JSObject> object, |
110 |
Handle<GlobalObject> holder, |
111 |
Handle<PropertyCell> cell, |
112 |
bool is_dont_delete);
|
113 |
|
114 |
// ---
|
115 |
|
116 |
Handle<Code> ComputeKeyedLoadField(Handle<Name> name, |
117 |
Handle<JSObject> object, |
118 |
Handle<JSObject> holder, |
119 |
PropertyIndex field_index, |
120 |
Representation representation); |
121 |
|
122 |
Handle<Code> ComputeKeyedLoadCallback( |
123 |
Handle<Name> name, |
124 |
Handle<JSObject> object, |
125 |
Handle<JSObject> holder, |
126 |
Handle<ExecutableAccessorInfo> callback); |
127 |
|
128 |
Handle<Code> ComputeKeyedLoadCallback( |
129 |
Handle<Name> name, |
130 |
Handle<JSObject> object, |
131 |
Handle<JSObject> holder, |
132 |
const CallOptimization& call_optimization);
|
133 |
|
134 |
Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name, |
135 |
Handle<JSObject> object, |
136 |
Handle<JSObject> holder, |
137 |
Handle<Object> value); |
138 |
|
139 |
Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name, |
140 |
Handle<JSObject> object, |
141 |
Handle<JSObject> holder); |
142 |
|
143 |
Handle<Code> ComputeStoreGlobal(Handle<Name> name, |
144 |
Handle<GlobalObject> object, |
145 |
Handle<PropertyCell> cell, |
146 |
Handle<Object> value, |
147 |
StrictModeFlag strict_mode); |
148 |
|
149 |
Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map); |
150 |
|
151 |
Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map, |
152 |
StrictModeFlag strict_mode, |
153 |
KeyedAccessStoreMode store_mode); |
154 |
|
155 |
Handle<Code> ComputeCallField(int argc,
|
156 |
Code::Kind, |
157 |
Code::ExtraICState extra_state, |
158 |
Handle<Name> name, |
159 |
Handle<Object> object, |
160 |
Handle<JSObject> holder, |
161 |
PropertyIndex index); |
162 |
|
163 |
Handle<Code> ComputeCallConstant(int argc,
|
164 |
Code::Kind, |
165 |
Code::ExtraICState extra_state, |
166 |
Handle<Name> name, |
167 |
Handle<Object> object, |
168 |
Handle<JSObject> holder, |
169 |
Handle<JSFunction> function); |
170 |
|
171 |
Handle<Code> ComputeCallInterceptor(int argc,
|
172 |
Code::Kind, |
173 |
Code::ExtraICState extra_state, |
174 |
Handle<Name> name, |
175 |
Handle<Object> object, |
176 |
Handle<JSObject> holder); |
177 |
|
178 |
Handle<Code> ComputeCallGlobal(int argc,
|
179 |
Code::Kind, |
180 |
Code::ExtraICState extra_state, |
181 |
Handle<Name> name, |
182 |
Handle<JSObject> object, |
183 |
Handle<GlobalObject> holder, |
184 |
Handle<PropertyCell> cell, |
185 |
Handle<JSFunction> function); |
186 |
|
187 |
// ---
|
188 |
|
189 |
Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
|
190 |
|
191 |
Handle<Code> ComputeKeyedCallInitialize(int argc);
|
192 |
|
193 |
Handle<Code> ComputeCallPreMonomorphic(int argc,
|
194 |
Code::Kind kind, |
195 |
Code::ExtraICState extra_state); |
196 |
|
197 |
Handle<Code> ComputeCallNormal(int argc,
|
198 |
Code::Kind kind, |
199 |
Code::ExtraICState state); |
200 |
|
201 |
Handle<Code> ComputeCallArguments(int argc);
|
202 |
|
203 |
Handle<Code> ComputeCallMegamorphic(int argc,
|
204 |
Code::Kind kind, |
205 |
Code::ExtraICState state); |
206 |
|
207 |
Handle<Code> ComputeCallMiss(int argc,
|
208 |
Code::Kind kind, |
209 |
Code::ExtraICState state); |
210 |
|
211 |
// ---
|
212 |
|
213 |
Handle<Code> ComputeCompareNil(Handle<Map> receiver_map, |
214 |
CompareNilICStub& stub); |
215 |
|
216 |
// ---
|
217 |
|
218 |
Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps); |
219 |
Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps, |
220 |
KeyedAccessStoreMode store_mode, |
221 |
StrictModeFlag strict_mode); |
222 |
|
223 |
Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps, |
224 |
CodeHandleList* handlers, |
225 |
int number_of_valid_maps,
|
226 |
Handle<Name> name, |
227 |
StrictModeFlag strict_mode); |
228 |
|
229 |
// Finds the Code object stored in the Heap::non_monomorphic_cache().
|
230 |
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
|
231 |
|
232 |
#ifdef ENABLE_DEBUGGER_SUPPORT
|
233 |
Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
|
234 |
|
235 |
Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
|
236 |
#endif
|
237 |
|
238 |
// Update cache for entry hash(name, map).
|
239 |
Code* Set(Name* name, Map* map, Code* code); |
240 |
|
241 |
// Clear the lookup table (@ mark compact collection).
|
242 |
void Clear();
|
243 |
|
244 |
// Collect all maps that match the name and flags.
|
245 |
void CollectMatchingMaps(SmallMapList* types,
|
246 |
Handle<Name> name, |
247 |
Code::Flags flags, |
248 |
Handle<Context> native_context, |
249 |
Zone* zone); |
250 |
|
251 |
// Generate code for probing the stub cache table.
|
252 |
// Arguments extra, extra2 and extra3 may be used to pass additional scratch
|
253 |
// registers. Set to no_reg if not needed.
|
254 |
void GenerateProbe(MacroAssembler* masm,
|
255 |
Code::Flags flags, |
256 |
Register receiver, |
257 |
Register name, |
258 |
Register scratch, |
259 |
Register extra, |
260 |
Register extra2 = no_reg, |
261 |
Register extra3 = no_reg); |
262 |
|
263 |
enum Table {
|
264 |
kPrimary, |
265 |
kSecondary |
266 |
}; |
267 |
|
268 |
|
269 |
SCTableReference key_reference(StubCache::Table table) { |
270 |
return SCTableReference(
|
271 |
reinterpret_cast<Address>(&first_entry(table)->key)); |
272 |
} |
273 |
|
274 |
|
275 |
SCTableReference map_reference(StubCache::Table table) { |
276 |
return SCTableReference(
|
277 |
reinterpret_cast<Address>(&first_entry(table)->map)); |
278 |
} |
279 |
|
280 |
|
281 |
SCTableReference value_reference(StubCache::Table table) { |
282 |
return SCTableReference(
|
283 |
reinterpret_cast<Address>(&first_entry(table)->value)); |
284 |
} |
285 |
|
286 |
|
287 |
StubCache::Entry* first_entry(StubCache::Table table) { |
288 |
switch (table) {
|
289 |
case StubCache::kPrimary: return StubCache::primary_; |
290 |
case StubCache::kSecondary: return StubCache::secondary_; |
291 |
} |
292 |
UNREACHABLE(); |
293 |
return NULL; |
294 |
} |
295 |
|
296 |
Isolate* isolate() { return isolate_; }
|
297 |
Heap* heap() { return isolate()->heap(); }
|
298 |
Factory* factory() { return isolate()->factory(); }
|
299 |
|
300 |
// These constants describe the structure of the interceptor arguments on the
|
301 |
// stack. The arguments are pushed by the (platform-specific)
|
302 |
// PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
|
303 |
// LoadWithInterceptor.
|
304 |
static const int kInterceptorArgsNameIndex = 0; |
305 |
static const int kInterceptorArgsInfoIndex = 1; |
306 |
static const int kInterceptorArgsThisIndex = 2; |
307 |
static const int kInterceptorArgsHolderIndex = 3; |
308 |
static const int kInterceptorArgsLength = 4; |
309 |
|
310 |
private:
|
311 |
explicit StubCache(Isolate* isolate); |
312 |
|
313 |
Handle<Code> ComputeCallInitialize(int argc,
|
314 |
RelocInfo::Mode mode, |
315 |
Code::Kind kind); |
316 |
|
317 |
// The stub cache has a primary and secondary level. The two levels have
|
318 |
// different hashing algorithms in order to avoid simultaneous collisions
|
319 |
// in both caches. Unlike a probing strategy (quadratic or otherwise) the
|
320 |
// update strategy on updates is fairly clear and simple: Any existing entry
|
321 |
// in the primary cache is moved to the secondary cache, and secondary cache
|
322 |
// entries are overwritten.
|
323 |
|
324 |
// Hash algorithm for the primary table. This algorithm is replicated in
|
325 |
// assembler for every architecture. Returns an index into the table that
|
326 |
// is scaled by 1 << kHeapObjectTagSize.
|
327 |
static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) { |
328 |
// This works well because the heap object tag size and the hash
|
329 |
// shift are equal. Shifting down the length field to get the
|
330 |
// hash code would effectively throw away two bits of the hash
|
331 |
// code.
|
332 |
STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift); |
333 |
// Compute the hash of the name (use entire hash field).
|
334 |
ASSERT(name->HasHashCode()); |
335 |
uint32_t field = name->hash_field(); |
336 |
// Using only the low bits in 64-bit mode is unlikely to increase the
|
337 |
// risk of collision even if the heap is spread over an area larger than
|
338 |
// 4Gb (and not at all if it isn't).
|
339 |
uint32_t map_low32bits = |
340 |
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)); |
341 |
// We always set the in_loop bit to zero when generating the lookup code
|
342 |
// so do it here too so the hash codes match.
|
343 |
uint32_t iflags = |
344 |
(static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); |
345 |
// Base the offset on a simple combination of name, flags, and map.
|
346 |
uint32_t key = (map_low32bits + field) ^ iflags; |
347 |
return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize); |
348 |
} |
349 |
|
350 |
// Hash algorithm for the secondary table. This algorithm is replicated in
|
351 |
// assembler for every architecture. Returns an index into the table that
|
352 |
// is scaled by 1 << kHeapObjectTagSize.
|
353 |
static int SecondaryOffset(Name* name, Code::Flags flags, int seed) { |
354 |
// Use the seed from the primary cache in the secondary cache.
|
355 |
uint32_t name_low32bits = |
356 |
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)); |
357 |
// We always set the in_loop bit to zero when generating the lookup code
|
358 |
// so do it here too so the hash codes match.
|
359 |
uint32_t iflags = |
360 |
(static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); |
361 |
uint32_t key = (seed - name_low32bits) + iflags; |
362 |
return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize); |
363 |
} |
364 |
|
365 |
// Compute the entry for a given offset in exactly the same way as
|
366 |
// we do in generated code. We generate an hash code that already
|
367 |
// ends in Name::kHashShift 0s. Then we multiply it so it is a multiple
|
368 |
// of sizeof(Entry). This makes it easier to avoid making mistakes
|
369 |
// in the hashed offset computations.
|
370 |
static Entry* entry(Entry* table, int offset) { |
371 |
const int multiplier = sizeof(*table) >> Name::kHashShift; |
372 |
return reinterpret_cast<Entry*>(
|
373 |
reinterpret_cast<Address>(table) + offset * multiplier); |
374 |
} |
375 |
|
376 |
static const int kPrimaryTableBits = 11; |
377 |
static const int kPrimaryTableSize = (1 << kPrimaryTableBits); |
378 |
static const int kSecondaryTableBits = 9; |
379 |
static const int kSecondaryTableSize = (1 << kSecondaryTableBits); |
380 |
|
381 |
Entry primary_[kPrimaryTableSize]; |
382 |
Entry secondary_[kSecondaryTableSize]; |
383 |
Isolate* isolate_; |
384 |
|
385 |
friend class Isolate; |
386 |
friend class SCTableReference; |
387 |
|
388 |
DISALLOW_COPY_AND_ASSIGN(StubCache); |
389 |
}; |
390 |
|
391 |
|
392 |
// ------------------------------------------------------------------------
|
393 |
|
394 |
|
395 |
// Support functions for IC stubs for callbacks.
|
396 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty); |
397 |
|
398 |
|
399 |
// Support functions for IC stubs for interceptors.
|
400 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly); |
401 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad); |
402 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall); |
403 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty); |
404 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty); |
405 |
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor); |
406 |
|
407 |
|
408 |
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
|
409 |
enum IcCheckType { ELEMENT, PROPERTY };
|
410 |
|
411 |
|
412 |
// The stub compilers compile stubs for the stub cache.
|
413 |
class StubCompiler BASE_EMBEDDED { |
414 |
public:
|
415 |
explicit StubCompiler(Isolate* isolate) |
416 |
: isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { } |
417 |
|
418 |
// Functions to compile either CallIC or KeyedCallIC. The specific kind
|
419 |
// is extracted from the code flags.
|
420 |
Handle<Code> CompileCallInitialize(Code::Flags flags); |
421 |
Handle<Code> CompileCallPreMonomorphic(Code::Flags flags); |
422 |
Handle<Code> CompileCallNormal(Code::Flags flags); |
423 |
Handle<Code> CompileCallMegamorphic(Code::Flags flags); |
424 |
Handle<Code> CompileCallArguments(Code::Flags flags); |
425 |
Handle<Code> CompileCallMiss(Code::Flags flags); |
426 |
|
427 |
#ifdef ENABLE_DEBUGGER_SUPPORT
|
428 |
Handle<Code> CompileCallDebugBreak(Code::Flags flags); |
429 |
Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags); |
430 |
#endif
|
431 |
|
432 |
// Static functions for generating parts of stubs.
|
433 |
static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, |
434 |
int index,
|
435 |
Register prototype); |
436 |
|
437 |
// Generates prototype loading code that uses the objects from the
|
438 |
// context we were in when this function was called. If the context
|
439 |
// has changed, a jump to miss is performed. This ties the generated
|
440 |
// code to a particular context and so must not be used in cases
|
441 |
// where the generated code is not allowed to have references to
|
442 |
// objects from a context.
|
443 |
static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, |
444 |
int index,
|
445 |
Register prototype, |
446 |
Label* miss); |
447 |
|
448 |
static void GenerateFastPropertyLoad(MacroAssembler* masm, |
449 |
Register dst, |
450 |
Register src, |
451 |
bool inobject,
|
452 |
int index,
|
453 |
Representation representation); |
454 |
|
455 |
static void GenerateLoadArrayLength(MacroAssembler* masm, |
456 |
Register receiver, |
457 |
Register scratch, |
458 |
Label* miss_label); |
459 |
|
460 |
static void GenerateLoadStringLength(MacroAssembler* masm, |
461 |
Register receiver, |
462 |
Register scratch1, |
463 |
Register scratch2, |
464 |
Label* miss_label); |
465 |
|
466 |
static void GenerateLoadFunctionPrototype(MacroAssembler* masm, |
467 |
Register receiver, |
468 |
Register scratch1, |
469 |
Register scratch2, |
470 |
Label* miss_label); |
471 |
|
472 |
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name); |
473 |
|
474 |
// Generates code that verifies that the property holder has not changed
|
475 |
// (checking maps of objects in the prototype chain for fast and global
|
476 |
// objects or doing negative lookup for slow objects, ensures that the
|
477 |
// property cells for global objects are still empty) and checks that the map
|
478 |
// of the holder has not changed. If necessary the function also generates
|
479 |
// code for security check in case of global object holders. Helps to make
|
480 |
// sure that the current IC is still valid.
|
481 |
//
|
482 |
// The scratch and holder registers are always clobbered, but the object
|
483 |
// register is only clobbered if it the same as the holder register. The
|
484 |
// function returns a register containing the holder - either object_reg or
|
485 |
// holder_reg.
|
486 |
// The function can optionally (when save_at_depth !=
|
487 |
// kInvalidProtoDepth) save the object at the given depth by moving
|
488 |
// it to [esp + kPointerSize].
|
489 |
Register CheckPrototypes(Handle<JSObject> object, |
490 |
Register object_reg, |
491 |
Handle<JSObject> holder, |
492 |
Register holder_reg, |
493 |
Register scratch1, |
494 |
Register scratch2, |
495 |
Handle<Name> name, |
496 |
Label* miss, |
497 |
PrototypeCheckType check = CHECK_ALL_MAPS) { |
498 |
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
|
499 |
scratch2, name, kInvalidProtoDepth, miss, check); |
500 |
} |
501 |
|
502 |
Register CheckPrototypes(Handle<JSObject> object, |
503 |
Register object_reg, |
504 |
Handle<JSObject> holder, |
505 |
Register holder_reg, |
506 |
Register scratch1, |
507 |
Register scratch2, |
508 |
Handle<Name> name, |
509 |
int save_at_depth,
|
510 |
Label* miss, |
511 |
PrototypeCheckType check = CHECK_ALL_MAPS); |
512 |
|
513 |
|
514 |
protected:
|
515 |
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name); |
516 |
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name); |
517 |
|
518 |
MacroAssembler* masm() { return &masm_; }
|
519 |
void set_failure(Failure* failure) { failure_ = failure; }
|
520 |
|
521 |
static void LookupPostInterceptor(Handle<JSObject> holder, |
522 |
Handle<Name> name, |
523 |
LookupResult* lookup); |
524 |
|
525 |
Isolate* isolate() { return isolate_; }
|
526 |
Heap* heap() { return isolate()->heap(); }
|
527 |
Factory* factory() { return isolate()->factory(); }
|
528 |
|
529 |
static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code); |
530 |
|
531 |
private:
|
532 |
Isolate* isolate_; |
533 |
MacroAssembler masm_; |
534 |
Failure* failure_; |
535 |
}; |
536 |
|
537 |
|
538 |
enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
|
539 |
|
540 |
|
541 |
class BaseLoadStoreStubCompiler: public StubCompiler { |
542 |
public:
|
543 |
BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind) |
544 |
: StubCompiler(isolate), kind_(kind) { |
545 |
InitializeRegisters(); |
546 |
} |
547 |
virtual ~BaseLoadStoreStubCompiler() { } |
548 |
|
549 |
Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map, |
550 |
Handle<Code> handler, |
551 |
Handle<Name> name); |
552 |
|
553 |
Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps, |
554 |
CodeHandleList* handlers, |
555 |
Handle<Name> name, |
556 |
Code::StubType type, |
557 |
IcCheckType check); |
558 |
|
559 |
virtual void GenerateNameCheck(Handle<Name> name,
|
560 |
Register name_reg, |
561 |
Label* miss) { } |
562 |
|
563 |
static Builtins::Name MissBuiltin(Code::Kind kind) {
|
564 |
switch (kind) {
|
565 |
case Code::LOAD_IC: return Builtins::kLoadIC_Miss; |
566 |
case Code::STORE_IC: return Builtins::kStoreIC_Miss; |
567 |
case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss; |
568 |
case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss; |
569 |
default: UNREACHABLE();
|
570 |
} |
571 |
return Builtins::kLoadIC_Miss;
|
572 |
} |
573 |
|
574 |
protected:
|
575 |
virtual Register HandlerFrontendHeader(Handle<JSObject> object, |
576 |
Register object_reg, |
577 |
Handle<JSObject> holder, |
578 |
Handle<Name> name, |
579 |
Label* miss) = 0;
|
580 |
|
581 |
virtual void HandlerFrontendFooter(Handle<Name> name,
|
582 |
Label* success, |
583 |
Label* miss) = 0;
|
584 |
|
585 |
Register HandlerFrontend(Handle<JSObject> object, |
586 |
Register object_reg, |
587 |
Handle<JSObject> holder, |
588 |
Handle<Name> name, |
589 |
Label* success); |
590 |
|
591 |
Handle<Code> GetCode(Code::Kind kind, |
592 |
Code::StubType type, |
593 |
Handle<Name> name); |
594 |
|
595 |
Handle<Code> GetICCode(Code::Kind kind, |
596 |
Code::StubType type, |
597 |
Handle<Name> name, |
598 |
InlineCacheState state = MONOMORPHIC); |
599 |
Code::Kind kind() { return kind_; }
|
600 |
|
601 |
Logger::LogEventsAndTags log_kind(Handle<Code> code) { |
602 |
if (!code->is_inline_cache_stub()) return Logger::STUB_TAG; |
603 |
if (kind_ == Code::LOAD_IC) {
|
604 |
return code->ic_state() == MONOMORPHIC
|
605 |
? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG; |
606 |
} else if (kind_ == Code::KEYED_LOAD_IC) { |
607 |
return code->ic_state() == MONOMORPHIC
|
608 |
? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG; |
609 |
} else if (kind_ == Code::STORE_IC) { |
610 |
return code->ic_state() == MONOMORPHIC
|
611 |
? Logger::STORE_IC_TAG : Logger::STORE_POLYMORPHIC_IC_TAG; |
612 |
} else {
|
613 |
return code->ic_state() == MONOMORPHIC
|
614 |
? Logger::KEYED_STORE_IC_TAG : Logger::KEYED_STORE_POLYMORPHIC_IC_TAG; |
615 |
} |
616 |
} |
617 |
void JitEvent(Handle<Name> name, Handle<Code> code);
|
618 |
|
619 |
virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; }
|
620 |
virtual Register receiver() = 0;
|
621 |
virtual Register name() = 0;
|
622 |
virtual Register scratch1() = 0;
|
623 |
virtual Register scratch2() = 0;
|
624 |
virtual Register scratch3() = 0;
|
625 |
|
626 |
void InitializeRegisters();
|
627 |
|
628 |
Code::Kind kind_; |
629 |
Register* registers_; |
630 |
}; |
631 |
|
632 |
|
633 |
class LoadStubCompiler: public BaseLoadStoreStubCompiler { |
634 |
public:
|
635 |
LoadStubCompiler(Isolate* isolate, Code::Kind kind = Code::LOAD_IC) |
636 |
: BaseLoadStoreStubCompiler(isolate, kind) { } |
637 |
virtual ~LoadStubCompiler() { } |
638 |
|
639 |
Handle<Code> CompileLoadField(Handle<JSObject> object, |
640 |
Handle<JSObject> holder, |
641 |
Handle<Name> name, |
642 |
PropertyIndex index, |
643 |
Representation representation); |
644 |
|
645 |
Handle<Code> CompileLoadCallback(Handle<JSObject> object, |
646 |
Handle<JSObject> holder, |
647 |
Handle<Name> name, |
648 |
Handle<ExecutableAccessorInfo> callback); |
649 |
|
650 |
Handle<Code> CompileLoadCallback(Handle<JSObject> object, |
651 |
Handle<JSObject> holder, |
652 |
Handle<Name> name, |
653 |
const CallOptimization& call_optimization);
|
654 |
|
655 |
Handle<Code> CompileLoadConstant(Handle<JSObject> object, |
656 |
Handle<JSObject> holder, |
657 |
Handle<Name> name, |
658 |
Handle<Object> value); |
659 |
|
660 |
Handle<Code> CompileLoadInterceptor(Handle<JSObject> object, |
661 |
Handle<JSObject> holder, |
662 |
Handle<Name> name); |
663 |
|
664 |
Handle<Code> CompileLoadViaGetter(Handle<JSObject> object, |
665 |
Handle<JSObject> holder, |
666 |
Handle<Name> name, |
667 |
Handle<JSFunction> getter); |
668 |
|
669 |
static void GenerateLoadViaGetter(MacroAssembler* masm, |
670 |
Register receiver, |
671 |
Handle<JSFunction> getter); |
672 |
|
673 |
Handle<Code> CompileLoadNonexistent(Handle<JSObject> object, |
674 |
Handle<JSObject> last, |
675 |
Handle<Name> name, |
676 |
Handle<GlobalObject> global); |
677 |
|
678 |
Handle<Code> CompileLoadGlobal(Handle<JSObject> object, |
679 |
Handle<GlobalObject> holder, |
680 |
Handle<PropertyCell> cell, |
681 |
Handle<Name> name, |
682 |
bool is_dont_delete);
|
683 |
|
684 |
static Register* registers();
|
685 |
|
686 |
protected:
|
687 |
virtual Register HandlerFrontendHeader(Handle<JSObject> object, |
688 |
Register object_reg, |
689 |
Handle<JSObject> holder, |
690 |
Handle<Name> name, |
691 |
Label* miss); |
692 |
|
693 |
virtual void HandlerFrontendFooter(Handle<Name> name,
|
694 |
Label* success, |
695 |
Label* miss); |
696 |
|
697 |
Register CallbackHandlerFrontend(Handle<JSObject> object, |
698 |
Register object_reg, |
699 |
Handle<JSObject> holder, |
700 |
Handle<Name> name, |
701 |
Label* success, |
702 |
Handle<Object> callback); |
703 |
void NonexistentHandlerFrontend(Handle<JSObject> object,
|
704 |
Handle<JSObject> last, |
705 |
Handle<Name> name, |
706 |
Label* success, |
707 |
Handle<GlobalObject> global); |
708 |
|
709 |
void GenerateLoadField(Register reg,
|
710 |
Handle<JSObject> holder, |
711 |
PropertyIndex field, |
712 |
Representation representation); |
713 |
void GenerateLoadConstant(Handle<Object> value);
|
714 |
void GenerateLoadCallback(Register reg,
|
715 |
Handle<ExecutableAccessorInfo> callback); |
716 |
void GenerateLoadCallback(const CallOptimization& call_optimization); |
717 |
void GenerateLoadInterceptor(Register holder_reg,
|
718 |
Handle<JSObject> object, |
719 |
Handle<JSObject> holder, |
720 |
LookupResult* lookup, |
721 |
Handle<Name> name); |
722 |
void GenerateLoadPostInterceptor(Register reg,
|
723 |
Handle<JSObject> interceptor_holder, |
724 |
Handle<Name> name, |
725 |
LookupResult* lookup); |
726 |
|
727 |
virtual Register receiver() { return registers_[0]; } |
728 |
virtual Register name() { return registers_[1]; } |
729 |
virtual Register scratch1() { return registers_[2]; } |
730 |
virtual Register scratch2() { return registers_[3]; } |
731 |
virtual Register scratch3() { return registers_[4]; } |
732 |
Register scratch4() { return registers_[5]; } |
733 |
}; |
734 |
|
735 |
|
736 |
class KeyedLoadStubCompiler: public LoadStubCompiler { |
737 |
public:
|
738 |
explicit KeyedLoadStubCompiler(Isolate* isolate) |
739 |
: LoadStubCompiler(isolate, Code::KEYED_LOAD_IC) { } |
740 |
|
741 |
Handle<Code> CompileLoadElement(Handle<Map> receiver_map); |
742 |
|
743 |
void CompileElementHandlers(MapHandleList* receiver_maps,
|
744 |
CodeHandleList* handlers); |
745 |
|
746 |
static void GenerateLoadDictionaryElement(MacroAssembler* masm); |
747 |
|
748 |
protected:
|
749 |
static Register* registers();
|
750 |
|
751 |
private:
|
752 |
virtual void GenerateNameCheck(Handle<Name> name,
|
753 |
Register name_reg, |
754 |
Label* miss); |
755 |
friend class BaseLoadStoreStubCompiler; |
756 |
}; |
757 |
|
758 |
|
759 |
class StoreStubCompiler: public BaseLoadStoreStubCompiler { |
760 |
public:
|
761 |
StoreStubCompiler(Isolate* isolate, |
762 |
StrictModeFlag strict_mode, |
763 |
Code::Kind kind = Code::STORE_IC) |
764 |
: BaseLoadStoreStubCompiler(isolate, kind), |
765 |
strict_mode_(strict_mode) { } |
766 |
|
767 |
virtual ~StoreStubCompiler() { } |
768 |
|
769 |
Handle<Code> CompileStoreTransition(Handle<JSObject> object, |
770 |
LookupResult* lookup, |
771 |
Handle<Map> transition, |
772 |
Handle<Name> name); |
773 |
|
774 |
Handle<Code> CompileStoreField(Handle<JSObject> object, |
775 |
LookupResult* lookup, |
776 |
Handle<Name> name); |
777 |
|
778 |
void GenerateNegativeHolderLookup(MacroAssembler* masm,
|
779 |
Handle<JSObject> holder, |
780 |
Register holder_reg, |
781 |
Handle<Name> name, |
782 |
Label* miss); |
783 |
|
784 |
void GenerateStoreTransition(MacroAssembler* masm,
|
785 |
Handle<JSObject> object, |
786 |
LookupResult* lookup, |
787 |
Handle<Map> transition, |
788 |
Handle<Name> name, |
789 |
Register receiver_reg, |
790 |
Register name_reg, |
791 |
Register value_reg, |
792 |
Register scratch1, |
793 |
Register scratch2, |
794 |
Register scratch3, |
795 |
Label* miss_label, |
796 |
Label* slow); |
797 |
|
798 |
void GenerateStoreField(MacroAssembler* masm,
|
799 |
Handle<JSObject> object, |
800 |
LookupResult* lookup, |
801 |
Register receiver_reg, |
802 |
Register name_reg, |
803 |
Register value_reg, |
804 |
Register scratch1, |
805 |
Register scratch2, |
806 |
Label* miss_label); |
807 |
|
808 |
Handle<Code> CompileStoreCallback(Handle<JSObject> object, |
809 |
Handle<JSObject> holder, |
810 |
Handle<Name> name, |
811 |
Handle<ExecutableAccessorInfo> callback); |
812 |
|
813 |
Handle<Code> CompileStoreCallback(Handle<JSObject> object, |
814 |
Handle<JSObject> holder, |
815 |
Handle<Name> name, |
816 |
const CallOptimization& call_optimization);
|
817 |
|
818 |
static void GenerateStoreViaSetter(MacroAssembler* masm, |
819 |
Handle<JSFunction> setter); |
820 |
|
821 |
Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, |
822 |
Handle<JSObject> holder, |
823 |
Handle<Name> name, |
824 |
Handle<JSFunction> setter); |
825 |
|
826 |
Handle<Code> CompileStoreInterceptor(Handle<JSObject> object, |
827 |
Handle<Name> name); |
828 |
|
829 |
static Builtins::Name SlowBuiltin(Code::Kind kind) {
|
830 |
switch (kind) {
|
831 |
case Code::STORE_IC: return Builtins::kStoreIC_Slow; |
832 |
case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow; |
833 |
default: UNREACHABLE();
|
834 |
} |
835 |
return Builtins::kStoreIC_Slow;
|
836 |
} |
837 |
|
838 |
protected:
|
839 |
virtual Register HandlerFrontendHeader(Handle<JSObject> object, |
840 |
Register object_reg, |
841 |
Handle<JSObject> holder, |
842 |
Handle<Name> name, |
843 |
Label* miss); |
844 |
|
845 |
virtual void HandlerFrontendFooter(Handle<Name> name,
|
846 |
Label* success, |
847 |
Label* miss); |
848 |
void GenerateRestoreName(MacroAssembler* masm,
|
849 |
Label* label, |
850 |
Handle<Name> name); |
851 |
|
852 |
virtual Register receiver() { return registers_[0]; } |
853 |
virtual Register name() { return registers_[1]; } |
854 |
Register value() { return registers_[2]; } |
855 |
virtual Register scratch1() { return registers_[3]; } |
856 |
virtual Register scratch2() { return registers_[4]; } |
857 |
virtual Register scratch3() { return registers_[5]; } |
858 |
StrictModeFlag strict_mode() { return strict_mode_; }
|
859 |
virtual Code::ExtraICState extra_state() { return strict_mode_; }
|
860 |
|
861 |
protected:
|
862 |
static Register* registers();
|
863 |
|
864 |
private:
|
865 |
StrictModeFlag strict_mode_; |
866 |
friend class BaseLoadStoreStubCompiler; |
867 |
}; |
868 |
|
869 |
|
870 |
class KeyedStoreStubCompiler: public StoreStubCompiler { |
871 |
public:
|
872 |
KeyedStoreStubCompiler(Isolate* isolate, |
873 |
StrictModeFlag strict_mode, |
874 |
KeyedAccessStoreMode store_mode) |
875 |
: StoreStubCompiler(isolate, strict_mode, Code::KEYED_STORE_IC), |
876 |
store_mode_(store_mode) { } |
877 |
|
878 |
Handle<Code> CompileStoreElement(Handle<Map> receiver_map); |
879 |
|
880 |
Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps, |
881 |
CodeHandleList* handler_stubs, |
882 |
MapHandleList* transitioned_maps); |
883 |
|
884 |
Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps); |
885 |
|
886 |
static void GenerateStoreDictionaryElement(MacroAssembler* masm); |
887 |
|
888 |
protected:
|
889 |
virtual Code::ExtraICState extra_state() { |
890 |
return Code::ComputeExtraICState(store_mode_, strict_mode());
|
891 |
} |
892 |
static Register* registers();
|
893 |
|
894 |
private:
|
895 |
Register transition_map() { |
896 |
return registers()[3]; |
897 |
} |
898 |
|
899 |
virtual void GenerateNameCheck(Handle<Name> name,
|
900 |
Register name_reg, |
901 |
Label* miss); |
902 |
KeyedAccessStoreMode store_mode_; |
903 |
friend class BaseLoadStoreStubCompiler; |
904 |
}; |
905 |
|
906 |
|
907 |
// Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call
|
908 |
// IC stubs.
|
909 |
#define CUSTOM_CALL_IC_GENERATORS(V) \
|
910 |
V(ArrayPush) \ |
911 |
V(ArrayPop) \ |
912 |
V(StringCharCodeAt) \ |
913 |
V(StringCharAt) \ |
914 |
V(StringFromCharCode) \ |
915 |
V(MathFloor) \ |
916 |
V(MathAbs) \ |
917 |
V(ArrayCode) |
918 |
|
919 |
|
920 |
#define SITE_SPECIFIC_CALL_GENERATORS(V) \
|
921 |
V(ArrayCode) |
922 |
|
923 |
|
924 |
class CallStubCompiler: public StubCompiler { |
925 |
public:
|
926 |
CallStubCompiler(Isolate* isolate, |
927 |
int argc,
|
928 |
Code::Kind kind, |
929 |
Code::ExtraICState extra_state, |
930 |
InlineCacheHolderFlag cache_holder = OWN_MAP); |
931 |
|
932 |
Handle<Code> CompileCallField(Handle<JSObject> object, |
933 |
Handle<JSObject> holder, |
934 |
PropertyIndex index, |
935 |
Handle<Name> name); |
936 |
|
937 |
void CompileHandlerFrontend(Handle<Object> object,
|
938 |
Handle<JSObject> holder, |
939 |
Handle<Name> name, |
940 |
CheckType check, |
941 |
Label* success); |
942 |
|
943 |
void CompileHandlerBackend(Handle<JSFunction> function);
|
944 |
|
945 |
Handle<Code> CompileCallConstant(Handle<Object> object, |
946 |
Handle<JSObject> holder, |
947 |
Handle<Name> name, |
948 |
CheckType check, |
949 |
Handle<JSFunction> function); |
950 |
|
951 |
Handle<Code> CompileCallInterceptor(Handle<JSObject> object, |
952 |
Handle<JSObject> holder, |
953 |
Handle<Name> name); |
954 |
|
955 |
Handle<Code> CompileCallGlobal(Handle<JSObject> object, |
956 |
Handle<GlobalObject> holder, |
957 |
Handle<PropertyCell> cell, |
958 |
Handle<JSFunction> function, |
959 |
Handle<Name> name); |
960 |
|
961 |
static bool HasCustomCallGenerator(Handle<JSFunction> function); |
962 |
static bool CanBeCached(Handle<JSFunction> function); |
963 |
|
964 |
private:
|
965 |
// Compiles a custom call constant/global IC. For constant calls cell is
|
966 |
// NULL. Returns an empty handle if there is no custom call code for the
|
967 |
// given function.
|
968 |
Handle<Code> CompileCustomCall(Handle<Object> object, |
969 |
Handle<JSObject> holder, |
970 |
Handle<Cell> cell, |
971 |
Handle<JSFunction> function, |
972 |
Handle<String> name, |
973 |
Code::StubType type); |
974 |
|
975 |
#define DECLARE_CALL_GENERATOR(name) \
|
976 |
Handle<Code> Compile##name##Call(Handle<Object> object, \ |
977 |
Handle<JSObject> holder, \ |
978 |
Handle<Cell> cell, \ |
979 |
Handle<JSFunction> function, \ |
980 |
Handle<String> fname, \ |
981 |
Code::StubType type); |
982 |
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR) |
983 |
#undef DECLARE_CALL_GENERATOR
|
984 |
|
985 |
Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
|
986 |
Handle<Object> object, |
987 |
Handle<JSObject> holder, |
988 |
Handle<Cell> cell, |
989 |
Handle<JSFunction> function, |
990 |
Handle<String> name); |
991 |
|
992 |
Handle<Code> GetCode(Code::StubType type, Handle<Name> name); |
993 |
Handle<Code> GetCode(Handle<JSFunction> function); |
994 |
|
995 |
const ParameterCount& arguments() { return arguments_; } |
996 |
|
997 |
void GenerateNameCheck(Handle<Name> name, Label* miss);
|
998 |
|
999 |
void GenerateGlobalReceiverCheck(Handle<JSObject> object,
|
1000 |
Handle<JSObject> holder, |
1001 |
Handle<Name> name, |
1002 |
Label* miss); |
1003 |
|
1004 |
// Generates code to load the function from the cell checking that
|
1005 |
// it still contains the same function.
|
1006 |
void GenerateLoadFunctionFromCell(Handle<Cell> cell,
|
1007 |
Handle<JSFunction> function, |
1008 |
Label* miss); |
1009 |
|
1010 |
// Generates a jump to CallIC miss stub.
|
1011 |
void GenerateMissBranch();
|
1012 |
|
1013 |
const ParameterCount arguments_;
|
1014 |
const Code::Kind kind_;
|
1015 |
const Code::ExtraICState extra_state_;
|
1016 |
const InlineCacheHolderFlag cache_holder_;
|
1017 |
}; |
1018 |
|
1019 |
|
1020 |
// Holds information about possible function call optimizations.
|
1021 |
class CallOptimization BASE_EMBEDDED { |
1022 |
public:
|
1023 |
explicit CallOptimization(LookupResult* lookup); |
1024 |
|
1025 |
explicit CallOptimization(Handle<JSFunction> function); |
1026 |
|
1027 |
bool is_constant_call() const { |
1028 |
return !constant_function_.is_null();
|
1029 |
} |
1030 |
|
1031 |
Handle<JSFunction> constant_function() const {
|
1032 |
ASSERT(is_constant_call()); |
1033 |
return constant_function_;
|
1034 |
} |
1035 |
|
1036 |
bool is_simple_api_call() const { |
1037 |
return is_simple_api_call_;
|
1038 |
} |
1039 |
|
1040 |
Handle<FunctionTemplateInfo> expected_receiver_type() const {
|
1041 |
ASSERT(is_simple_api_call()); |
1042 |
return expected_receiver_type_;
|
1043 |
} |
1044 |
|
1045 |
Handle<CallHandlerInfo> api_call_info() const {
|
1046 |
ASSERT(is_simple_api_call()); |
1047 |
return api_call_info_;
|
1048 |
} |
1049 |
|
1050 |
// Returns the depth of the object having the expected type in the
|
1051 |
// prototype chain between the two arguments.
|
1052 |
int GetPrototypeDepthOfExpectedType(Handle<JSObject> object,
|
1053 |
Handle<JSObject> holder) const;
|
1054 |
|
1055 |
bool IsCompatibleReceiver(Object* receiver) {
|
1056 |
ASSERT(is_simple_api_call()); |
1057 |
if (expected_receiver_type_.is_null()) return true; |
1058 |
return receiver->IsInstanceOf(*expected_receiver_type_);
|
1059 |
} |
1060 |
|
1061 |
private:
|
1062 |
void Initialize(Handle<JSFunction> function);
|
1063 |
|
1064 |
// Determines whether the given function can be called using the
|
1065 |
// fast api call builtin.
|
1066 |
void AnalyzePossibleApiFunction(Handle<JSFunction> function);
|
1067 |
|
1068 |
Handle<JSFunction> constant_function_; |
1069 |
bool is_simple_api_call_;
|
1070 |
Handle<FunctionTemplateInfo> expected_receiver_type_; |
1071 |
Handle<CallHandlerInfo> api_call_info_; |
1072 |
}; |
1073 |
|
1074 |
|
1075 |
} } // namespace v8::internal
|
1076 |
|
1077 |
#endif // V8_STUB_CACHE_H_ |