Commit 93f2ed48 authored by verwaest@chromium.org's avatar verwaest@chromium.org

Handle all object types (minus smi) in load/store ICs

R=ulan@chromium.org

Review URL: https://chromiumcodereview.appspot.com/62953007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17755 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 883a5c80
......@@ -1298,34 +1298,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
}
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ b(success);
Label success;
__ b(&success);
__ bind(miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ b(success);
Label success;
__ b(&success);
GenerateRestoreName(masm(), miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
Register LoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
Handle<Object> callback) {
Label miss;
......@@ -1362,7 +1361,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
__ b(ne, &miss);
}
HandlerFrontendFooter(name, success, &miss);
HandlerFrontendFooter(name, &miss);
return reg;
}
......@@ -1468,7 +1467,7 @@ void LoadStubCompiler::GenerateLoadCallback(
void LoadStubCompiler::GenerateLoadInterceptor(
Register holder_reg,
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
Handle<Name> name) {
......@@ -2539,11 +2538,23 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
}
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
// Check that the object is a boolean.
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(object, ip);
__ b(eq, &success);
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ cmp(object, ip);
__ b(ne, miss);
__ bind(&success);
}
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
CheckType check,
Label* success) {
CheckType check) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
......@@ -2619,15 +2630,8 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
break;
}
case BOOLEAN_CHECK: {
Label fast;
// Check that the object is a boolean.
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r1, ip);
__ b(eq, &fast);
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ cmp(r1, ip);
__ b(ne, &miss);
__ bind(&fast);
GenerateBooleanCheck(r1, &miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
......@@ -2638,11 +2642,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
}
}
__ b(success);
Label success;
__ b(&success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
__ bind(&success);
}
......@@ -2671,10 +2678,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerFrontend(object, holder, name, check);
CompileHandlerBackend(function);
// Return the generated code.
......@@ -2785,9 +2789,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
// Stub never generated for non-global objects that require access checks.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
......@@ -2813,9 +2815,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
const CallOptimization& call_optimization) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
Register values[] = { value() };
GenerateFastApiCall(
......@@ -2910,15 +2910,12 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Handle<JSGlobalObject> global) {
Label success;
NonexistentHandlerFrontend(object, last, name, global);
NonexistentHandlerFrontend(object, last, name, &success, global);
__ bind(&success);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
......@@ -3013,12 +3010,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<Object> object,
Handle<GlobalObject> global,
Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
Label miss;
HandlerFrontendHeader(object, receiver(), global, name, &miss);
......@@ -3033,8 +3030,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
__ b(eq, &miss);
}
HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
HandlerFrontendFooter(name, &miss);
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3);
......
......@@ -1267,34 +1267,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
}
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
Label success;
__ jmp(&success);
__ bind(miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
Label success;
__ jmp(&success);
GenerateRestoreName(masm(), miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
Register LoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
Handle<Object> callback) {
Label miss;
......@@ -1344,7 +1343,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
__ j(not_equal, &miss);
}
HandlerFrontendFooter(name, success, &miss);
HandlerFrontendFooter(name, &miss);
return reg;
}
......@@ -1450,7 +1449,7 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
void LoadStubCompiler::GenerateLoadInterceptor(
Register holder_reg,
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
Handle<Name> name) {
......@@ -2613,11 +2612,21 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
}
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
// Check that the object is a boolean.
__ cmp(object, factory()->true_value());
__ j(equal, &success);
__ cmp(object, factory()->false_value());
__ j(not_equal, miss);
__ bind(&success);
}
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
CheckType check,
Label* success) {
CheckType check) {
// ----------- S t a t e -------------
// -- ecx : name
// -- esp[0] : return address
......@@ -2696,13 +2705,7 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
break;
}
case BOOLEAN_CHECK: {
Label fast;
// Check that the object is a boolean.
__ cmp(edx, factory()->true_value());
__ j(equal, &fast);
__ cmp(edx, factory()->false_value());
__ j(not_equal, &miss);
__ bind(&fast);
GenerateBooleanCheck(edx, &miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
......@@ -2713,11 +2716,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
}
}
__ jmp(success);
Label success;
__ jmp(&success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
__ bind(&success);
}
......@@ -2747,10 +2753,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerFrontend(object, holder, name, check);
CompileHandlerBackend(function);
// Return the generated code.
......@@ -2885,9 +2888,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
__ pop(scratch1()); // remove the return address
__ push(receiver());
......@@ -2911,9 +2912,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
const CallOptimization& call_optimization) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
Register values[] = { value() };
GenerateFastApiCall(
......@@ -3020,15 +3019,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Handle<JSGlobalObject> global) {
Label success;
NonexistentHandlerFrontend(object, last, name, global);
NonexistentHandlerFrontend(object, last, name, &success, global);
__ bind(&success);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ mov(eax, isolate()->factory()->undefined_value());
......@@ -3118,12 +3114,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<Object> object,
Handle<GlobalObject> global,
Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
Label miss;
HandlerFrontendHeader(object, receiver(), global, name, &miss);
// Get the value from the cell.
......@@ -3143,8 +3139,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
__ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
}
HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
HandlerFrontendFooter(name, &miss);
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->named_load_global_stub(), 1);
......
......@@ -100,8 +100,7 @@ void IC::SetTargetAtAddress(Address address, Code* target) {
}
InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object,
JSObject* holder) {
InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object) {
if (object->IsJSObject()) return OWN_MAP;
// If the object is a value, we use the prototype map for the cache.
......@@ -111,13 +110,12 @@ InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object,
}
JSObject* IC::GetCodeCacheHolder(Isolate* isolate,
HeapObject* IC::GetCodeCacheHolder(Isolate* isolate,
Object* object,
InlineCacheHolderFlag holder) {
Object* map_owner =
holder == OWN_MAP ? object : object->GetPrototype(isolate);
ASSERT(map_owner->IsJSObject());
return JSObject::cast(map_owner);
return HeapObject::cast(map_owner);
}
......
......@@ -1005,7 +1005,7 @@ void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<String> name) {
if (!handler->is_handler()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
receiver, handler, name, strict_mode());
name, receiver, handler, strict_mode());
set_target(*ic);
}
......@@ -1035,9 +1035,13 @@ bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
}
void IC::PatchCache(Handle<HeapObject> receiver,
void IC::PatchCache(Handle<Object> object,
Handle<String> name,
Handle<Code> code) {
// TODO(verwaest): Handle smi here as well.
if (!object->IsHeapObject()) return;
Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
......@@ -1097,13 +1101,6 @@ Handle<Code> LoadIC::SimpleFieldLoad(int offset,
void LoadIC::UpdateCaches(LookupResult* lookup,
Handle<Object> object,
Handle<String> name) {
// TODO(verwaest): It would be nice to support loading fields from smis as
// well. For now just fail to update the cache.
if (!object->IsHeapObject()) return;
Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
Handle<Code> code;
if (state() == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
......@@ -1111,27 +1108,23 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
set_target(*pre_monomorphic_stub());
TRACE_IC("LoadIC", name);
return;
} else if (!lookup->IsCacheable()) {
}
Handle<Code> code;
if (!lookup->IsCacheable()) {
// Bail out if the result is not cacheable.
code = slow_stub();
} else if (object->IsString() &&
name->Equals(isolate()->heap()->length_string())) {
int length_index = String::kLengthOffset / kPointerSize;
code = SimpleFieldLoad(length_index);
} else if (!object->IsJSObject()) {
// TODO(jkummerow): It would be nice to support non-JSObjects in
// ComputeLoadHandler, then we wouldn't need to go generic here.
code = slow_stub();
} else if (!lookup->IsProperty()) {
code = kind() == Code::LOAD_IC
? isolate()->stub_cache()->ComputeLoadNonexistent(
name, Handle<JSObject>::cast(receiver))
: slow_stub();
if (kind() == Code::LOAD_IC) {
code = isolate()->stub_cache()->ComputeLoadNonexistent(name, object);
} else {
code = slow_stub();
}
} else {
code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
code = ComputeHandler(lookup, object, name);
}
PatchCache(receiver, name, code);
PatchCache(object, name, code);
TRACE_IC("LoadIC", name);
}
......@@ -1144,18 +1137,22 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
Handle<Code> IC::ComputeHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object);
Handle<HeapObject> stub_holder(GetCodeCacheHolder(
isolate(), *object, cache_holder));
Handle<Code> code = isolate()->stub_cache()->FindHandler(
name, receiver, kind());
name, stub_holder, kind(), cache_holder, strict_mode());
if (!code.is_null()) return code;
code = CompileHandler(lookup, receiver, name, value);
code = CompileHandler(lookup, object, name, value, cache_holder);
ASSERT(code->is_handler());
if (code->type() != Code::NORMAL) {
HeapObject::UpdateMapCodeCache(receiver, name, code);
HeapObject::UpdateMapCodeCache(stub_holder, name, code);
}
return code;
......@@ -1163,29 +1160,35 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> unused) {
Handle<Object> unused,
InlineCacheHolderFlag cache_holder) {
if (object->IsString() && name->Equals(isolate()->heap()->length_string())) {
int length_index = String::kLengthOffset / kPointerSize;
return SimpleFieldLoad(length_index);
}
Handle<JSObject> holder(lookup->holder());
LoadStubCompiler compiler(isolate(), kind());
LoadStubCompiler compiler(isolate(), cache_holder, kind());
switch (lookup->type()) {
case FIELD: {
PropertyIndex field = lookup->GetFieldIndex();
if (receiver.is_identical_to(holder)) {
if (object.is_identical_to(holder)) {
return SimpleFieldLoad(field.translate(holder),
field.is_inobject(holder),
lookup->representation());
}
return compiler.CompileLoadField(
receiver, holder, name, field, lookup->representation());
object, holder, name, field, lookup->representation());
}
case CONSTANT: {
Handle<Object> constant(lookup->GetConstant(), isolate());
// TODO(2803): Don't compute a stub for cons strings because they cannot
// be embedded into code.
if (constant->IsConsString()) break;
return compiler.CompileLoadConstant(receiver, holder, name, constant);
return compiler.CompileLoadConstant(object, holder, name, constant);
}
case NORMAL:
if (kind() != Code::LOAD_IC) break;
......@@ -1194,26 +1197,31 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
Handle<Code> code = compiler.CompileLoadGlobal(
receiver, global, cell, name, lookup->IsDontDelete());
object, global, cell, name, lookup->IsDontDelete());
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
HeapObject::UpdateMapCodeCache(receiver, name, code);
Handle<HeapObject> stub_holder(GetCodeCacheHolder(
isolate(), *object, cache_holder));
HeapObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the receiver for the stub to be
// property must be found in the object for the stub to be
// applicable.
if (!holder.is_identical_to(receiver)) break;
if (!object.is_identical_to(holder)) break;
return isolate()->builtins()->LoadIC_Normal();
case CALLBACKS: {
// Use simple field loads for some well-known callback properties.
int object_offset;
Handle<Map> map(receiver->map());
if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
PropertyIndex index =
PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
return compiler.CompileLoadField(
receiver, receiver, name, index, Representation::Tagged());
if (object->IsJSObject()) {
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<Map> map(receiver->map());
if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
PropertyIndex index =
PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
return compiler.CompileLoadField(
receiver, receiver, name, index, Representation::Tagged());
}
}
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
......@@ -1221,8 +1229,8 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
Handle<ExecutableAccessorInfo> info =
Handle<ExecutableAccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->getter()) == 0) break;
if (!info->IsCompatibleReceiver(*receiver)) break;
return compiler.CompileLoadCallback(receiver, holder, name, info);
if (!info->IsCompatibleReceiver(*object)) break;
return compiler.CompileLoadCallback(object, holder, name, info);
} else if (callback->IsAccessorPair()) {
Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
isolate());
......@@ -1230,13 +1238,20 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
if (holder->IsGlobalObject()) break;
if (!holder->HasFastProperties()) break;
Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
if (!object->IsJSObject() &&
!function->IsBuiltin() &&
function->shared()->is_classic_mode()) {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
break;
}
CallOptimization call_optimization(function);
if (call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiver(*receiver)) {
call_optimization.IsCompatibleReceiver(*object)) {
return compiler.CompileLoadCallback(
receiver, holder, name, call_optimization);
object, holder, name, call_optimization);
}
return compiler.CompileLoadViaGetter(receiver, holder, name, function);
return compiler.CompileLoadViaGetter(object, holder, name, function);
}
// TODO(dcarney): Handle correctly.
if (callback->IsDeclaredAccessorInfo()) break;
......@@ -1246,7 +1261,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
}
case INTERCEPTOR:
ASSERT(HasInterceptorGetter(*holder));
return compiler.CompileLoadInterceptor(receiver, holder, name);
return compiler.CompileLoadInterceptor(object, holder, name);
default:
break;
}
......@@ -1582,9 +1597,14 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
Handle<Object> value,
InlineCacheHolderFlag cache_holder) {
ASSERT(cache_holder == OWN_MAP);
// This is currently guaranteed by checks in StoreIC::Store.
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<JSObject> holder(lookup->holder());
StoreStubCompiler compiler(isolate(), strict_mode(), kind());
switch (lookup->type()) {
......
......@@ -132,11 +132,13 @@ class IC {
// Determines which map must be used for keeping the code stub.
// These methods should not be called with undefined or null.
static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object,
JSObject* holder);
static inline JSObject* GetCodeCacheHolder(Isolate* isolate,
Object* object,
InlineCacheHolderFlag holder);
static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
// TODO(verwaest): This currently returns a HeapObject rather than JSObject*
// since loading the IC for loading the length from strings are stored on
// the string map directly, rather than on the JSObject-typed prototype.
static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
Object* object,
InlineCacheHolderFlag holder);
static bool IsCleared(Code* code) {
InlineCacheState state = code->ic_state();
......@@ -180,13 +182,14 @@ class IC {
// Compute the handler either by compiling or by retrieving a cached version.
Handle<Code> ComputeHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> value = Handle<Code>::null());
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
Handle<Object> value,
InlineCacheHolderFlag cache_holder) {
UNREACHABLE();
return Handle<Code>::null();
}
......@@ -200,7 +203,7 @@ class IC {
void CopyICToMegamorphicCache(Handle<String> name);
bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
void PatchCache(Handle<HeapObject> receiver,
void PatchCache(Handle<Object> object,
Handle<String> name,
Handle<Code> code);
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
......@@ -422,9 +425,10 @@ class LoadIC: public IC {
Handle<String> name);
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> unused);
Handle<Object> unused,
InlineCacheHolderFlag cache_holder);
private:
// Stub accessors.
......@@ -617,9 +621,10 @@ class StoreIC: public IC {
Handle<String> name,
Handle<Object> value);
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<Object> object,
Handle<String> name,
Handle<Object> value);
Handle<Object> value,
InlineCacheHolderFlag cache_holder);
private:
void set_target(Code* code) {
......
......@@ -4185,9 +4185,9 @@ Code::Flags Code::ComputeFlags(Kind kind,
Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
ExtraICState extra_ic_state,
InlineCacheHolderFlag holder,
StubType type,
int argc,
InlineCacheHolderFlag holder) {
int argc) {
return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, argc, holder);
}
......
......@@ -5253,9 +5253,9 @@ class Code: public HeapObject {
static inline Flags ComputeMonomorphicFlags(
Kind kind,
ExtraICState extra_ic_state = kNoExtraICState,
InlineCacheHolderFlag holder = OWN_MAP,
StubType type = NORMAL,
int argc = -1,
InlineCacheHolderFlag holder = OWN_MAP);
int argc = -1);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
static inline StubType ExtractTypeFromFlags(Flags flags);
......
......@@ -102,8 +102,10 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
Handle<Code> StubCache::FindIC(Handle<Name> name,
Handle<Map> stub_holder_map,
Code::Kind kind,
Code::ExtraICState extra_state) {
Code::Flags flags = Code::ComputeMonomorphicFlags(kind, extra_state);
Code::ExtraICState extra_state,
InlineCacheHolderFlag cache_holder) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, cache_holder);
Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
......@@ -111,17 +113,10 @@ Handle<Code> StubCache::FindIC(Handle<Name> name,
}
Handle<Code> StubCache::FindIC(Handle<Name> name,
Handle<JSObject> stub_holder,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
return FindIC(name, Handle<Map>(stub_holder->map()), kind, extra_ic_state);
}
Handle<Code> StubCache::FindHandler(Handle<Name> name,
Handle<JSObject> receiver,
Handle<HeapObject> stub_holder,
Code::Kind kind,
InlineCacheHolderFlag cache_holder,
StrictModeFlag strict_mode) {
Code::ExtraICState extra_ic_state = Code::kNoExtraICState;
if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
......@@ -129,28 +124,36 @@ Handle<Code> StubCache::FindHandler(Handle<Name> name,
STANDARD_STORE, strict_mode);
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::HANDLER, extra_ic_state, Code::NORMAL, kind);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Code::HANDLER, extra_ic_state, cache_holder, Code::NORMAL, kind);
Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
return Handle<Code>::null();
}
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<Name> name,
Handle<HeapObject> object,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode) {
Code::Kind kind = handler->handler_kind();
Handle<Map> map(receiver->map());
Handle<Code> ic = FindIC(name, map, kind, strict_mode);
// Use the same cache holder for the IC as for the handler.
InlineCacheHolderFlag cache_holder =
Code::ExtractCacheHolderFromFlags(handler->flags());
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
isolate(), *object, cache_holder));
Handle<Map> stub_holder_map(stub_holder->map());
Handle<Code> ic = FindIC(
name, stub_holder_map, kind, strict_mode, cache_holder);
if (!ic.is_null()) return ic;
Handle<Map> map(object->map());
if (kind == Code::LOAD_IC) {
LoadStubCompiler ic_compiler(isolate());
LoadStubCompiler ic_compiler(isolate(), cache_holder);
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
} else if (kind == Code::KEYED_LOAD_IC) {
KeyedLoadStubCompiler ic_compiler(isolate());
KeyedLoadStubCompiler ic_compiler(isolate(), cache_holder);
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
} else if (kind == Code::STORE_IC) {
StoreStubCompiler ic_compiler(isolate(), strict_mode);
......@@ -161,13 +164,16 @@ Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver,
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
}
HeapObject::UpdateMapCodeCache(receiver, name, ic);
HeapObject::UpdateMapCodeCache(stub_holder, name, ic);
return ic;
}
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
Handle<JSObject> receiver) {
Handle<Object> object) {
InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
isolate(), *object, cache_holder));
// If no global objects are present in the prototype chain, the load
// nonexistent IC stub can be shared for all names for a given map
// and we use the empty string for the map cache in that case. If
......@@ -176,7 +182,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
// specific to the name.
Handle<Name> cache_name = factory()->empty_string();
Handle<JSObject> current;
Handle<Object> next = receiver;
Handle<Object> next = stub_holder;
Handle<JSGlobalObject> global;
do {
current = Handle<JSObject>::cast(next);
......@@ -191,13 +197,14 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
Handle<Code> handler = FindHandler(cache_name, receiver, Code::LOAD_IC);
Handle<Code> handler = FindHandler(
cache_name, stub_holder, Code::LOAD_IC, cache_holder);
if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
LoadStubCompiler compiler(isolate_, cache_holder);
handler =
compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
HeapObject::UpdateMapCodeCache(receiver, cache_name, handler);
compiler.CompileLoadNonexistent(object, current, cache_name, global);
HeapObject::UpdateMapCodeCache(stub_holder, cache_name, handler);
return handler;
}
......@@ -257,9 +264,8 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
Handle<JSObject> holder,
Handle<JSFunction> function) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
isolate_, *object, cache_holder));
// Compute check type based on receiver/holder.
......@@ -283,7 +289,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::CONSTANT, argc, cache_holder);
kind, extra_state, cache_holder, Code::CONSTANT, argc);
Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
......@@ -312,9 +318,8 @@ Handle<Code> StubCache::ComputeCallField(int argc,
Handle<JSObject> holder,
PropertyIndex index) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
isolate_, *object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
......@@ -326,7 +331,7 @@ Handle<Code> StubCache::ComputeCallField(int argc,
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::FIELD, argc, cache_holder);
kind, extra_state, cache_holder, Code::FIELD, argc);
Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
......@@ -351,9 +356,8 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
Handle<Object> object,
Handle<JSObject> holder) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
isolate_, *object, cache_holder));
// TODO(1233596): We cannot do receiver map check for non-JS objects
......@@ -365,7 +369,7 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
}
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
kind, extra_state, cache_holder, Code::INTERCEPTOR, argc);
Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
......@@ -392,7 +396,7 @@ Handle<Code> StubCache::ComputeCallGlobal(int argc,
Handle<PropertyCell> cell,
Handle<JSFunction> function) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::NORMAL, argc);
kind, extra_state, OWN_MAP, Code::NORMAL, argc);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
......@@ -1096,10 +1100,7 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
masm_.GetCode(&desc);
Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
code->Disassemble(name, trace_scope.file());
}
if (FLAG_print_code_stubs) code->Disassemble(name);
#endif
return code;
}
......@@ -1127,55 +1128,82 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
Register LoadStubCompiler::HandlerFrontendHeader(
Handle<JSObject> object,
Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* miss) {
return CheckPrototypes(object, object_reg, holder,
Handle<JSObject> receiver;
PrototypeCheckType check_type = CHECK_ALL_MAPS;
int function_index = -1;
if (object->IsJSObject()) {
receiver = Handle<JSObject>::cast(object);
check_type = SKIP_RECEIVER;
} else {
if (object->IsString()) {
function_index = Context::STRING_FUNCTION_INDEX;
} else if (object->IsSymbol()) {
function_index = Context::SYMBOL_FUNCTION_INDEX;
} else if (object->IsNumber()) {
function_index = Context::NUMBER_FUNCTION_INDEX;
} else {
ASSERT(object->IsBoolean());
// Booleans use the generic oddball map, so an additional check is
// needed to ensure the receiver is really a boolean.
GenerateBooleanCheck(object_reg, miss);
function_index = Context::BOOLEAN_FUNCTION_INDEX;
}
GenerateDirectLoadGlobalFunctionPrototype(
masm(), function_index, scratch1(), miss);
receiver = handle(JSObject::cast(object->GetPrototype(isolate())));
object_reg = scratch1();
}
// Check that the maps starting from the prototype haven't changed.
return CheckPrototypes(receiver, object_reg, holder,
scratch1(), scratch2(), scratch3(),
name, miss, SKIP_RECEIVER);
name, miss, check_type);
}
// HandlerFrontend for store uses the name register. It has to be restored
// before a miss.
Register StoreStubCompiler::HandlerFrontendHeader(
Handle<JSObject> object,
Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* miss) {
return CheckPrototypes(object, object_reg, holder,
return CheckPrototypes(Handle<JSObject>::cast(object), object_reg, holder,
this->name(), scratch1(), scratch2(),
name, miss, SKIP_RECEIVER);
}
Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object,
Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success) {
Handle<Name> name) {
Label miss;
Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
HandlerFrontendFooter(name, success, &miss);
HandlerFrontendFooter(name, &miss);
return reg;
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<JSGlobalObject> global) {
Label miss;
Register holder =
HandlerFrontendHeader(object, receiver(), last, name, &miss);
Register holder = HandlerFrontendHeader(
object, receiver(), last, name, &miss);
if (!last->HasFastProperties() &&
!last->IsJSGlobalObject() &&
......@@ -1196,12 +1224,12 @@ void LoadStubCompiler::NonexistentHandlerFrontend(
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
HandlerFrontendFooter(name, &miss);
}
Handle<Code> LoadStubCompiler::CompileLoadField(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
PropertyIndex field,
......@@ -1221,13 +1249,11 @@ Handle<Code> LoadStubCompiler::CompileLoadField(
Handle<Code> LoadStubCompiler::CompileLoadConstant(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<Object> value) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
GenerateLoadConstant(value);
// Return the generated code.
......@@ -1236,15 +1262,12 @@ Handle<Code> LoadStubCompiler::CompileLoadConstant(
Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
Label success;
Register reg = CallbackHandlerFrontend(
object, receiver(), holder, name, &success, callback);
__ bind(&success);
object, receiver(), holder, name, callback);
GenerateLoadCallback(reg, callback);
// Return the generated code.
......@@ -1253,17 +1276,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
const CallOptimization& call_optimization) {
ASSERT(call_optimization.is_simple_api_call());
Label success;
Handle<JSFunction> callback = call_optimization.constant_function();
CallbackHandlerFrontend(
object, receiver(), holder, name, &success, callback);
__ bind(&success);
CallbackHandlerFrontend(object, receiver(), holder, name, callback);
GenerateLoadCallback(call_optimization);
// Return the generated code.
......@@ -1272,16 +1291,13 @@ Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name) {
Label success;
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
Register reg = HandlerFrontend(object, receiver(), holder, name);
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptor(reg, object, holder, &lookup, name);
......@@ -1296,7 +1312,6 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
Handle<JSObject> interceptor_holder,
Handle<Name> name,
LookupResult* lookup) {
Label success;
Handle<JSObject> holder(lookup->holder());
if (lookup->IsField()) {
PropertyIndex field = lookup->GetFieldIndex();
......@@ -1307,8 +1322,7 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
// We found FIELD property in prototype chain of interceptor's holder.
// Retrieve a field from field's holder.
Register reg = HandlerFrontend(
interceptor_holder, interceptor_reg, holder, name, &success);
__ bind(&success);
interceptor_holder, interceptor_reg, holder, name);
GenerateLoadField(
reg, holder, field, lookup->representation());
}
......@@ -1321,8 +1335,7 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
ASSERT(callback->getter() != NULL);
Register reg = CallbackHandlerFrontend(
interceptor_holder, interceptor_reg, holder, name, &success, callback);
__ bind(&success);
interceptor_holder, interceptor_reg, holder, name, callback);
GenerateLoadCallback(reg, callback);
}
}
......@@ -1342,14 +1355,11 @@ Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<JSFunction> getter) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
GenerateLoadViaGetter(masm(), receiver(), getter);
// Return the generated code.
......@@ -1442,10 +1452,7 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
Handle<JSObject> holder,
Handle<Name> name,
Handle<JSFunction> setter) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
GenerateStoreViaSetter(masm(), setter);
return GetCode(kind(), Code::CALLBACKS, name);
......@@ -1555,7 +1562,7 @@ Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
Code::StubType type,
Handle<Name> name) {
Code::Flags flags = Code::ComputeFlags(
Code::HANDLER, MONOMORPHIC, extra_state(), type, kind);
Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_);
Handle<Code> code = GetCodeWithFlags(flags, name);
PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
JitEvent(name, code);
......@@ -1723,11 +1730,8 @@ Handle<Code> CallStubCompiler::CompileCustomCall(
Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
Handle<Name> name) {
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
extra_state_,
type,
argc,
cache_holder_);
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind_, extra_state_, cache_holder_, type, argc);
return GetCodeWithFlags(flags, name);
}
......
......@@ -83,29 +83,21 @@ class StubCache {
Handle<Code> FindIC(Handle<Name> name,
Handle<Map> stub_holder_map,
Code::Kind kind,
Code::ExtraICState extra_state = Code::kNoExtraICState);
Handle<Code> FindIC(Handle<Name> name,
Handle<JSObject> stub_holder,
Code::Kind kind,
Code::ExtraICState extra_state = Code::kNoExtraICState);
Code::ExtraICState extra_state = Code::kNoExtraICState,
InlineCacheHolderFlag cache_holder = OWN_MAP);
Handle<Code> FindHandler(Handle<Name> name,
Handle<JSObject> receiver,
Handle<HeapObject> stub_holder,
Code::Kind kind,
InlineCacheHolderFlag cache_holder = OWN_MAP,
StrictModeFlag strict_mode = kNonStrictMode);
Handle<Code> ComputeMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode);
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
Handle<JSObject> object);
// ---
Handle<Code> ComputeLoadNonexistent(Handle<Name> name, Handle<Object> object);
Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
......@@ -501,6 +493,7 @@ class StubCompiler BASE_EMBEDDED {
Label* miss,
PrototypeCheckType check = CHECK_ALL_MAPS);
void GenerateBooleanCheck(Register object, Label* miss);
protected:
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
......@@ -531,8 +524,10 @@ enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
class BaseLoadStoreStubCompiler: public StubCompiler {
public:
BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind)
: StubCompiler(isolate), kind_(kind) {
BaseLoadStoreStubCompiler(Isolate* isolate,
Code::Kind kind,
InlineCacheHolderFlag cache_holder = OWN_MAP)
: StubCompiler(isolate), kind_(kind), cache_holder_(cache_holder) {
InitializeRegisters();
}
virtual ~BaseLoadStoreStubCompiler() { }
......@@ -563,21 +558,18 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
}
protected:
virtual Register HandlerFrontendHeader(Handle<JSObject> object,
virtual Register HandlerFrontendHeader(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* miss) = 0;
virtual void HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) = 0;
virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss) = 0;
Register HandlerFrontend(Handle<JSObject> object,
Register HandlerFrontend(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success);
Handle<Name> name);
Handle<Code> GetCode(Code::Kind kind,
Code::StubType type,
......@@ -617,42 +609,45 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
void InitializeRegisters();
Code::Kind kind_;
InlineCacheHolderFlag cache_holder_;
Register* registers_;
};
class LoadStubCompiler: public BaseLoadStoreStubCompiler {
public:
LoadStubCompiler(Isolate* isolate, Code::Kind kind = Code::LOAD_IC)
: BaseLoadStoreStubCompiler(isolate, kind) { }
LoadStubCompiler(Isolate* isolate,
InlineCacheHolderFlag cache_holder = OWN_MAP,
Code::Kind kind = Code::LOAD_IC)
: BaseLoadStoreStubCompiler(isolate, kind, cache_holder) { }
virtual ~LoadStubCompiler() { }
Handle<Code> CompileLoadField(Handle<JSObject> object,
Handle<Code> CompileLoadField(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
PropertyIndex index,
Representation representation);
Handle<Code> CompileLoadCallback(Handle<JSObject> object,
Handle<Code> CompileLoadCallback(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback);
Handle<Code> CompileLoadCallback(Handle<JSObject> object,
Handle<Code> CompileLoadCallback(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
const CallOptimization& call_optimization);
Handle<Code> CompileLoadConstant(Handle<JSObject> object,
Handle<Code> CompileLoadConstant(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<Object> value);
Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
Handle<Code> CompileLoadInterceptor(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name);
Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
Handle<Code> CompileLoadViaGetter(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
Handle<JSFunction> getter);
......@@ -661,12 +656,12 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
Register receiver,
Handle<JSFunction> getter);
Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
Handle<Code> CompileLoadNonexistent(Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Handle<JSGlobalObject> global);
Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
Handle<Code> CompileLoadGlobal(Handle<Object> object,
Handle<GlobalObject> holder,
Handle<PropertyCell> cell,
Handle<Name> name,
......@@ -675,26 +670,22 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
static Register* registers();
protected:
virtual Register HandlerFrontendHeader(Handle<JSObject> object,
virtual Register HandlerFrontendHeader(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* miss);
virtual void HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss);
virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
Register CallbackHandlerFrontend(Handle<JSObject> object,
Register CallbackHandlerFrontend(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
Handle<Object> callback);
void NonexistentHandlerFrontend(Handle<JSObject> object,
void NonexistentHandlerFrontend(Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<JSGlobalObject> global);
void GenerateLoadField(Register reg,
......@@ -706,7 +697,7 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
Handle<ExecutableAccessorInfo> callback);
void GenerateLoadCallback(const CallOptimization& call_optimization);
void GenerateLoadInterceptor(Register holder_reg,
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> holder,
LookupResult* lookup,
Handle<Name> name);
......@@ -726,8 +717,9 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
class KeyedLoadStubCompiler: public LoadStubCompiler {
public:
explicit KeyedLoadStubCompiler(Isolate* isolate)
: LoadStubCompiler(isolate, Code::KEYED_LOAD_IC) { }
KeyedLoadStubCompiler(Isolate* isolate,
InlineCacheHolderFlag cache_holder = OWN_MAP)
: LoadStubCompiler(isolate, cache_holder, Code::KEYED_LOAD_IC) { }
Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
......@@ -827,15 +819,13 @@ class StoreStubCompiler: public BaseLoadStoreStubCompiler {
}
protected:
virtual Register HandlerFrontendHeader(Handle<JSObject> object,
virtual Register HandlerFrontendHeader(Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* miss);
virtual void HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss);
virtual void HandlerFrontendFooter(Handle<Name> name, Label* miss);
void GenerateRestoreName(MacroAssembler* masm,
Label* label,
Handle<Name> name);
......@@ -928,8 +918,7 @@ class CallStubCompiler: public StubCompiler {
void CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
CheckType check,
Label* success);
CheckType check);
void CompileHandlerBackend(Handle<JSFunction> function);
......
......@@ -298,11 +298,8 @@ void TypeFeedbackOracle::CallReceiverTypes(Call* expr,
Code::ExtraICState extra_ic_state =
CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
extra_ic_state,
Code::NORMAL,
arity,
OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(
Code::CALL_IC, extra_ic_state, OWN_MAP, Code::NORMAL, arity);
CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types);
}
......
......@@ -1200,34 +1200,33 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
}
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
Label success;
__ jmp(&success);
__ bind(miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
Label* success,
Label* miss) {
void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
Label success;
__ jmp(&success);
GenerateRestoreName(masm(), miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
Register LoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Handle<Object> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
Label* success,
Handle<Object> callback) {
Label miss;
......@@ -1268,7 +1267,7 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
__ j(not_equal, &miss);
}
HandlerFrontendFooter(name, success, &miss);
HandlerFrontendFooter(name, &miss);
return reg;
}
......@@ -1389,7 +1388,7 @@ void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
void LoadStubCompiler::GenerateLoadInterceptor(
Register holder_reg,
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
Handle<Name> name) {
......@@ -2507,11 +2506,21 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
}
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
// Check that the object is a boolean.
__ CompareRoot(object, Heap::kTrueValueRootIndex);
__ j(equal, &success);
__ CompareRoot(object, Heap::kFalseValueRootIndex);
__ j(not_equal, miss);
__ bind(&success);
}
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
CheckType check,
Label* success) {
CheckType check) {
// ----------- S t a t e -------------
// rcx : function name
// rsp[0] : return address
......@@ -2593,13 +2602,7 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
break;
}
case BOOLEAN_CHECK: {
Label fast;
// Check that the object is a boolean.
__ CompareRoot(rdx, Heap::kTrueValueRootIndex);
__ j(equal, &fast);
__ CompareRoot(rdx, Heap::kFalseValueRootIndex);
__ j(not_equal, &miss);
__ bind(&fast);
GenerateBooleanCheck(rdx, &miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
......@@ -2610,11 +2613,14 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
}
}
__ jmp(success);
Label success;
__ jmp(&success);
// Handle call cache miss.
__ bind(&miss);
GenerateMissBranch();
__ bind(&success);
}
......@@ -2643,10 +2649,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
if (!code.is_null()) return code;
}
Label success;
CompileHandlerFrontend(object, holder, name, check, &success);
__ bind(&success);
CompileHandlerFrontend(object, holder, name, check);
CompileHandlerBackend(function);
// Return the generated code.
......@@ -2782,9 +2785,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
__ PopReturnAddressTo(scratch1());
__ push(receiver());
......@@ -2808,9 +2809,7 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> holder,
Handle<Name> name,
const CallOptimization& call_optimization) {
Label success;
HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
HandlerFrontend(object, receiver(), holder, name);
Register values[] = { value() };
GenerateFastApiCall(
......@@ -2924,15 +2923,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<JSObject> object,
Handle<Object> object,
Handle<JSObject> last,
Handle<Name> name,
Handle<JSGlobalObject> global) {
Label success;
NonexistentHandlerFrontend(object, last, name, global);
NonexistentHandlerFrontend(object, last, name, &success, global);
__ bind(&success);
// Return undefined if maps of the full prototype chain are still the
// same and no global property with this name contains a value.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
......@@ -3027,12 +3023,12 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
Handle<Code> LoadStubCompiler::CompileLoadGlobal(
Handle<JSObject> object,
Handle<Object> object,
Handle<GlobalObject> global,
Handle<PropertyCell> cell,
Handle<Name> name,
bool is_dont_delete) {
Label success, miss;
Label miss;
// TODO(verwaest): Directly store to rax. Currently we cannot do this, since
// rax is used as receiver(), which we would otherwise clobber before a
// potential miss.
......@@ -3051,8 +3047,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
__ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
}
HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
HandlerFrontendFooter(name, &miss);
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->named_load_global_stub(), 1);
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Object.defineProperty(Boolean.prototype, "v",
{get:function() { return this; }});
function f(b) {
return b.v;
}
assertEquals("object", typeof f(true));
assertEquals("object", typeof f(true));
assertEquals("object", typeof f(true));
assertEquals("object", typeof f(true));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment