Commit 4d2dd669 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[ic] Turn load-interceptor into a smi-handler

This doesn't support "lookup after interceptor", but that should be unnecessary by now since we have non-masking interceptors.

BUG=

Change-Id: I8650a47ab2ce6fa314de25d0c4775b5c165df179
Reviewed-on: https://chromium-review.googlesource.com/453376Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43766}
parent f20261bf
...@@ -186,7 +186,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { ...@@ -186,7 +186,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
if (map == heap->boolean_map()) return kBoolean; if (map == heap->boolean_map()) return kBoolean;
if (map == heap->the_hole_map()) return kHole; if (map == heap->the_hole_map()) return kHole;
DCHECK(map == heap->uninitialized_map() || DCHECK(map == heap->uninitialized_map() ||
map == heap->no_interceptor_result_sentinel_map() ||
map == heap->termination_exception_map() || map == heap->termination_exception_map() ||
map == heap->arguments_marker_map() || map == heap->arguments_marker_map() ||
map == heap->optimized_out_map() || map == heap->optimized_out_map() ||
......
...@@ -181,7 +181,6 @@ Type::bitset BitsetType::Lub(i::Map* map) { ...@@ -181,7 +181,6 @@ Type::bitset BitsetType::Lub(i::Map* map) {
if (map == heap->boolean_map()) return kBoolean; if (map == heap->boolean_map()) return kBoolean;
if (map == heap->the_hole_map()) return kHole; if (map == heap->the_hole_map()) return kHole;
DCHECK(map == heap->uninitialized_map() || DCHECK(map == heap->uninitialized_map() ||
map == heap->no_interceptor_result_sentinel_map() ||
map == heap->termination_exception_map() || map == heap->termination_exception_map() ||
map == heap->arguments_marker_map() || map == heap->arguments_marker_map() ||
map == heap->optimized_out_map() || map == heap->optimized_out_map() ||
......
...@@ -786,7 +786,9 @@ class RuntimeCallTimer final { ...@@ -786,7 +786,9 @@ class RuntimeCallTimer final {
V(LoadIC_LoadFieldFromPrototypeDH) \ V(LoadIC_LoadFieldFromPrototypeDH) \
V(LoadIC_LoadField) \ V(LoadIC_LoadField) \
V(LoadIC_LoadGlobal) \ V(LoadIC_LoadGlobal) \
V(LoadIC_LoadInterceptor) \ V(LoadIC_LoadInterceptorDH) \
V(LoadIC_LoadNonMaskingInterceptorDH) \
V(LoadIC_LoadInterceptorFromPrototypeDH) \
V(LoadIC_LoadNonexistentDH) \ V(LoadIC_LoadNonexistentDH) \
V(LoadIC_LoadNonexistent) \ V(LoadIC_LoadNonexistent) \
V(LoadIC_LoadNormalDH) \ V(LoadIC_LoadNormalDH) \
......
...@@ -2330,7 +2330,6 @@ bool Heap::CreateInitialMaps() { ...@@ -2330,7 +2330,6 @@ bool Heap::CreateInitialMaps() {
Context::BOOLEAN_FUNCTION_INDEX); Context::BOOLEAN_FUNCTION_INDEX);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, uninitialized);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, arguments_marker);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, no_interceptor_result_sentinel);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, exception);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, termination_exception);
ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out); ALLOCATE_MAP(ODDBALL_TYPE, Oddball::kSize, optimized_out);
...@@ -2670,11 +2669,6 @@ void Heap::CreateInitialObjects() { ...@@ -2670,11 +2669,6 @@ void Heap::CreateInitialObjects() {
handle(Smi::FromInt(-4), isolate()), "undefined", handle(Smi::FromInt(-4), isolate()), "undefined",
Oddball::kArgumentsMarker)); Oddball::kArgumentsMarker));
set_no_interceptor_result_sentinel(*factory->NewOddball(
factory->no_interceptor_result_sentinel_map(),
"no_interceptor_result_sentinel", handle(Smi::FromInt(-2), isolate()),
"undefined", Oddball::kOther));
set_termination_exception(*factory->NewOddball( set_termination_exception(*factory->NewOddball(
factory->termination_exception_map(), "termination_exception", factory->termination_exception_map(), "termination_exception",
handle(Smi::FromInt(-3), isolate()), "undefined", Oddball::kOther)); handle(Smi::FromInt(-3), isolate()), "undefined", Oddball::kOther));
......
...@@ -67,7 +67,6 @@ using v8::MemoryPressureLevel; ...@@ -67,7 +67,6 @@ using v8::MemoryPressureLevel;
/* This means they are never in new space and never on a page that is */ \ /* This means they are never in new space and never on a page that is */ \
/* being compacted. */ \ /* being compacted. */ \
/* Oddballs */ \ /* Oddballs */ \
V(Oddball, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
V(Oddball, arguments_marker, ArgumentsMarker) \ V(Oddball, arguments_marker, ArgumentsMarker) \
V(Oddball, exception, Exception) \ V(Oddball, exception, Exception) \
V(Oddball, termination_exception, TerminationException) \ V(Oddball, termination_exception, TerminationException) \
...@@ -216,7 +215,6 @@ using v8::MemoryPressureLevel; ...@@ -216,7 +215,6 @@ using v8::MemoryPressureLevel;
V(Map, boolean_map, BooleanMap) \ V(Map, boolean_map, BooleanMap) \
V(Map, uninitialized_map, UninitializedMap) \ V(Map, uninitialized_map, UninitializedMap) \
V(Map, arguments_marker_map, ArgumentsMarkerMap) \ V(Map, arguments_marker_map, ArgumentsMarkerMap) \
V(Map, no_interceptor_result_sentinel_map, NoInterceptorResultSentinelMap) \
V(Map, exception_map, ExceptionMap) \ V(Map, exception_map, ExceptionMap) \
V(Map, termination_exception_map, TerminationExceptionMap) \ V(Map, termination_exception_map, TerminationExceptionMap) \
V(Map, optimized_out_map, OptimizedOutMap) \ V(Map, optimized_out_map, OptimizedOutMap) \
...@@ -278,7 +276,6 @@ using v8::MemoryPressureLevel; ...@@ -278,7 +276,6 @@ using v8::MemoryPressureLevel;
V(FixedDoubleArrayMap) \ V(FixedDoubleArrayMap) \
V(WeakCellMap) \ V(WeakCellMap) \
V(TransitionArrayMap) \ V(TransitionArrayMap) \
V(NoInterceptorResultSentinel) \
V(HashTableMap) \ V(HashTableMap) \
V(OrderedHashTableMap) \ V(OrderedHashTableMap) \
V(EmptyFixedArray) \ V(EmptyFixedArray) \
......
This diff is collapsed.
...@@ -139,6 +139,7 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -139,6 +139,7 @@ class AccessorAssembler : public CodeStubAssembler {
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder, void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
Node* smi_handler, Label* miss, Node* smi_handler, Label* miss,
ExitPoint* exit_point, ExitPoint* exit_point,
bool throw_reference_error_if_nonexistent,
ElementSupport support_elements); ElementSupport support_elements);
void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler, void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
...@@ -154,8 +155,7 @@ class AccessorAssembler : public CodeStubAssembler { ...@@ -154,8 +155,7 @@ class AccessorAssembler : public CodeStubAssembler {
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler, Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags, Node* handler_length, Node* handler_flags,
Label* miss, Label* miss);
bool throw_reference_error_if_nonexistent);
// LoadGlobalIC implementation. // LoadGlobalIC implementation.
......
...@@ -200,24 +200,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -200,24 +200,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ b(ne, miss); __ b(ne, miss);
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ push(name);
__ push(receiver);
__ push(holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -445,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -445,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
__ cmp(r0, scratch1());
__ b(eq, &interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
__ pop(this->name());
__ pop(holder_reg);
if (must_preserve_receiver_reg) {
__ pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -99,22 +99,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -99,22 +99,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -474,87 +458,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -474,87 +458,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
scratch3()));
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
&interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ Ret();
__ Bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
if (must_preserve_receiver_reg) {
__ Pop(this->name(), holder_reg, receiver());
} else {
__ Pop(this->name(), holder_reg);
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -101,7 +101,15 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( ...@@ -101,7 +101,15 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
GenerateTailCall(masm(), slow_stub); GenerateTailCall(masm(), slow_stub);
} }
Register reg = Frontend(name); Register reg = Frontend(name);
GenerateLoadCallback(reg, callback); DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
__ Move(ApiGetterDescriptor::HolderRegister(), reg);
// The callback is alive if this instruction is executed,
// so the weak cell is not cleared and points to data.
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
__ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
CallApiGetterStub stub(isolate());
__ TailCallStub(&stub);
return GetCode(kind(), name); return GetCode(kind(), name);
} }
...@@ -118,191 +126,6 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( ...@@ -118,191 +126,6 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
return GetCode(kind(), name); return GetCode(kind(), name);
} }
void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
if (IC::ShouldPushPopSlotAndVector(kind())) {
if (holder_reg.is(receiver())) {
PushVectorAndSlot();
} else {
DCHECK(holder_reg.is(scratch1()));
PushVectorAndSlot(scratch2(), scratch3());
}
}
}
void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
PopMode mode) {
if (IC::ShouldPushPopSlotAndVector(kind())) {
if (mode == DISCARD) {
DiscardVectorAndSlot();
} else {
if (holder_reg.is(receiver())) {
PopVectorAndSlot();
} else {
DCHECK(holder_reg.is(scratch1()));
PopVectorAndSlot(scratch2(), scratch3());
}
}
}
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
LookupIterator* it) {
// So far the most popular follow ups for interceptor loads are DATA and
// AccessorInfo, so inline only them. Other cases may be added
// later.
bool inline_followup = false;
switch (it->state()) {
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY:
case LookupIterator::NOT_FOUND:
case LookupIterator::INTEGER_INDEXED_EXOTIC:
break;
case LookupIterator::DATA: {
PropertyDetails details = it->property_details();
inline_followup = details.kind() == kData &&
details.location() == kField &&
!it->is_dictionary_holder();
break;
}
case LookupIterator::ACCESSOR: {
Handle<Object> accessors = it->GetAccessors();
if (accessors->IsAccessorInfo()) {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
inline_followup =
info->getter() != NULL &&
AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
} else if (accessors->IsAccessorPair()) {
Handle<JSObject> property_holder(it->GetHolder<JSObject>());
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
isolate());
if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
break;
}
if (!property_holder->HasFastProperties()) break;
CallOptimization call_optimization(getter);
Handle<Map> receiver_map = map();
inline_followup = call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiverMap(
receiver_map, property_holder);
}
}
}
Label miss;
InterceptorVectorSlotPush(receiver());
bool lost_holder_register = false;
auto holder_orig = holder();
// non masking interceptors must check the entire chain, so temporarily reset
// the holder to be that last element for the FrontendHeader call.
if (holder()->GetNamedInterceptor()->non_masking()) {
DCHECK(!inline_followup);
JSObject* last = *holder();
PrototypeIterator iter(isolate(), last);
while (!iter.IsAtEnd()) {
lost_holder_register = true;
// Casting to JSObject is fine here. The LookupIterator makes sure to
// look behind non-masking interceptors during the original lookup, and
// we wouldn't try to compile a handler if there was a Proxy anywhere.
last = iter.GetCurrent<JSObject>();
iter.Advance();
}
auto last_handle = handle(last);
set_holder(last_handle);
}
Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
// Reset the holder so further calculations are correct.
set_holder(holder_orig);
if (lost_holder_register) {
if (*it->GetReceiver() == *holder()) {
reg = receiver();
} else {
// Reload lost holder register.
auto cell = isolate()->factory()->NewWeakCell(holder());
__ LoadWeakValue(reg, cell, &miss);
}
}
FrontendFooter(it->name(), &miss);
InterceptorVectorSlotPop(reg);
if (inline_followup) {
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptorWithFollowup(it, reg);
} else {
GenerateLoadInterceptor(reg);
}
return GetCode(kind(), it->name());
}
void NamedLoadHandlerCompiler::GenerateLoadCallback(
Register reg, Handle<AccessorInfo> callback) {
DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
__ Move(ApiGetterDescriptor::HolderRegister(), reg);
// The callback is alive if this instruction is executed,
// so the weak cell is not cleared and points to data.
Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
__ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
CallApiGetterStub stub(isolate());
__ TailCallStub(&stub);
}
void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
LookupIterator* it, Register interceptor_reg) {
Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
Handle<Map> holder_map(holder()->map());
set_map(holder_map);
set_holder(real_named_property_holder);
Label miss;
InterceptorVectorSlotPush(interceptor_reg);
Register reg =
FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
FrontendFooter(it->name(), &miss);
// We discard the vector and slot now because we don't miss below this point.
InterceptorVectorSlotPop(reg, DISCARD);
switch (it->state()) {
case LookupIterator::ACCESS_CHECK:
case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY:
case LookupIterator::NOT_FOUND:
case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::DATA: {
DCHECK_EQ(kData, it->property_details().kind());
DCHECK_EQ(kField, it->property_details().location());
__ Move(LoadFieldDescriptor::ReceiverRegister(), reg);
Handle<Object> smi_handler =
LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex());
__ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler);
GenerateTailCall(masm(), isolate()->builtins()->LoadField());
break;
}
case LookupIterator::ACCESSOR:
if (it->GetAccessors()->IsAccessorInfo()) {
Handle<AccessorInfo> info =
Handle<AccessorInfo>::cast(it->GetAccessors());
DCHECK_NOT_NULL(info->getter());
GenerateLoadCallback(reg, info);
} else {
Handle<Object> function = handle(
AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
CallOptimization call_optimization(function);
GenerateApiAccessorCall(masm(), call_optimization, holder_map,
receiver(), scratch2(), false, no_reg, reg,
it->GetAccessorIndex());
}
}
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
Handle<Name> name, int accessor_index, int expected_arguments) { Handle<Name> name, int accessor_index, int expected_arguments) {
Register holder = Frontend(name); Register holder = Frontend(name);
......
...@@ -137,11 +137,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { ...@@ -137,11 +137,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
const CallOptimization& call_optimization, const CallOptimization& call_optimization,
int accessor_index, Handle<Code> slow_stub); int accessor_index, Handle<Code> slow_stub);
// 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, Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index,
int expected_arguments); int expected_arguments);
...@@ -158,15 +153,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { ...@@ -158,15 +153,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
no_reg); no_reg);
} }
// 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: protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name, virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
Label* miss, ReturnHolder return_what); Label* miss, ReturnHolder return_what);
...@@ -174,18 +160,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { ...@@ -174,18 +160,6 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
virtual void FrontendFooter(Handle<Name> name, Label* miss); virtual void FrontendFooter(Handle<Name> name, Label* miss);
private: private:
void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback);
// 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);
Register scratch3() { return registers_[4]; } Register scratch3() { return registers_[4]; }
}; };
......
...@@ -13,68 +13,68 @@ ...@@ -13,68 +13,68 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
Handle<Object> LoadHandler::LoadNormal(Isolate* isolate) { Handle<Smi> LoadHandler::LoadNormal(Isolate* isolate) {
int config = KindBits::encode(kForNormal); int config = KindBits::encode(kNormal);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::LoadField(Isolate* isolate, Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) {
FieldIndex field_index) { int config = KindBits::encode(kInterceptor);
int config = KindBits::encode(kForFields) | return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
int config = KindBits::encode(kField) |
IsInobjectBits::encode(field_index.is_inobject()) | IsInobjectBits::encode(field_index.is_inobject()) |
IsDoubleBits::encode(field_index.is_double()) | IsDoubleBits::encode(field_index.is_double()) |
FieldOffsetBits::encode(field_index.offset()); FieldOffsetBits::encode(field_index.offset());
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) { Handle<Smi> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
int config = KindBits::encode(kForConstants) | int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(false) |
IsAccessorInfoBits::encode(false) |
DescriptorBits::encode(descriptor); DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) { Handle<Smi> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) {
int config = KindBits::encode(kForConstants) | int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) |
IsAccessorInfoBits::encode(true) |
DescriptorBits::encode(descriptor); DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::EnableAccessCheckOnReceiver( Handle<Smi> LoadHandler::EnableAccessCheckOnReceiver(Isolate* isolate,
Isolate* isolate, Handle<Object> smi_handler) { Handle<Smi> smi_handler) {
int config = Smi::cast(*smi_handler)->value(); int config = smi_handler->value();
#ifdef DEBUG #ifdef DEBUG
Kind kind = KindBits::decode(config); Kind kind = KindBits::decode(config);
DCHECK_NE(kForElements, kind); DCHECK_NE(kElement, kind);
#endif #endif
config = DoAccessCheckOnReceiverBits::update(config, true); config = DoAccessCheckOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::EnableLookupOnReceiver(Isolate* isolate, Handle<Smi> LoadHandler::EnableLookupOnReceiver(Isolate* isolate,
Handle<Object> smi_handler) { Handle<Smi> smi_handler) {
int config = Smi::cast(*smi_handler)->value(); int config = smi_handler->value();
#ifdef DEBUG #ifdef DEBUG
Kind kind = KindBits::decode(config); Kind kind = KindBits::decode(config);
DCHECK_NE(kForElements, kind); DCHECK_NE(kElement, kind);
#endif #endif
config = LookupOnReceiverBits::update(config, true); config = LookupOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::LoadNonExistent(Isolate* isolate, Handle<Smi> LoadHandler::LoadNonExistent(Isolate* isolate) {
bool do_lookup_on_receiver) { int config = KindBits::encode(kNonExistent);
int config = KindBits::encode(kForNonExistent) |
LookupOnReceiverBits::encode(do_lookup_on_receiver);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Object> LoadHandler::LoadElement(Isolate* isolate, Handle<Smi> LoadHandler::LoadElement(Isolate* isolate,
ElementsKind elements_kind, ElementsKind elements_kind,
bool convert_hole_to_undefined, bool convert_hole_to_undefined,
bool is_js_array) { bool is_js_array) {
int config = KindBits::encode(kForElements) | int config = KindBits::encode(kElement) |
ElementsKindBits::encode(elements_kind) | ElementsKindBits::encode(elements_kind) |
ConvertHoleBits::encode(convert_hole_to_undefined) | ConvertHoleBits::encode(convert_hole_to_undefined) |
IsJsArrayBits::encode(is_js_array); IsJsArrayBits::encode(is_js_array);
......
...@@ -17,24 +17,24 @@ namespace internal { ...@@ -17,24 +17,24 @@ namespace internal {
class LoadHandler { class LoadHandler {
public: public:
enum Kind { enum Kind {
kForElements, kElement,
kForNormal, kNormal,
kForFields, kField,
kForConstants, kConstant,
kForNonExistent kInterceptor,
kNonExistent
}; };
class KindBits : public BitField<Kind, 0, 3> {}; class KindBits : public BitField<Kind, 0, 3> {};
// Defines whether access rights check should be done on receiver object. // Defines whether access rights check should be done on receiver object.
// Applicable to kForFields, kForConstants and kForNonExistent kinds only when // Applicable to named property kinds only when loading value from prototype
// loading value from prototype chain. Ignored when loading from holder. // chain. Ignored when loading from holder.
class DoAccessCheckOnReceiverBits class DoAccessCheckOnReceiverBits
: public BitField<bool, KindBits::kNext, 1> {}; : public BitField<bool, KindBits::kNext, 1> {};
// Defines whether a lookup should be done on receiver object before // Defines whether a lookup should be done on receiver object before
// proceeding to the prototype chain. Applicable to kForFields, kForConstants // proceeding to the prototype chain. Applicable to named property kinds only
// and kForNonExistent kinds only when loading value from prototype chain. // when loading value from prototype chain. Ignored when loading from holder.
// Ignored when loading from holder.
class LookupOnReceiverBits class LookupOnReceiverBits
: public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {}; : public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {};
...@@ -51,7 +51,7 @@ class LoadHandler { ...@@ -51,7 +51,7 @@ class LoadHandler {
STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize); STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
// //
// Encoding when KindBits contains kForFields. // Encoding when KindBits contains kField.
// //
class IsInobjectBits : public BitField<bool, LookupOnReceiverBits::kNext, 1> { class IsInobjectBits : public BitField<bool, LookupOnReceiverBits::kNext, 1> {
}; };
...@@ -64,7 +64,7 @@ class LoadHandler { ...@@ -64,7 +64,7 @@ class LoadHandler {
STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize); STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize);
// //
// Encoding when KindBits contains kForElements. // Encoding when KindBits contains kElement.
// //
class IsJsArrayBits : public BitField<bool, KindBits::kNext, 1> {}; class IsJsArrayBits : public BitField<bool, KindBits::kNext, 1> {};
class ConvertHoleBits : public BitField<bool, IsJsArrayBits::kNext, 1> {}; class ConvertHoleBits : public BitField<bool, IsJsArrayBits::kNext, 1> {};
...@@ -89,35 +89,37 @@ class LoadHandler { ...@@ -89,35 +89,37 @@ class LoadHandler {
static const int kFirstPrototypeIndex = 3; static const int kFirstPrototypeIndex = 3;
// Creates a Smi-handler for loading a property from a slow object. // Creates a Smi-handler for loading a property from a slow object.
static inline Handle<Object> LoadNormal(Isolate* isolate); static inline Handle<Smi> LoadNormal(Isolate* isolate);
// Creates a Smi-handler for loading a property from an object with an
// interceptor.
static inline Handle<Smi> LoadInterceptor(Isolate* isolate);
// Creates a Smi-handler for loading a field from fast object. // Creates a Smi-handler for loading a field from fast object.
static inline Handle<Object> LoadField(Isolate* isolate, static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
FieldIndex field_index);
// Creates a Smi-handler for loading a constant from fast object. // Creates a Smi-handler for loading a constant from fast object.
static inline Handle<Object> LoadConstant(Isolate* isolate, int descriptor); static inline Handle<Smi> LoadConstant(Isolate* isolate, int descriptor);
// Creates a Smi-handler for loading an Api getter property from fast object. // Creates a Smi-handler for loading an Api getter property from fast object.
static inline Handle<Object> LoadApiGetter(Isolate* isolate, int descriptor); static inline Handle<Smi> LoadApiGetter(Isolate* isolate, int descriptor);
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver // Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check. // check is a part of a prototype chain check.
static inline Handle<Object> EnableAccessCheckOnReceiver( static inline Handle<Smi> EnableAccessCheckOnReceiver(
Isolate* isolate, Handle<Object> smi_handler); Isolate* isolate, Handle<Smi> smi_handler);
// Sets LookupOnReceiverBits in given Smi-handler. The receiver // Sets LookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check. // check is a part of a prototype chain check.
static inline Handle<Object> EnableLookupOnReceiver( static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate,
Isolate* isolate, Handle<Object> smi_handler); Handle<Smi> smi_handler);
// Creates a Smi-handler for loading a non-existent property. Works only as // Creates a Smi-handler for loading a non-existent property. Works only as
// a part of prototype chain check. // a part of prototype chain check.
static inline Handle<Object> LoadNonExistent(Isolate* isolate, static inline Handle<Smi> LoadNonExistent(Isolate* isolate);
bool do_lookup_on_receiver);
// Creates a Smi-handler for loading an element. // Creates a Smi-handler for loading an element.
static inline Handle<Object> LoadElement(Isolate* isolate, static inline Handle<Smi> LoadElement(Isolate* isolate,
ElementsKind elements_kind, ElementsKind elements_kind,
bool convert_hole_to_undefined, bool convert_hole_to_undefined,
bool is_js_array); bool is_js_array);
......
...@@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( ...@@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
} }
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ push(name);
__ push(receiver);
__ push(holder);
__ CallRuntime(id);
}
#undef __ #undef __
#define __ ACCESS_MASM(masm()) #define __ ACCESS_MASM(masm())
...@@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ push(receiver());
}
__ push(holder_reg);
__ push(this->name());
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ cmp(eax, factory()->no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ ret(0);
// Clobber registers when generating debug-code to provoke errors.
__ bind(&interceptor_failed);
if (FLAG_debug_code) {
__ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
__ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
__ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
}
InterceptorVectorSlotPop(holder_reg);
__ pop(this->name());
__ pop(holder_reg);
if (must_preserve_receiver_reg) {
__ pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
// Stack:
// return address
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ push(receiver());
__ push(holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ push(slot());
__ push(vector());
} else {
__ push(scratch3()); // slot
__ push(scratch2()); // vector
}
__ push(Operand(esp, 4 * kPointerSize)); // return address
__ mov(Operand(esp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they // Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only). // are properly loaded by the handler (debug-only).
......
...@@ -869,7 +869,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { ...@@ -869,7 +869,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
} }
} }
Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) { Handle<Smi> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH); TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH);
return LoadHandler::LoadField(isolate, index); return LoadHandler::LoadField(isolate, index);
} }
...@@ -967,12 +967,13 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map, ...@@ -967,12 +967,13 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<JSObject> holder,
Handle<Name> name, Handle<Name> name,
Handle<Object> smi_handler) { Handle<Smi> smi_handler) {
int checks_count = int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name); GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count); DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map()); DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context. DCHECK_LE(1, checks_count); // For native context.
smi_handler = smi_handler =
...@@ -1003,43 +1004,45 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, ...@@ -1003,43 +1004,45 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
return handler_array; return handler_array;
} }
Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
Handle<Name> name) { Handle<Object> holder, Handle<Name> name,
Handle<JSObject> holder; // null handle Handle<Smi> smi_handler) {
int checks_count = Handle<JSObject> end; // null handle
GetPrototypeCheckCount(isolate(), receiver_map, holder, name); int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
DCHECK_LE(0, checks_count); DCHECK_LE(0, checks_count);
bool do_negative_lookup_on_receiver = if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap(); receiver_map->is_access_check_needed()) {
Handle<Object> smi_handler =
LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver);
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
DCHECK(!receiver_map->is_dictionary_map()); DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context. DCHECK_LE(1, checks_count); // For native context.
smi_handler = smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
} }
Handle<Object> validity_cell = Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) { if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count); DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::FromInt(0), isolate()); // Lookup on receiver isn't supported in case of a simple smi handler.
if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) {
return smi_handler;
}
validity_cell = handle(Smi::kZero, isolate());
} }
Factory* factory = isolate()->factory(); Factory* factory = isolate()->factory();
if (checks_count == 0) { if (checks_count == 0) {
return factory->NewTuple3(factory->null_value(), smi_handler, return factory->NewTuple3(holder, smi_handler, validity_cell);
validity_cell);
} }
Handle<FixedArray> handler_array(factory->NewFixedArray( Handle<FixedArray> handler_array(factory->NewFixedArray(
LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value()); handler_array->set(LoadHandler::kHolderCellIndex, *holder);
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array, InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array,
LoadHandler::kFirstPrototypeIndex); LoadHandler::kFirstPrototypeIndex);
return handler_array; return handler_array;
} }
...@@ -1099,7 +1102,9 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { ...@@ -1099,7 +1102,9 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub(); code = slow_stub();
} else if (!lookup->IsFound()) { } else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
code = LoadNonExistent(receiver_map(), lookup->name()); Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(),
lookup->name(), smi_handler);
} else { } else {
if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA && if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA &&
lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
...@@ -1304,8 +1309,26 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { ...@@ -1304,8 +1309,26 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<JSObject> holder = lookup->GetHolder<JSObject>(); Handle<JSObject> holder = lookup->GetHolder<JSObject>();
bool receiver_is_holder = receiver.is_identical_to(holder); bool receiver_is_holder = receiver.is_identical_to(holder);
switch (lookup->state()) { switch (lookup->state()) {
case LookupIterator::INTERCEPTOR: case LookupIterator::INTERCEPTOR: {
break; // Custom-compiled handler. Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
if (holder->GetNamedInterceptor()->non_masking()) {
Handle<Object> holder_ref = isolate()->factory()->null_value();
if (!receiver_is_holder) {
holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate());
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
return LoadFullChain(map, holder_ref, lookup->name(), smi_handler);
}
if (receiver_is_holder) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
return smi_handler;
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
case LookupIterator::ACCESSOR: { case LookupIterator::ACCESSOR: {
// Use simple field loads for some well-known callback properties. // Use simple field loads for some well-known callback properties.
...@@ -1345,7 +1368,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { ...@@ -1345,7 +1368,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub(); return slow_stub();
} }
Handle<Object> smi_handler = Handle<Smi> smi_handler =
LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex()); LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
if (receiver_is_holder) { if (receiver_is_holder) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
...@@ -1364,7 +1387,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) { ...@@ -1364,7 +1387,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
case LookupIterator::DATA: { case LookupIterator::DATA: {
DCHECK_EQ(kData, lookup->property_details().kind()); DCHECK_EQ(kData, lookup->property_details().kind());
Handle<Object> smi_handler; Handle<Smi> smi_handler;
if (lookup->is_dictionary_holder()) { if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) { if (holder->IsJSGlobalObject()) {
break; // Custom-compiled handler. break; // Custom-compiled handler.
...@@ -1427,17 +1450,9 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup, ...@@ -1427,17 +1450,9 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
Handle<Map> map = receiver_map(); Handle<Map> map = receiver_map();
switch (lookup->state()) { switch (lookup->state()) {
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR:
DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate())); UNREACHABLE();
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor); break;
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
// Perform a lookup behind the interceptor. Copy the LookupIterator since
// the original iterator will be used to fetch the value.
LookupIterator it = *lookup;
it.Next();
LookupForRead(&it);
return compiler.CompileLoadInterceptor(&it);
}
case LookupIterator::ACCESSOR: { case LookupIterator::ACCESSOR: {
#ifdef DEBUG #ifdef DEBUG
...@@ -3055,57 +3070,16 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { ...@@ -3055,57 +3070,16 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
} }
/**
* Attempts to load a property with an interceptor (which must be present),
* but doesn't search the prototype chain.
*
* Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
* provide any value for the given name.
*/
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
Handle<Name> name =
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
Handle<Object> receiver =
args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
HandleScope scope(isolate);
if (!receiver->IsJSReceiver()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, receiver, Object::ConvertReceiver(isolate, receiver));
}
InterceptorInfo* interceptor = holder->GetNamedInterceptor();
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
*holder, Object::DONT_THROW);
v8::GenericNamedPropertyGetterCallback getter =
v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
interceptor->getter());
Handle<Object> result = arguments.Call(getter, name);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.is_null()) return *result;
return isolate->heap()->no_interceptor_result_sentinel();
}
/** /**
* Loads a property with an interceptor performing post interceptor * Loads a property with an interceptor performing post interceptor
* lookup if interceptor failed. * lookup if interceptor failed.
*/ */
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2); DCHECK_EQ(5, args.length());
Handle<Name> name = Handle<Name> name = args.at<Name>(0);
args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); Handle<Object> receiver = args.at(1);
Handle<Object> receiver = Handle<JSObject> holder = args.at<JSObject>(2);
args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
if (!receiver->IsJSReceiver()) { if (!receiver->IsJSReceiver()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
......
...@@ -311,17 +311,20 @@ class LoadIC : public IC { ...@@ -311,17 +311,20 @@ class LoadIC : public IC {
private: private:
// Creates a data handler that represents a load of a field by given index. // Creates a data handler that represents a load of a field by given index.
static Handle<Object> SimpleFieldLoad(Isolate* isolate, FieldIndex index); static Handle<Smi> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
// Creates a data handler that represents a prototype chain check followed // Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder. // by given Smi-handler that encoded a load from the holder.
// Can be used only if GetPrototypeCheckCount() returns non negative value. // Can be used only if GetPrototypeCheckCount() returns non negative value.
Handle<Object> LoadFromPrototype(Handle<Map> receiver_map, Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<Name> name, Handle<JSObject> holder, Handle<Name> name,
Handle<Object> smi_handler); Handle<Smi> smi_handler);
// Creates a data handler that represents a load of a non-existent property. // Creates a data handler that represents a load of a non-existent property.
Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name); // {holder} is the object from which the property is loaded. If no holder is
// needed (e.g., for "nonexistent"), null_value() may be passed in.
Handle<Object> LoadFullChain(Handle<Map> receiver_map, Handle<Object> holder,
Handle<Name> name, Handle<Smi> smi_handler);
friend class IC; friend class IC;
friend class NamedLoadHandlerCompiler; friend class NamedLoadHandlerCompiler;
......
...@@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at)); __ Branch(miss, ne, scratch, Operand(at));
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method).
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
__ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
if (must_preserve_receiver_reg) {
__ Pop(receiver(), holder_reg, this->name());
} else {
__ Pop(holder_reg, this->name());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -190,22 +190,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at)); __ Branch(miss, ne, scratch, Operand(at));
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -428,85 +412,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method).
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
__ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
if (must_preserve_receiver_reg) {
__ Pop(receiver(), holder_reg, this->name());
} else {
__ Pop(holder_reg, this->name());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -195,22 +195,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -195,22 +195,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -443,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -443,86 +427,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
__ cmp(r3, scratch1());
__ beq(&interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
__ pop(this->name());
__ pop(holder_reg);
if (must_preserve_receiver_reg) {
__ pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -186,21 +186,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( ...@@ -186,21 +186,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ bne(miss); __ bne(miss);
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name, receiver, holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -425,84 +410,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -425,84 +410,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
__ Push(holder_reg, this->name());
}
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ CompareRoot(r2, Heap::kNoInterceptorResultSentinelRootIndex);
__ beq(&interceptor_failed, Label::kNear);
frame_scope.GenerateLeaveFrame();
__ Ret();
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
__ Pop(this->name());
__ Pop(holder_reg);
if (must_preserve_receiver_reg) {
__ Pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name(), receiver(), holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot(), vector());
} else {
__ Push(scratch3(), scratch2()); // slot, vector
}
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -83,24 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( ...@@ -83,24 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1); __ DecrementCounter(counters->negative_lookups_miss(), 1);
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(name);
__ Push(receiver);
__ Push(holder);
__ CallRuntime(id);
}
// Generate call to api function. // Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall( void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization, MacroAssembler* masm, const CallOptimization& optimization,
...@@ -437,96 +419,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -437,96 +419,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver());
}
__ Push(holder_reg);
__ Push(this->name());
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
__ j(equal, &interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ ret(0);
__ bind(&interceptor_failed);
InterceptorVectorSlotPop(holder_reg);
__ Pop(this->name());
__ Pop(holder_reg);
if (must_preserve_receiver_reg) {
__ Pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
// Call the runtime system to load the interceptor.
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Stack:
// return address
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ Push(receiver());
__ Push(holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ Push(slot());
__ Push(vector());
} else {
__ Push(scratch3()); // slot
__ Push(scratch2()); // vector
}
__ Push(Operand(rsp, 4 * kPointerSize)); // return address
__ movp(Operand(rsp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack); STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
} }
......
...@@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( ...@@ -287,23 +287,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
} }
} }
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm, Register receiver, Register holder, Register name,
Handle<JSObject> holder_obj, Runtime::FunctionId id) {
DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
Runtime::FunctionForId(id)->nargs);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ push(name);
__ push(receiver);
__ push(holder);
__ CallRuntime(id);
}
#undef __ #undef __
#define __ ACCESS_MASM(masm()) #define __ ACCESS_MASM(masm())
...@@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { ...@@ -445,102 +428,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
} }
} }
void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
LookupIterator* it, Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Compile the interceptor call, followed by inline code to load the
// property from further up the prototype chain if the call fails.
// Check that the maps haven't changed.
DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
// Preserve the receiver register explicitly whenever it is different from the
// holder and it is needed should the interceptor return without any result.
// The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
// case might cause a miss during the prototype check.
bool must_perform_prototype_check =
!holder().is_identical_to(it->GetHolder<JSObject>());
bool must_preserve_receiver_reg =
!receiver().is(holder_reg) &&
(it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ push(receiver());
}
__ push(holder_reg);
__ push(this->name());
InterceptorVectorSlotPush(holder_reg);
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method.)
CompileCallLoadPropertyWithInterceptor(
masm(), receiver(), holder_reg, this->name(), holder(),
Runtime::kLoadPropertyWithInterceptorOnly);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
__ cmp(eax, factory()->no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed);
frame_scope.GenerateLeaveFrame();
__ ret(0);
// Clobber registers when generating debug-code to provoke errors.
__ bind(&interceptor_failed);
if (FLAG_debug_code) {
__ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
__ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
__ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
}
InterceptorVectorSlotPop(holder_reg);
__ pop(this->name());
__ pop(holder_reg);
if (must_preserve_receiver_reg) {
__ pop(receiver());
}
// Leave the internal frame.
}
GenerateLoadPostInterceptor(it, holder_reg);
}
void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
DCHECK(holder()->HasNamedInterceptor());
DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
// Call the runtime system to load the interceptor.
// Stack:
// return address
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
__ push(receiver());
__ push(holder_reg);
// See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
if (holder_reg.is(receiver())) {
__ push(slot());
__ push(vector());
} else {
__ push(scratch3()); // slot
__ push(scratch2()); // vector
}
__ push(Operand(esp, 4 * kPointerSize)); // return address
__ mov(Operand(esp, 5 * kPointerSize), name());
__ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
}
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() { void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they // Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only). // are properly loaded by the handler (debug-only).
......
...@@ -694,8 +694,6 @@ void Oddball::OddballVerify() { ...@@ -694,8 +694,6 @@ void Oddball::OddballVerify() {
this == heap->false_value()); this == heap->false_value());
} else if (map() == heap->uninitialized_map()) { } else if (map() == heap->uninitialized_map()) {
CHECK(this == heap->uninitialized_value()); CHECK(this == heap->uninitialized_value());
} else if (map() == heap->no_interceptor_result_sentinel_map()) {
CHECK(this == heap->no_interceptor_result_sentinel());
} else if (map() == heap->arguments_marker_map()) { } else if (map() == heap->arguments_marker_map()) {
CHECK(this == heap->arguments_marker()); CHECK(this == heap->arguments_marker());
} else if (map() == heap->termination_exception_map()) { } else if (map() == heap->termination_exception_map()) {
......
...@@ -658,7 +658,6 @@ namespace internal { ...@@ -658,7 +658,6 @@ namespace internal {
F(LoadGlobalIC_Slow, 3, 1) \ F(LoadGlobalIC_Slow, 3, 1) \
F(LoadIC_Miss, 4, 1) \ F(LoadIC_Miss, 4, 1) \
F(LoadPropertyWithInterceptor, 5, 1) \ F(LoadPropertyWithInterceptor, 5, 1) \
F(LoadPropertyWithInterceptorOnly, 3, 1) \
F(StoreCallbackProperty, 6, 1) \ F(StoreCallbackProperty, 6, 1) \
F(StoreIC_Miss, 5, 1) \ F(StoreIC_Miss, 5, 1) \
F(StorePropertyWithInterceptor, 5, 1) \ F(StorePropertyWithInterceptor, 5, 1) \
......
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