blob: a571f4f6bbbefc562f7f43f5a7c16a649c7fc60f [file] [log] [blame]
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_IC_HANDLER_COMPILER_H_
#define V8_IC_HANDLER_COMPILER_H_
#include "src/ic/access-compiler.h"
#include "src/ic/ic-state.h"
namespace v8 {
namespace internal {
class CallOptimization;
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING };
class PropertyHandlerCompiler : public PropertyAccessCompiler {
public:
static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind,
CacheHolderFlag cache_holder);
protected:
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map,
Handle<JSObject> holder, CacheHolderFlag cache_holder)
: PropertyAccessCompiler(isolate, kind, cache_holder),
map_(map),
holder_(holder) {}
virtual ~PropertyHandlerCompiler() {}
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
Label* miss, ReturnHolder return_what) {
UNREACHABLE();
return receiver();
}
virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); }
// Frontend loads from receiver(), returns holder register which may be
// different.
Register Frontend(Handle<Name> name);
void NonexistentFrontendHeader(Handle<Name> name, Label* miss,
Register scratch1, Register scratch2);
// When FLAG_vector_ics is true, handlers that have the possibility of missing
// will need to save and pass these to miss handlers.
void PushVectorAndSlot() { PushVectorAndSlot(vector(), slot()); }
void PushVectorAndSlot(Register vector, Register slot);
void PopVectorAndSlot() { PopVectorAndSlot(vector(), slot()); }
void PopVectorAndSlot(Register vector, Register slot);
void DiscardVectorAndSlot();
// TODO(verwaest): Make non-static.
static void GenerateApiAccessorCall(MacroAssembler* masm,
const CallOptimization& optimization,
Handle<Map> receiver_map,
Register receiver, Register scratch,
bool is_store, Register store_parameter,
Register accessor_holder,
int accessor_index);
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name, Register r0,
Register r1);
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<JSGlobalObject> global,
Handle<Name> name, Register scratch,
Label* miss);
// Generates code that verifies that the property holder has not changed
// (checking maps of objects in the prototype chain for fast and global
// objects or doing negative lookup for slow objects, ensures that the
// property cells for global objects are still empty) and checks that the map
// of the holder has not changed. If necessary the function also generates
// code for security check in case of global object holders. Helps to make
// sure that the current IC is still valid.
//
// The scratch and holder registers are always clobbered, but the object
// register is only clobbered if it the same as the holder register. The
// function returns a register containing the holder - either object_reg or
// holder_reg.
Register CheckPrototypes(Register object_reg, Register holder_reg,
Register scratch1, Register scratch2,
Handle<Name> name, Label* miss,
PrototypeCheckType check, ReturnHolder return_what);
Handle<Code> GetCode(Code::Kind kind, Handle<Name> name);
void set_holder(Handle<JSObject> holder) { holder_ = holder; }
Handle<Map> map() const { return map_; }
void set_map(Handle<Map> map) { map_ = map; }
Handle<JSObject> holder() const { return holder_; }
private:
Handle<Map> map_;
Handle<JSObject> holder_;
};
class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
public:
NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map,
Handle<JSObject> holder,
CacheHolderFlag cache_holder)
: PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder,
cache_holder) {}
virtual ~NamedLoadHandlerCompiler() {}
Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index);
Handle<Code> CompileLoadCallback(Handle<Name> name,
Handle<AccessorInfo> callback);
Handle<Code> CompileLoadCallback(Handle<Name> name,
const CallOptimization& call_optimization,
int accessor_index);
Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index);
// The LookupIterator is used to perform a lookup behind the interceptor. If
// the iterator points to a LookupIterator::PROPERTY, its access will be
// inlined.
Handle<Code> CompileLoadInterceptor(LookupIterator* it);
Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index,
int expected_arguments);
Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
bool is_configurable);
// Static interface
static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
Handle<Map> map);
static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map,
Register receiver, Register holder,
int accessor_index, int expected_arguments,
Register scratch);
static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
no_reg);
}
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Label* miss_label);
// These constants describe the structure of the interceptor arguments on the
// stack. The arguments are pushed by the (platform-specific)
// PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
// LoadWithInterceptor.
static const int kInterceptorArgsNameIndex = 0;
static const int kInterceptorArgsThisIndex = 1;
static const int kInterceptorArgsHolderIndex = 2;
static const int kInterceptorArgsLength = 3;
protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
Label* miss, ReturnHolder return_what);
virtual void FrontendFooter(Handle<Name> name, Label* miss);
private:
Handle<Code> CompileLoadNonexistent(Handle<Name> name);
void GenerateLoadConstant(Handle<Object> value);
void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback);
void GenerateLoadCallback(const CallOptimization& call_optimization,
Handle<Map> receiver_map);
// Helper emits no code if vector-ics are disabled.
void InterceptorVectorSlotPush(Register holder_reg);
enum PopMode { POP, DISCARD };
void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP);
void GenerateLoadInterceptor(Register holder_reg);
void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
Register holder_reg);
void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
// Generates prototype loading code that uses the objects from the
// context we were in when this function was called. If the context
// has changed, a jump to miss is performed. This ties the generated
// code to a particular context and so must not be used in cases
// where the generated code is not allowed to have references to
// objects from a context.
static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
int index,
Register prototype,
Label* miss);
Register scratch3() { return registers_[4]; }
};
class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
public:
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
Handle<JSObject> holder)
: PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
kCacheOnReceiver) {}
virtual ~NamedStoreHandlerCompiler() {}
Handle<Code> CompileStoreTransition(Handle<Map> transition,
Handle<Name> name);
Handle<Code> CompileStoreField(LookupIterator* it);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
Handle<AccessorInfo> callback,
LanguageMode language_mode);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
const CallOptimization& call_optimization,
int accessor_index);
Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
int accessor_index,
int expected_arguments);
static void GenerateStoreViaSetter(MacroAssembler* masm, Handle<Map> map,
Register receiver, Register holder,
int accessor_index, int expected_arguments,
Register scratch);
static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) {
GenerateStoreViaSetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
no_reg);
}
static void GenerateSlow(MacroAssembler* masm);
protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
Label* miss, ReturnHolder return_what);
virtual void FrontendFooter(Handle<Name> name, Label* miss);
void GenerateRestoreName(Label* label, Handle<Name> name);
// Pop the vector and slot into appropriate registers, moving the map in
// the process. (This is an accomodation for register pressure on ia32).
void RearrangeVectorAndSlot(Register current_map, Register destination_map);
private:
void GenerateRestoreName(Handle<Name> name);
void GenerateRestoreMap(Handle<Map> transition, Register map_reg,
Register scratch, Label* miss);
void GenerateConstantCheck(Register map_reg, int descriptor,
Register value_reg, Register scratch,
Label* miss_label);
bool RequiresFieldTypeChecks(FieldType* field_type) const;
void GenerateFieldTypeChecks(FieldType* field_type, Register value_reg,
Label* miss_label);
static Builtins::Name SlowBuiltin(Code::Kind kind) {
switch (kind) {
case Code::STORE_IC:
return Builtins::kStoreIC_Slow;
case Code::KEYED_STORE_IC:
return Builtins::kKeyedStoreIC_Slow;
default:
UNREACHABLE();
}
return Builtins::kStoreIC_Slow;
}
static Register value();
};
class ElementHandlerCompiler : public PropertyHandlerCompiler {
public:
explicit ElementHandlerCompiler(Isolate* isolate)
: PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
Handle<Map>::null(), Handle<JSObject>::null(),
kCacheOnReceiver) {}
virtual ~ElementHandlerCompiler() {}
void CompileElementHandlers(MapHandleList* receiver_maps,
CodeHandleList* handlers);
static void GenerateStoreSlow(MacroAssembler* masm);
};
} // namespace internal
} // namespace v8
#endif // V8_IC_HANDLER_COMPILER_H_