Version 3.29.17 (based on bleeding_edge revision r23372) Performance and stability improvements on all platforms. git-svn-id: https://v8.googlecode.com/svn/trunk@23377 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/BUILD.gn b/BUILD.gn index 8512dea..49ae65a 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -718,6 +718,8 @@ "src/ic/access-compiler.h", "src/ic/call-optimization.cc", "src/ic/call-optimization.h", + "src/ic/handler-compiler.cc", + "src/ic/handler-compiler.h", "src/ic/ic-inl.h", "src/ic/ic.cc", "src/ic/ic.h", @@ -934,6 +936,7 @@ "src/compiler/x64/instruction-selector-x64.cc", "src/compiler/x64/linkage-x64.cc", "src/ic/x64/access-compiler-x64.cc", + "src/ic/x64/handler-compiler-x64.cc", "src/ic/x64/ic-x64.cc", "src/ic/x64/ic-compiler-x64.cc", "src/ic/x64/stub-cache-x64.cc", @@ -973,6 +976,7 @@ "src/compiler/arm/instruction-selector-arm.cc", "src/compiler/arm/linkage-arm.cc", "src/ic/arm/access-compiler-arm.cc", + "src/ic/arm/handler-compiler-arm.cc", "src/ic/arm/ic-arm.cc", "src/ic/arm/ic-compiler-arm.cc", "src/ic/arm/stub-cache-arm.cc", @@ -1023,6 +1027,7 @@ "src/compiler/arm64/instruction-selector-arm64.cc", "src/compiler/arm64/linkage-arm64.cc", "src/ic/arm64/access-compiler-arm64.cc", + "src/ic/arm64/handler-compiler-arm64.cc", "src/ic/arm64/ic-arm64.cc", "src/ic/arm64/ic-compiler-arm64.cc", "src/ic/arm64/stub-cache-arm64.cc", @@ -1046,7 +1051,6 @@ "src/mips/frames-mips.cc", "src/mips/frames-mips.h", "src/mips/full-codegen-mips.cc", - "src/mips/ic-mips.cc", "src/mips/lithium-codegen-mips.cc", "src/mips/lithium-codegen-mips.h", "src/mips/lithium-gap-resolver-mips.cc", @@ -1058,7 +1062,47 @@ "src/mips/regexp-macro-assembler-mips.cc", "src/mips/regexp-macro-assembler-mips.h", "src/mips/simulator-mips.cc", - "src/mips/stub-cache-mips.cc", + "src/ic/mips/access-compiler-mips.cc", + "src/ic/mips/handler-compiler-mips.cc", + "src/ic/mips/ic-mips.cc", + "src/ic/mips/ic-compiler-mips.cc", + "src/ic/mips/stub-cache-mips.cc", + ] + } else if (v8_target_arch == "mips64") { + sources += [ + "src/mips64/assembler-mips64.cc", + "src/mips64/assembler-mips64.h", + "src/mips64/assembler-mips64-inl.h", + "src/mips64/builtins-mips64.cc", + "src/mips64/codegen-mips64.cc", + "src/mips64/codegen-mips64.h", + "src/mips64/code-stubs-mips64.cc", + "src/mips64/code-stubs-mips64.h", + "src/mips64/constants-mips64.cc", + "src/mips64/constants-mips64.h", + "src/mips64/cpu-mips64.cc", + "src/mips64/debug-mips64.cc", + "src/mips64/deoptimizer-mips64.cc", + "src/mips64/disasm-mips64.cc", + "src/mips64/frames-mips64.cc", + "src/mips64/frames-mips64.h", + "src/mips64/full-codegen-mips64.cc", + "src/mips64/lithium-codegen-mips64.cc", + "src/mips64/lithium-codegen-mips64.h", + "src/mips64/lithium-gap-resolver-mips64.cc", + "src/mips64/lithium-gap-resolver-mips64.h", + "src/mips64/lithium-mips64.cc", + "src/mips64/lithium-mips64.h", + "src/mips64/macro-assembler-mips64.cc", + "src/mips64/macro-assembler-mips64.h", + "src/mips64/regexp-macro-assembler-mips64.cc", + "src/mips64/regexp-macro-assembler-mips64.h", + "src/mips64/simulator-mips64.cc", + "src/ic/mips64/access-compiler-mips64.cc", + "src/ic/mips64/handler-compiler-mips64.cc", + "src/ic/mips64/ic-mips64.cc", + "src/ic/mips64/ic-compiler-mips64.cc", + "src/ic/mips64/stub-cache-mips64.cc", ] }
diff --git a/ChangeLog b/ChangeLog index 18bed25..caf6bb9 100644 --- a/ChangeLog +++ b/ChangeLog
@@ -1,3 +1,8 @@ +2014-08-25: Version 3.29.17 + + Performance and stability improvements on all platforms. + + 2014-08-24: Version 3.29.16 Fix issue with numeric property names (issue 3507).
diff --git a/build/toolchain.gypi b/build/toolchain.gypi index 45c1f9d..eddc329 100644 --- a/build/toolchain.gypi +++ b/build/toolchain.gypi
@@ -91,6 +91,9 @@ # Allow to suppress the array bounds warning (default is no suppression). 'wno_array_bounds%': '', + # Link-Time Optimizations + 'use_lto%': 0, + 'variables': { # This is set when building the Android WebView inside the Android build # system, using the 'android' gyp backend. @@ -241,6 +244,15 @@ }], ], }], + # Disable LTO for v8 + # v8 is optimized for speed, which takes precedence over + # size optimization in LTO. + ['use_lto==1', { + 'cflags!': [ + '-flto', + '-ffat-lto-objects', + ], + }], ], }], # _toolset=="target" ],
diff --git a/include/v8.h b/include/v8.h index 9407c6c..cbe8edd 100644 --- a/include/v8.h +++ b/include/v8.h
@@ -1473,6 +1473,30 @@ bool IsPromise() const; /** + * Returns true if this value is a Map. + * This is an experimental feature. + */ + bool IsMap() const; + + /** + * Returns true if this value is a Set. + * This is an experimental feature. + */ + bool IsSet() const; + + /** + * Returns true if this value is a WeakMap. + * This is an experimental feature. + */ + bool IsWeakMap() const; + + /** + * Returns true if this value is a WeakSet. + * This is an experimental feature. + */ + bool IsWeakSet() const; + + /** * Returns true if this value is an ArrayBuffer. * This is an experimental feature. */ @@ -5669,7 +5693,7 @@ static const int kNullValueRootIndex = 7; static const int kTrueValueRootIndex = 8; static const int kFalseValueRootIndex = 9; - static const int kEmptyStringRootIndex = 162; + static const int kEmptyStringRootIndex = 164; // The external allocation limit should be below 256 MB on all architectures // to avoid that resource-constrained embedders run low on memory.
diff --git a/src/accessors.cc b/src/accessors.cc index c2361b3..9a2431b 100644 --- a/src/accessors.cc +++ b/src/accessors.cc
@@ -156,6 +156,46 @@ // +// Accessors::ArgumentsIterator +// + + +void Accessors::ArgumentsIteratorGetter( + v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + DisallowHeapAllocation no_allocation; + HandleScope scope(isolate); + Object* result = isolate->native_context()->array_values_iterator(); + info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate))); +} + + +void Accessors::ArgumentsIteratorSetter( + v8::Local<v8::Name> name, v8::Local<v8::Value> val, + const v8::PropertyCallbackInfo<void>& info) { + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + Handle<JSObject> object = Utils::OpenHandle(*info.This()); + Handle<Object> value = Utils::OpenHandle(*val); + + if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return; + + LookupIterator it(object, Utils::OpenHandle(*name)); + CHECK(it.HasProperty()); + DCHECK(it.HolderIsReceiverOrHiddenPrototype()); + Object::SetDataProperty(&it, value); +} + + +Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo( + Isolate* isolate, PropertyAttributes attributes) { + Handle<Name> name(isolate->native_context()->iterator_symbol(), isolate); + return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, + &ArgumentsIteratorSetter, attributes); +} + + +// // Accessors::ArrayLength //
diff --git a/src/accessors.h b/src/accessors.h index 75099a0..8fc1f84 100644 --- a/src/accessors.h +++ b/src/accessors.h
@@ -13,27 +13,28 @@ // The list of accessor descriptors. This is a second-order macro // taking a macro to be applied to all accessor descriptor names. -#define ACCESSOR_INFO_LIST(V) \ - V(ArrayLength) \ - V(FunctionArguments) \ - V(FunctionCaller) \ - V(FunctionName) \ - V(FunctionLength) \ - V(FunctionPrototype) \ - V(ScriptColumnOffset) \ - V(ScriptCompilationType) \ - V(ScriptContextData) \ - V(ScriptEvalFromScript) \ - V(ScriptEvalFromScriptPosition) \ - V(ScriptEvalFromFunctionName) \ - V(ScriptId) \ - V(ScriptLineEnds) \ - V(ScriptLineOffset) \ - V(ScriptName) \ - V(ScriptSource) \ - V(ScriptType) \ - V(ScriptSourceUrl) \ - V(ScriptSourceMappingUrl) \ +#define ACCESSOR_INFO_LIST(V) \ + V(ArgumentsIterator) \ + V(ArrayLength) \ + V(FunctionArguments) \ + V(FunctionCaller) \ + V(FunctionName) \ + V(FunctionLength) \ + V(FunctionPrototype) \ + V(ScriptColumnOffset) \ + V(ScriptCompilationType) \ + V(ScriptContextData) \ + V(ScriptEvalFromScript) \ + V(ScriptEvalFromScriptPosition) \ + V(ScriptEvalFromFunctionName) \ + V(ScriptId) \ + V(ScriptLineEnds) \ + V(ScriptLineOffset) \ + V(ScriptName) \ + V(ScriptSource) \ + V(ScriptType) \ + V(ScriptSourceUrl) \ + V(ScriptSourceMappingUrl) \ V(StringLength) // Accessors contains all predefined proxy accessors.
diff --git a/src/api.cc b/src/api.cc index b23ec0e..45efd68 100644 --- a/src/api.cc +++ b/src/api.cc
@@ -2412,12 +2412,26 @@ } -bool Value::IsArgumentsObject() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->Arguments_string()); -} +#define VALUE_IS_SPECIFIC_TYPE(Type, Class) \ + bool Value::Is##Type() const { \ + i::Handle<i::Object> obj = Utils::OpenHandle(this); \ + if (!obj->IsHeapObject()) return false; \ + i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); \ + return obj->HasSpecificClassOf(isolate->heap()->Class##_string()); \ + } + +VALUE_IS_SPECIFIC_TYPE(ArgumentsObject, Arguments) +VALUE_IS_SPECIFIC_TYPE(BooleanObject, Boolean) +VALUE_IS_SPECIFIC_TYPE(NumberObject, Number) +VALUE_IS_SPECIFIC_TYPE(StringObject, String) +VALUE_IS_SPECIFIC_TYPE(SymbolObject, Symbol) +VALUE_IS_SPECIFIC_TYPE(Date, Date) +VALUE_IS_SPECIFIC_TYPE(Map, Map) +VALUE_IS_SPECIFIC_TYPE(Set, Set) +VALUE_IS_SPECIFIC_TYPE(WeakMap, WeakMap) +VALUE_IS_SPECIFIC_TYPE(WeakSet, WeakSet) + +#undef VALUE_IS_SPECIFIC_TYPE bool Value::IsBoolean() const { @@ -2454,38 +2468,6 @@ } -bool Value::IsDate() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->Date_string()); -} - - -bool Value::IsStringObject() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->String_string()); -} - - -bool Value::IsSymbolObject() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->Symbol_string()); -} - - -bool Value::IsNumberObject() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->Number_string()); -} - - static bool CheckConstructor(i::Isolate* isolate, i::Handle<i::JSObject> obj, const char* class_name) { @@ -2517,14 +2499,6 @@ } -bool Value::IsBooleanObject() const { - i::Handle<i::Object> obj = Utils::OpenHandle(this); - if (!obj->IsHeapObject()) return false; - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - return obj->HasSpecificClassOf(isolate->heap()->Boolean_string()); -} - - bool Value::IsRegExp() const { i::Handle<i::Object> obj = Utils::OpenHandle(this); return obj->IsJSRegExp(); @@ -3636,7 +3610,7 @@ i::PrototypeIterator iter(isolate, self_obj); if (iter.IsAtEnd()) return Local<Value>(); i::LookupIterator it(i::PrototypeIterator::GetCurrent(iter), key_obj, - i::LookupIterator::CHECK_DERIVED_PROPERTY); + i::LookupIterator::PROTOTYPE_CHAIN_PROPERTY); return GetPropertyByLookup(&it); } @@ -3649,7 +3623,7 @@ i::Handle<i::JSObject> self_obj = Utils::OpenHandle(this); i::Handle<i::String> key_obj = Utils::OpenHandle(*key); i::LookupIterator it(self_obj, key_obj, - i::LookupIterator::CHECK_DERIVED_PROPERTY); + i::LookupIterator::PROTOTYPE_CHAIN_PROPERTY); return GetPropertyByLookup(&it); }
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index a04bb86..d96560f 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc
@@ -9,7 +9,7 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic/ic-compiler.h" +#include "src/ic/handler-compiler.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" @@ -425,7 +425,7 @@ class OpBits: public BitField<Token::Value, 2, 14> {}; Major MajorKey() const { return ConvertToDouble; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return result1_.code() + (result2_.code() << 4) + @@ -1392,7 +1392,7 @@ // Enter the exit frame that transitions from JavaScript to C++. FrameScope scope(masm, StackFrame::MANUAL); - __ EnterExitFrame(save_doubles_); + __ EnterExitFrame(save_doubles()); // Store a copy of argc in callee-saved registers for later. __ mov(r4, Operand(r0)); @@ -1476,7 +1476,7 @@ // sp: stack pointer // fp: frame pointer // Callee-saved register r4 still holds argc. - __ LeaveExitFrame(save_doubles_, r4, true); + __ LeaveExitFrame(save_doubles(), r4, true); __ mov(pc, lr); // Handling of exception.
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index 08efecb..64a0c18 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h
@@ -28,7 +28,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -69,7 +69,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -100,7 +100,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, @@ -140,7 +140,7 @@ class ScratchRegisterBits: public BitField<int, 8, 4> {}; Major MajorKey() const { return WriteInt32ToHeapNumber; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return IntRegisterBits::encode(the_int_.code()) | HeapNumberRegisterBits::encode(the_heap_number_.code()) @@ -307,7 +307,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) | @@ -348,7 +348,7 @@ private: Major MajorKey() const { return DirectCEntry; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } bool NeedsImmovableCode() { return true; } }; @@ -395,7 +395,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { return LookupModeBits::encode(mode_); } + uint32_t MinorKey() const { return LookupModeBits::encode(mode_); } class LookupModeBits: public BitField<LookupMode, 0, 1> {};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index e2658f3..cb0277e 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc
@@ -931,7 +931,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -2990,6 +2990,19 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(r0)); + __ mov(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); @@ -2997,13 +3010,7 @@ __ mov(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(r0)); - __ mov(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -3126,13 +3133,7 @@ // Name is always in r2. __ mov(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(r0)); - __ mov(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); @@ -3422,13 +3423,7 @@ DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(r0)); - __ mov(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h index ee5f4e9..0094755 100644 --- a/src/arm/lithium-codegen-arm.h +++ b/src/arm/lithium-codegen-arm.h
@@ -332,6 +332,9 @@ void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); + template <class T> + void EmitVectorLoadICRegisters(T* instr); + ZoneList<LEnvironment*> deoptimizations_; ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_; ZoneList<Handle<Object> > deoptimization_literals_;
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index 23a5737..c00b572 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc
@@ -9,7 +9,7 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic/ic-compiler.h" +#include "src/ic/handler-compiler.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" @@ -1377,7 +1377,7 @@ // Enter the exit frame. Reserve three slots to preserve x21-x23 callee-saved // registers. FrameScope scope(masm, StackFrame::MANUAL); - __ EnterExitFrame(save_doubles_, x10, 3); + __ EnterExitFrame(save_doubles(), x10, 3); DCHECK(csp.Is(__ StackPointer())); // Poke callee-saved registers into reserved space. @@ -1474,7 +1474,7 @@ __ Peek(argc, 2 * kPointerSize); __ Peek(target, 3 * kPointerSize); - __ LeaveExitFrame(save_doubles_, x10, true); + __ LeaveExitFrame(save_doubles(), x10, true); DCHECK(jssp.Is(__ StackPointer())); // Pop or drop the remaining stack slots and return from the stub. // jssp[24]: Arguments array (of size argc), including receiver.
diff --git a/src/arm64/code-stubs-arm64.h b/src/arm64/code-stubs-arm64.h index 6ba2f57..cb4738d 100644 --- a/src/arm64/code-stubs-arm64.h +++ b/src/arm64/code-stubs-arm64.h
@@ -28,7 +28,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -63,7 +63,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return StoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -77,7 +77,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return RestoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -303,16 +303,14 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return MinorKeyFor(object_, value_, address_, remembered_set_action_, save_fp_regs_mode_); } - static int MinorKeyFor(Register object, - Register value, - Register address, - RememberedSetAction action, - SaveFPRegsMode fp_mode) { + static uint32_t MinorKeyFor(Register object, Register value, Register address, + RememberedSetAction action, + SaveFPRegsMode fp_mode) { DCHECK(object.Is64Bits()); DCHECK(value.Is64Bits()); DCHECK(address.Is64Bits()); @@ -353,7 +351,7 @@ private: Major MajorKey() const { return DirectCEntry; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } bool NeedsImmovableCode() { return true; } }; @@ -400,7 +398,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { return LookupModeBits::encode(mode_); } + uint32_t MinorKey() const { return LookupModeBits::encode(mode_); } class LookupModeBits: public BitField<LookupMode, 0, 1> {}; @@ -414,7 +412,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -444,7 +442,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm,
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index d6c9ef6..b5fef7e 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc
@@ -937,7 +937,7 @@ if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -3344,19 +3344,25 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ Mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(x0)); + __ Mov(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); DCHECK(ToRegister(instr->result()).Is(x0)); __ Mov(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(x0)); - __ Mov(LoadIC::SlotRegister(), - Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -3611,13 +3617,7 @@ DCHECK(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(x0)); - __ Mov(LoadIC::SlotRegister(), - Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); @@ -3673,13 +3673,7 @@ DCHECK(ToRegister(instr->object()).is(LoadIC::ReceiverRegister())); __ Mov(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(x0)); - __ Mov(LoadIC::SlotRegister(), - Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL);
diff --git a/src/arm64/lithium-codegen-arm64.h b/src/arm64/lithium-codegen-arm64.h index 7baa05d..e16d44a 100644 --- a/src/arm64/lithium-codegen-arm64.h +++ b/src/arm64/lithium-codegen-arm64.h
@@ -196,6 +196,9 @@ int* offset, AllocationSiteMode mode); + template <class T> + void EmitVectorLoadICRegisters(T* instr); + // Emits optimized code for %_IsString(x). Preserves input register. // Returns the condition on which a final split to // true and false label should be made, to optimize fallthrough.
diff --git a/src/base/bits.h b/src/base/bits.h index 129bf62..04a0300 100644 --- a/src/base/bits.h +++ b/src/base/bits.h
@@ -17,8 +17,8 @@ namespace base { namespace bits { -// CountSetBits32(value) returns the number of bits set in |value|. -inline uint32_t CountSetBits32(uint32_t value) { +// CountPopulation32(value) returns the number of bits set in |value|. +inline uint32_t CountPopulation32(uint32_t value) { #if V8_HAS_BUILTIN_POPCOUNT return __builtin_popcount(value); #else @@ -47,7 +47,7 @@ value = value | (value >> 4); value = value | (value >> 8); value = value | (value >> 16); - return CountSetBits32(~value); + return CountPopulation32(~value); #endif }
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index fc0af00..e0e90b3 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc
@@ -780,7 +780,7 @@ name, code, prototype, JS_GLOBAL_OBJECT_TYPE, JSGlobalObject::kSize); #ifdef DEBUG LookupIterator it(prototype, factory()->constructor_string(), - LookupIterator::CHECK_PROPERTY); + LookupIterator::OWN_PROPERTY); Handle<Object> value = JSReceiver::GetProperty(&it).ToHandleChecked(); DCHECK(it.IsFound()); DCHECK_EQ(*isolate()->object_function(), *value); @@ -1204,6 +1204,7 @@ DONT_ENUM, Representation::Tagged()); map->AppendDescriptor(&d); } + // @@iterator method is added later. map->set_function_with_prototype(true); map->set_pre_allocated_property_fields(2); @@ -1262,6 +1263,7 @@ CallbacksDescriptor d(factory->caller_string(), caller, attributes); map->AppendDescriptor(&d); } + // @@iterator method is added later. map->set_function_with_prototype(true); map->set_prototype(native_context()->object_function()->prototype()); @@ -1596,6 +1598,7 @@ INSTALL_NATIVE(Symbol, "symbolIterator", iterator_symbol); INSTALL_NATIVE(Symbol, "symbolUnscopables", unscopables_symbol); + INSTALL_NATIVE(JSFunction, "ArrayValues", array_values_iterator); INSTALL_NATIVE_MATH(abs) INSTALL_NATIVE_MATH(acos) @@ -2039,6 +2042,34 @@ native_context()->set_regexp_result_map(*initial_map); } + // Add @@iterator method to the arguments object maps. + { + PropertyAttributes attribs = DONT_ENUM; + Handle<AccessorInfo> arguments_iterator = + Accessors::ArgumentsIteratorInfo(isolate(), attribs); + { + CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()), + arguments_iterator, attribs); + Handle<Map> map(native_context()->sloppy_arguments_map()); + Map::EnsureDescriptorSlack(map, 1); + map->AppendDescriptor(&d); + } + { + CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()), + arguments_iterator, attribs); + Handle<Map> map(native_context()->aliased_arguments_map()); + Map::EnsureDescriptorSlack(map, 1); + map->AppendDescriptor(&d); + } + { + CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()), + arguments_iterator, attribs); + Handle<Map> map(native_context()->strict_arguments_map()); + Map::EnsureDescriptorSlack(map, 1); + map->AppendDescriptor(&d); + } + } + #ifdef VERIFY_HEAP builtins->ObjectVerify(); #endif @@ -2449,7 +2480,7 @@ } case CALLBACKS: { Handle<Name> key(descs->GetKey(i)); - LookupIterator it(to, key, LookupIterator::CHECK_PROPERTY); + LookupIterator it(to, key, LookupIterator::OWN_PROPERTY); // If the property is already there we skip it if (it.IsFound() && it.HasProperty()) continue; HandleScope inner(isolate()); @@ -2480,7 +2511,7 @@ DCHECK(raw_key->IsName()); // If the property is already there we skip it. Handle<Name> key(Name::cast(raw_key)); - LookupIterator it(to, key, LookupIterator::CHECK_PROPERTY); + LookupIterator it(to, key, LookupIterator::OWN_PROPERTY); if (it.IsFound() && it.HasProperty()) continue; // Set the property. Handle<Object> value = Handle<Object>(properties->ValueAt(i),
diff --git a/src/builtins.cc b/src/builtins.cc index 0f7bc20..7c64f65 100644 --- a/src/builtins.cc +++ b/src/builtins.cc
@@ -13,8 +13,8 @@ #include "src/gdb-jit.h" #include "src/heap/mark-compact.h" #include "src/heap-profiler.h" +#include "src/ic/handler-compiler.h" #include "src/ic/ic.h" -#include "src/ic/ic-compiler.h" #include "src/prototype.h" #include "src/vm-state-inl.h" @@ -1298,11 +1298,6 @@ } -static void Generate_StoreIC_Slow(MacroAssembler* masm) { - StoreIC::GenerateSlow(masm); -} - - static void Generate_StoreIC_Miss(MacroAssembler* masm) { StoreIC::GenerateMiss(masm); } @@ -1313,6 +1308,16 @@ } +static void Generate_StoreIC_Slow(MacroAssembler* masm) { + NamedStoreHandlerCompiler::GenerateSlow(masm); +} + + +static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) { + ElementHandlerCompiler::GenerateStoreSlow(masm); +} + + static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) { NamedStoreHandlerCompiler::GenerateStoreViaSetterForDeopt(masm); } @@ -1333,11 +1338,6 @@ } -static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) { - KeyedStoreIC::GenerateSlow(masm); -} - - static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) { KeyedStoreIC::GenerateInitialize(masm); }
diff --git a/src/code-stubs.cc b/src/code-stubs.cc index b190321..9b84122 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc
@@ -9,7 +9,7 @@ #include "src/cpu-profiler.h" #include "src/factory.h" #include "src/gdb-jit.h" -#include "src/ic/ic-compiler.h" +#include "src/ic/handler-compiler.h" #include "src/macro-assembler.h" namespace v8 { @@ -380,7 +380,7 @@ } -int ICCompareStub::MinorKey() const { +uint32_t ICCompareStub::MinorKey() const { return OpField::encode(op_ - Token::EQ) | LeftStateField::encode(left_) | RightStateField::encode(right_) | @@ -690,7 +690,7 @@ UNREACHABLE(); break; case DICTIONARY_ELEMENTS: - ElementHandlerCompiler::GenerateStoreDictionaryElement(masm); + ElementHandlerCompiler::GenerateStoreSlow(masm); break; case SLOPPY_ARGUMENTS_ELEMENTS: UNREACHABLE();
diff --git a/src/code-stubs.h b/src/code-stubs.h index 4d021c2..9f18772 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h
@@ -150,7 +150,7 @@ static Major MajorKeyFromKey(uint32_t key) { return static_cast<Major>(MajorKeyBits::decode(key)); } - static int MinorKeyFromKey(uint32_t key) { + static uint32_t MinorKeyFromKey(uint32_t key) { return MinorKeyBits::decode(key); } @@ -163,7 +163,7 @@ static const char* MajorName(Major major_key, bool allow_unknown_keys); - explicit CodeStub(Isolate* isolate) : isolate_(isolate) { } + explicit CodeStub(Isolate* isolate) : minor_key_(0), isolate_(isolate) {} virtual ~CodeStub() {} static void GenerateStubsAheadOfTime(Isolate* isolate); @@ -182,7 +182,7 @@ // Returns information for computing the number key. virtual Major MajorKey() const = 0; - virtual int MinorKey() const = 0; + virtual uint32_t MinorKey() const { return minor_key_; } virtual InlineCacheState GetICState() const { return UNINITIALIZED; } virtual ExtraICState GetExtraICState() const { return kNoExtraICState; } @@ -215,6 +215,8 @@ return MinorKeyBits::encode(MinorKey()) | MajorKeyBits::encode(MajorKey()); } + uint32_t minor_key_; + private: // Perform bookkeeping required after code generation when stub code is // initially generated. @@ -476,7 +478,7 @@ class IsMissBits: public BitField<bool, kStubMinorKeyBits - 1, 1> {}; void GenerateLightweightMiss(MacroAssembler* masm); - virtual int MinorKey() const { + virtual uint32_t MinorKey() const { return IsMissBits::encode(is_uninitialized_) | MinorKeyBits::encode(NotMissMinorKey()); } @@ -753,7 +755,7 @@ private: Major MajorKey() const { return Instanceof; } - int MinorKey() const { return static_cast<int>(flags_); } + uint32_t MinorKey() const { return static_cast<int>(flags_); } bool HasArgsInRegisters() const { return (flags_ & kArgsInRegisters) != 0; @@ -794,7 +796,7 @@ virtual void PrintName(OStream& os) const V8_OVERRIDE; // NOLINT virtual CodeStub::Major MajorKey() const { return ArrayConstructor; } - virtual int MinorKey() const { return argument_count_; } + virtual uint32_t MinorKey() const { return argument_count_; } ArgumentCountKey argument_count_; }; @@ -808,7 +810,7 @@ private: virtual CodeStub::Major MajorKey() const { return InternalArrayConstructor; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } void GenerateCase(MacroAssembler* masm, ElementsKind kind); }; @@ -824,7 +826,7 @@ private: virtual CodeStub::Major MajorKey() const { return MathPow; } - virtual int MinorKey() const { return exponent_type_; } + virtual uint32_t MinorKey() const { return exponent_type_; } ExponentType exponent_type_; }; @@ -857,7 +859,7 @@ } protected: - virtual int MinorKey() const { return GetExtraICState(); } + virtual uint32_t MinorKey() const { return GetExtraICState(); } virtual void PrintState(OStream& os) const V8_OVERRIDE; // NOLINT virtual CodeStub::Major MajorKey() const { return CallIC; } @@ -897,7 +899,7 @@ private: virtual CodeStub::Major MajorKey() const { return FunctionPrototype; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } }; @@ -1083,7 +1085,7 @@ private: virtual void Generate(MacroAssembler* masm) V8_OVERRIDE; virtual Major MajorKey() const V8_OVERRIDE { return CallApiFunction; } - virtual int MinorKey() const V8_OVERRIDE { return bit_field_; } + virtual uint32_t MinorKey() const V8_OVERRIDE { return bit_field_; } class IsStoreBits: public BitField<bool, 0, 1> {}; class CallDataUndefinedBits: public BitField<bool, 1, 1> {}; @@ -1102,7 +1104,7 @@ private: virtual void Generate(MacroAssembler* masm) V8_OVERRIDE; virtual Major MajorKey() const V8_OVERRIDE { return CallApiGetter; } - virtual int MinorKey() const V8_OVERRIDE { return 0; } + virtual uint32_t MinorKey() const V8_OVERRIDE { return 0; } DISALLOW_COPY_AND_ASSIGN(CallApiGetterStub); }; @@ -1196,7 +1198,7 @@ virtual Major MajorKey() const V8_OVERRIDE { return BinaryOpICWithAllocationSite; } - virtual int MinorKey() const V8_OVERRIDE { return GetExtraICState(); } + virtual uint32_t MinorKey() const V8_OVERRIDE { return GetExtraICState(); } private: static void GenerateAheadOfTime(Isolate* isolate, @@ -1327,7 +1329,7 @@ class HandlerStateField: public BitField<int, 11, 4> { }; virtual CodeStub::Major MajorKey() const { return CompareIC; } - virtual int MinorKey() const; + virtual uint32_t MinorKey() const; virtual Code::Kind GetCodeKind() const { return Code::COMPARE_IC; } @@ -1460,12 +1462,15 @@ class CEntryStub : public PlatformCodeStub { public: - CEntryStub(Isolate* isolate, - int result_size, + CEntryStub(Isolate* isolate, int result_size, SaveFPRegsMode save_doubles = kDontSaveFPRegs) - : PlatformCodeStub(isolate), - result_size_(result_size), - save_doubles_(save_doubles) { } + : PlatformCodeStub(isolate) { + minor_key_ = SaveDoublesBits::encode(save_doubles == kSaveFPRegs); + DCHECK(result_size == 1 || result_size == 2); +#ifdef _WIN64 + minor_key_ = ResultSizeBits::update(minor_key_, result_size); +#endif // _WIN64 + } void Generate(MacroAssembler* masm); @@ -1476,14 +1481,17 @@ static void GenerateAheadOfTime(Isolate* isolate); private: - // Number of pointers/values returned. - const int result_size_; - SaveFPRegsMode save_doubles_; - Major MajorKey() const { return CEntry; } - int MinorKey() const; + + bool save_doubles() const { return SaveDoublesBits::decode(minor_key_); } +#ifdef _WIN64 + int result_size() const { return ResultSizeBits::decode(minor_key_); } +#endif // _WIN64 bool NeedsImmovableCode(); + + class SaveDoublesBits : public BitField<bool, 0, 1> {}; + class ResultSizeBits : public BitField<int, 1, 3> {}; }; @@ -1498,7 +1506,7 @@ private: Major MajorKey() const { return JSEntry; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } virtual void FinishCode(Handle<Code> code); @@ -1513,7 +1521,7 @@ void Generate(MacroAssembler* masm) { GenerateBody(masm, true); } private: - int MinorKey() const { return 1; } + uint32_t MinorKey() const { return 1; } virtual void PrintName(OStream& os) const V8_OVERRIDE { // NOLINT os << "JSConstructEntryStub"; @@ -1537,7 +1545,7 @@ Type type_; Major MajorKey() const { return ArgumentsAccess; } - int MinorKey() const { return type_; } + uint32_t MinorKey() const { return type_; } void Generate(MacroAssembler* masm); void GenerateReadElement(MacroAssembler* masm); @@ -1555,7 +1563,7 @@ private: Major MajorKey() const { return RegExpExec; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -1615,7 +1623,7 @@ STATIC_ASSERT(Code::kArgumentsBits + 2 <= kStubMinorKeyBits); Major MajorKey() const { return CallFunction; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 32 bit value. return FlagBits::encode(flags_) | ArgcBits::encode(argc_); } @@ -1650,7 +1658,7 @@ virtual void PrintName(OStream& os) const V8_OVERRIDE; // NOLINT Major MajorKey() const { return CallConstruct; } - int MinorKey() const { return flags_; } + uint32_t MinorKey() const { return flags_; } bool RecordCallTarget() const { return (flags_ & RECORD_CONSTRUCTOR_TARGET) != 0; @@ -1859,7 +1867,7 @@ private: Major MajorKey() const { return LoadElement; } - int MinorKey() const { return DICTIONARY_ELEMENTS; } + uint32_t MinorKey() const { return DICTIONARY_ELEMENTS; } DISALLOW_COPY_AND_ASSIGN(LoadDictionaryElementPlatformStub); }; @@ -1946,7 +1954,7 @@ public BitField<int, 2 * kBitsPerRegisterNumber + 5, 1> {}; // NOLINT Major MajorKey() const { return DoubleToI; } - int MinorKey() const { return bit_field_; } + uint32_t MinorKey() const { return bit_field_; } int bit_field_; @@ -2282,7 +2290,7 @@ store_mode_(store_mode) {} Major MajorKey() const { return StoreElement; } - int MinorKey() const { + uint32_t MinorKey() const { return ElementsKindBits::encode(elements_kind_) | IsJSArrayBits::encode(is_js_array_) | StoreModeBits::encode(store_mode_); @@ -2472,7 +2480,7 @@ private: Major MajorKey() const { return StoreArrayLiteralElement; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); @@ -2492,7 +2500,9 @@ class FunctionModeField: public BitField<StubFunctionMode, 0, 1> {}; Major MajorKey() const { return StubFailureTrampoline; } - int MinorKey() const { return FunctionModeField::encode(function_mode_); } + uint32_t MinorKey() const { + return FunctionModeField::encode(function_mode_); + } void Generate(MacroAssembler* masm); @@ -2518,7 +2528,7 @@ Isolate* isolate); Major MajorKey() const { return ProfileEntryHook; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm);
diff --git a/src/codegen.cc b/src/codegen.cc index 8b54ff5..082905a 100644 --- a/src/codegen.cc +++ b/src/codegen.cc
@@ -252,16 +252,4 @@ } } - -int CEntryStub::MinorKey() const { - int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0; - DCHECK(result_size_ == 1 || result_size_ == 2); -#ifdef _WIN64 - return result | ((result_size_ == 1) ? 0 : 2); -#else - return result; -#endif -} - - } } // namespace v8::internal
diff --git a/src/compiler.cc b/src/compiler.cc index bddb327..7918920 100644 --- a/src/compiler.cc +++ b/src/compiler.cc
@@ -414,7 +414,9 @@ compiler::Pipeline pipeline(info()); pipeline.GenerateCode(); if (!info()->code().is_null()) { - info()->context()->native_context()->AddOptimizedCode(*info()->code()); + if (FLAG_turbo_deoptimization) { + info()->context()->native_context()->AddOptimizedCode(*info()->code()); + } return SetLastStatus(SUCCEEDED); } }
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc index 19a7b94..a8678bd 100644 --- a/src/compiler/arm/code-generator-arm.cc +++ b/src/compiler/arm/code-generator-arm.cc
@@ -377,42 +377,49 @@ DCHECK_EQ(LeaveCC, i.OutputSBit()); break; } - case kArmLoadWord8: + case kArmLdrb: __ ldrb(i.OutputRegister(), i.InputOffset()); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; - case kArmStoreWord8: { + case kArmLdrsb: + __ ldrsb(i.OutputRegister(), i.InputOffset()); + DCHECK_EQ(LeaveCC, i.OutputSBit()); + break; + case kArmStrb: { int index = 0; MemOperand operand = i.InputOffset(&index); __ strb(i.InputRegister(index), operand); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; } - case kArmLoadWord16: + case kArmLdrh: __ ldrh(i.OutputRegister(), i.InputOffset()); break; - case kArmStoreWord16: { + case kArmLdrsh: + __ ldrsh(i.OutputRegister(), i.InputOffset()); + break; + case kArmStrh: { int index = 0; MemOperand operand = i.InputOffset(&index); __ strh(i.InputRegister(index), operand); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; } - case kArmLoadWord32: + case kArmLdr: __ ldr(i.OutputRegister(), i.InputOffset()); break; - case kArmStoreWord32: { + case kArmStr: { int index = 0; MemOperand operand = i.InputOffset(&index); __ str(i.InputRegister(index), operand); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; } - case kArmFloat64Load: + case kArmVldr64: __ vldr(i.OutputDoubleRegister(), i.InputOffset()); DCHECK_EQ(LeaveCC, i.OutputSBit()); break; - case kArmFloat64Store: { + case kArmVstr64: { int index = 0; MemOperand operand = i.InputOffset(&index); __ vstr(i.InputDoubleRegister(index), operand);
diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h index 1d5b5c7..ab86ce4 100644 --- a/src/compiler/arm/instruction-codes-arm.h +++ b/src/compiler/arm/instruction-codes-arm.h
@@ -50,14 +50,16 @@ V(ArmVcvtF64U32) \ V(ArmVcvtS32F64) \ V(ArmVcvtU32F64) \ - V(ArmFloat64Load) \ - V(ArmFloat64Store) \ - V(ArmLoadWord8) \ - V(ArmStoreWord8) \ - V(ArmLoadWord16) \ - V(ArmStoreWord16) \ - V(ArmLoadWord32) \ - V(ArmStoreWord32) \ + V(ArmVldr64) \ + V(ArmVstr64) \ + V(ArmLdrb) \ + V(ArmLdrsb) \ + V(ArmStrb) \ + V(ArmLdrh) \ + V(ArmLdrsh) \ + V(ArmStrh) \ + V(ArmLdr) \ + V(ArmStr) \ V(ArmStoreWriteBarrier)
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index 3bf7e2f..6ec86bd 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -55,19 +55,21 @@ case kArmRsb: return ImmediateFitsAddrMode1Instruction(value); - case kArmFloat64Load: - case kArmFloat64Store: + case kArmVldr64: + case kArmVstr64: return value >= -1020 && value <= 1020 && (value % 4) == 0; - case kArmLoadWord8: - case kArmStoreWord8: - case kArmLoadWord32: - case kArmStoreWord32: + case kArmLdrb: + case kArmLdrsb: + case kArmStrb: + case kArmLdr: + case kArmStr: case kArmStoreWriteBarrier: return value >= -4095 && value <= 4095; - case kArmLoadWord16: - case kArmStoreWord16: + case kArmLdrh: + case kArmLdrsh: + case kArmStrh: return value >= -255 && value <= 255; case kArchJmp: @@ -287,6 +289,7 @@ void InstructionSelector::VisitLoad(Node* node) { MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); + MachineType typ = TypeOf(OpParameter<MachineType>(node)); ArmOperandGenerator g(this); Node* base = node->InputAt(0); Node* index = node->InputAt(1); @@ -296,21 +299,20 @@ : g.DefineAsRegister(node); ArchOpcode opcode; - // TODO(titzer): signed/unsigned small loads switch (rep) { case kRepFloat64: - opcode = kArmFloat64Load; + opcode = kArmVldr64; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kArmLoadWord8; + opcode = typ == kTypeUint32 ? kArmLdrb : kArmLdrsb; break; case kRepWord16: - opcode = kArmLoadWord16; + opcode = typ == kTypeUint32 ? kArmLdrh : kArmLdrsh; break; case kRepTagged: // Fall through. case kRepWord32: - opcode = kArmLoadWord32; + opcode = kArmLdr; break; default: UNREACHABLE(); @@ -320,9 +322,6 @@ if (g.CanBeImmediate(index, opcode)) { Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), result, g.UseRegister(base), g.UseImmediate(index)); - } else if (g.CanBeImmediate(base, opcode)) { - Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), result, - g.UseRegister(index), g.UseImmediate(base)); } else { Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), result, g.UseRegister(base), g.UseRegister(index)); @@ -356,18 +355,18 @@ ArchOpcode opcode; switch (rep) { case kRepFloat64: - opcode = kArmFloat64Store; + opcode = kArmVstr64; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kArmStoreWord8; + opcode = kArmStrb; break; case kRepWord16: - opcode = kArmStoreWord16; + opcode = kArmStrh; break; case kRepTagged: // Fall through. case kRepWord32: - opcode = kArmStoreWord32; + opcode = kArmStr; break; default: UNREACHABLE(); @@ -377,9 +376,6 @@ if (g.CanBeImmediate(index, opcode)) { Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, g.UseRegister(base), g.UseImmediate(index), val); - } else if (g.CanBeImmediate(base, opcode)) { - Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), NULL, - g.UseRegister(index), g.UseImmediate(base), val); } else { Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), NULL, g.UseRegister(base), g.UseRegister(index), val); @@ -423,7 +419,7 @@ } if (IsSupported(ARMv7) && m.right().HasValue()) { uint32_t value = m.right().Value(); - uint32_t width = base::bits::CountSetBits32(value); + uint32_t width = base::bits::CountPopulation32(value); uint32_t msb = base::bits::CountLeadingZeros32(value); if (width != 0 && msb + width == 32) { DCHECK_EQ(0, base::bits::CountTrailingZeros32(value)); @@ -536,7 +532,7 @@ Int32BinopMatcher mleft(m.left().node()); if (mleft.right().HasValue()) { uint32_t value = (mleft.right().Value() >> lsb) << lsb; - uint32_t width = base::bits::CountSetBits32(value); + uint32_t width = base::bits::CountPopulation32(value); uint32_t msb = base::bits::CountLeadingZeros32(value); if (msb + width + lsb == 32) { DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index ab0236f..baacc85 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc
@@ -396,34 +396,40 @@ case kArm64Uint32ToFloat64: __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0)); break; - case kArm64LoadWord8: + case kArm64Ldrb: __ Ldrb(i.OutputRegister(), i.MemoryOperand()); break; - case kArm64StoreWord8: + case kArm64Ldrsb: + __ Ldrsb(i.OutputRegister(), i.MemoryOperand()); + break; + case kArm64Strb: __ Strb(i.InputRegister(2), i.MemoryOperand()); break; - case kArm64LoadWord16: + case kArm64Ldrh: __ Ldrh(i.OutputRegister(), i.MemoryOperand()); break; - case kArm64StoreWord16: + case kArm64Ldrsh: + __ Ldrsh(i.OutputRegister(), i.MemoryOperand()); + break; + case kArm64Strh: __ Strh(i.InputRegister(2), i.MemoryOperand()); break; - case kArm64LoadWord32: + case kArm64LdrW: __ Ldr(i.OutputRegister32(), i.MemoryOperand()); break; - case kArm64StoreWord32: + case kArm64StrW: __ Str(i.InputRegister32(2), i.MemoryOperand()); break; - case kArm64LoadWord64: + case kArm64Ldr: __ Ldr(i.OutputRegister(), i.MemoryOperand()); break; - case kArm64StoreWord64: + case kArm64Str: __ Str(i.InputRegister(2), i.MemoryOperand()); break; - case kArm64Float64Load: + case kArm64LdrD: __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand()); break; - case kArm64Float64Store: + case kArm64StrD: __ Str(i.InputDoubleRegister(2), i.MemoryOperand()); break; case kArm64StoreWriteBarrier: {
diff --git a/src/compiler/arm64/instruction-codes-arm64.h b/src/compiler/arm64/instruction-codes-arm64.h index cb4d18e..bce47f8 100644 --- a/src/compiler/arm64/instruction-codes-arm64.h +++ b/src/compiler/arm64/instruction-codes-arm64.h
@@ -68,16 +68,18 @@ V(Arm64Float64ToUint32) \ V(Arm64Int32ToFloat64) \ V(Arm64Uint32ToFloat64) \ - V(Arm64Float64Load) \ - V(Arm64Float64Store) \ - V(Arm64LoadWord8) \ - V(Arm64StoreWord8) \ - V(Arm64LoadWord16) \ - V(Arm64StoreWord16) \ - V(Arm64LoadWord32) \ - V(Arm64StoreWord32) \ - V(Arm64LoadWord64) \ - V(Arm64StoreWord64) \ + V(Arm64LdrD) \ + V(Arm64StrD) \ + V(Arm64Ldrb) \ + V(Arm64Ldrsb) \ + V(Arm64Strb) \ + V(Arm64Ldrh) \ + V(Arm64Ldrsh) \ + V(Arm64Strh) \ + V(Arm64LdrW) \ + V(Arm64StrW) \ + V(Arm64Ldr) \ + V(Arm64Str) \ V(Arm64StoreWriteBarrier)
diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index dd1857b..410105c 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc
@@ -143,6 +143,7 @@ void InstructionSelector::VisitLoad(Node* node) { MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); + MachineType typ = TypeOf(OpParameter<MachineType>(node)); Arm64OperandGenerator g(this); Node* base = node->InputAt(0); Node* index = node->InputAt(1); @@ -155,21 +156,21 @@ // TODO(titzer): signed/unsigned small loads switch (rep) { case kRepFloat64: - opcode = kArm64Float64Load; + opcode = kArm64LdrD; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kArm64LoadWord8; + opcode = typ == kTypeInt32 ? kArm64Ldrsb : kArm64Ldrb; break; case kRepWord16: - opcode = kArm64LoadWord16; + opcode = typ == kTypeInt32 ? kArm64Ldrsh : kArm64Ldrh; break; case kRepWord32: - opcode = kArm64LoadWord32; + opcode = kArm64LdrW; break; case kRepTagged: // Fall through. case kRepWord64: - opcode = kArm64LoadWord64; + opcode = kArm64Ldr; break; default: UNREACHABLE(); @@ -178,9 +179,6 @@ if (g.CanBeImmediate(index, kLoadStoreImm)) { Emit(opcode | AddressingModeField::encode(kMode_MRI), result, g.UseRegister(base), g.UseImmediate(index)); - } else if (g.CanBeImmediate(base, kLoadStoreImm)) { - Emit(opcode | AddressingModeField::encode(kMode_MRI), result, - g.UseRegister(index), g.UseImmediate(base)); } else { Emit(opcode | AddressingModeField::encode(kMode_MRR), result, g.UseRegister(base), g.UseRegister(index)); @@ -217,21 +215,21 @@ ArchOpcode opcode; switch (rep) { case kRepFloat64: - opcode = kArm64Float64Store; + opcode = kArm64StrD; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kArm64StoreWord8; + opcode = kArm64Strb; break; case kRepWord16: - opcode = kArm64StoreWord16; + opcode = kArm64Strh; break; case kRepWord32: - opcode = kArm64StoreWord32; + opcode = kArm64StrW; break; case kRepTagged: // Fall through. case kRepWord64: - opcode = kArm64StoreWord64; + opcode = kArm64Str; break; default: UNREACHABLE(); @@ -240,9 +238,6 @@ if (g.CanBeImmediate(index, kLoadStoreImm)) { Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, g.UseRegister(base), g.UseImmediate(index), val); - } else if (g.CanBeImmediate(base, kLoadStoreImm)) { - Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, - g.UseRegister(index), g.UseImmediate(base), val); } else { Emit(opcode | AddressingModeField::encode(kMode_MRR), NULL, g.UseRegister(base), g.UseRegister(index), val);
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 66a371b..0e642c9 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc
@@ -744,13 +744,13 @@ // Bind value and do loop body. VisitForInAssignment(stmt->each(), value); VisitIterationBody(stmt, &for_loop, 5); + for_loop.EndBody(); // Inc counter and continue. Node* index_inc = NewNode(javascript()->Add(), index, jsgraph()->OneConstant()); // TODO(jarin): provide real bailout id. PrepareFrameState(index_inc, BailoutId::None()); environment()->Poke(0, index_inc); - for_loop.EndBody(); for_loop.EndLoop(); environment()->Drop(5); // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index 5a5d9f9..1cbb596 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc
@@ -53,6 +53,7 @@ FinishCode(masm()); + UpdateSafepointsWithDeoptimizationPc(); safepoints()->Emit(masm(), frame()->GetSpillSlotCount()); // TODO(titzer): what are the right code flags here? @@ -76,9 +77,10 @@ } -void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind, - int arguments, - Safepoint::DeoptMode deopt_mode) { +Safepoint::Id CodeGenerator::RecordSafepoint(PointerMap* pointers, + Safepoint::Kind kind, + int arguments, + Safepoint::DeoptMode deopt_mode) { const ZoneList<InstructionOperand*>* operands = pointers->GetNormalizedOperands(); Safepoint safepoint = @@ -92,6 +94,7 @@ safepoint.DefinePointerRegister(reg, zone()); } } + return safepoint.id(); } @@ -172,13 +175,25 @@ } +void CodeGenerator::UpdateSafepointsWithDeoptimizationPc() { + int patch_count = static_cast<int>(lazy_deoptimization_entries_.size()); + for (int i = 0; i < patch_count; ++i) { + LazyDeoptimizationEntry entry = lazy_deoptimization_entries_[i]; + // TODO(jarin) make sure that there is no code (other than nops) + // between the call position and the continuation position. + safepoints()->SetDeoptimizationPc(entry.safepoint_id(), + entry.deoptimization()->pos()); + } +} + + void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { CompilationInfo* info = linkage()->info(); int deopt_count = code()->GetDeoptimizationEntryCount(); int patch_count = static_cast<int>(lazy_deoptimization_entries_.size()); if (patch_count == 0 && deopt_count == 0) return; - Handle<DeoptimizationInputData> data = DeoptimizationInputData::New( - isolate(), deopt_count, patch_count, TENURED); + Handle<DeoptimizationInputData> data = + DeoptimizationInputData::New(isolate(), deopt_count, TENURED); Handle<ByteArray> translation_array = translations_.CreateByteArray(isolate()->factory()); @@ -222,13 +237,6 @@ data->SetPc(i, Smi::FromInt(-1)); } - // Populate the return address patcher entries. - for (int i = 0; i < patch_count; ++i) { - LazyDeoptimizationEntry entry = lazy_deoptimization_entries_[i]; - data->SetReturnAddressPc(i, Smi::FromInt(entry.position_after_call())); - data->SetPatchedAddressPc(i, Smi::FromInt(entry.deoptimization()->pos())); - } - code_object->set_deoptimization_data(*data); } @@ -238,30 +246,43 @@ static_cast<CallDescriptor::DeoptimizationSupport>( MiscField::decode(instr->opcode())); - if ((deopt & CallDescriptor::kLazyDeoptimization) != 0) { - RecordLazyDeoptimizationEntry(instr); - } - bool needs_frame_state = (deopt & CallDescriptor::kNeedsFrameState) != 0; - RecordSafepoint( + Safepoint::Id safepoint_id = RecordSafepoint( instr->pointer_map(), Safepoint::kSimple, 0, needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); - if ((deopt & CallDescriptor::kNeedsFrameState) != 0) { + if ((deopt & CallDescriptor::kLazyDeoptimization) != 0) { + RecordLazyDeoptimizationEntry(instr, safepoint_id); + } + + if (needs_frame_state) { // If the frame state is present, it starts at argument 1 // (just after the code address). InstructionOperandConverter converter(this, instr); // Argument 1 is deoptimization id. int deoptimization_id = converter.ToConstant(instr->InputAt(1)).ToInt32(); // The actual frame state values start with argument 2. - BuildTranslation(instr, 2, deoptimization_id); + int first_state_value_offset = 2; +#if DEBUG + // Make sure all the values live in stack slots or they are immediates. + // (The values should not live in register because registers are clobbered + // by calls.) + FrameStateDescriptor* descriptor = + code()->GetDeoptimizationEntry(deoptimization_id); + for (int i = 0; i < descriptor->size(); i++) { + InstructionOperand* op = instr->InputAt(first_state_value_offset + i); + CHECK(op->IsStackSlot() || op->IsImmediate()); + } +#endif + BuildTranslation(instr, first_state_value_offset, deoptimization_id); safepoints()->RecordLazyDeoptimizationIndex(deoptimization_id); } } -void CodeGenerator::RecordLazyDeoptimizationEntry(Instruction* instr) { +void CodeGenerator::RecordLazyDeoptimizationEntry(Instruction* instr, + Safepoint::Id safepoint_id) { InstructionOperandConverter i(this, instr); Label after_call; @@ -276,8 +297,8 @@ Label* cont_label = code_->GetLabel(cont_block); Label* deopt_label = code_->GetLabel(deopt_block); - lazy_deoptimization_entries_.push_back( - LazyDeoptimizationEntry(after_call.pos(), cont_label, deopt_label)); + lazy_deoptimization_entries_.push_back(LazyDeoptimizationEntry( + after_call.pos(), cont_label, deopt_label, safepoint_id)); }
diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h index 8bacdf3..14ee351 100644 --- a/src/compiler/code-generator.h +++ b/src/compiler/code-generator.h
@@ -46,8 +46,8 @@ } // Record a safepoint with the given pointer map. - void RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind, - int arguments, Safepoint::DeoptMode deopt_mode); + Safepoint::Id RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind, + int arguments, Safepoint::DeoptMode deopt_mode); // Assemble code for the specified instruction. void AssembleInstruction(Instruction* instr); @@ -82,7 +82,9 @@ // =========================================================================== // Deoptimization table construction void AddSafepointAndDeopt(Instruction* instr); - void RecordLazyDeoptimizationEntry(Instruction* instr); + void UpdateSafepointsWithDeoptimizationPc(); + void RecordLazyDeoptimizationEntry(Instruction* instr, + Safepoint::Id safepoint_id); void PopulateDeoptimizationData(Handle<Code> code); int DefineDeoptimizationLiteral(Handle<Object> literal); void BuildTranslation(Instruction* instr, int first_argument_index, @@ -95,19 +97,22 @@ class LazyDeoptimizationEntry V8_FINAL { public: LazyDeoptimizationEntry(int position_after_call, Label* continuation, - Label* deoptimization) + Label* deoptimization, Safepoint::Id safepoint_id) : position_after_call_(position_after_call), continuation_(continuation), - deoptimization_(deoptimization) {} + deoptimization_(deoptimization), + safepoint_id_(safepoint_id) {} int position_after_call() const { return position_after_call_; } Label* continuation() const { return continuation_; } Label* deoptimization() const { return deoptimization_; } + Safepoint::Id safepoint_id() const { return safepoint_id_; } private: int position_after_call_; Label* continuation_; Label* deoptimization_; + Safepoint::Id safepoint_id_; }; struct DeoptimizationState : ZoneObject {
diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index 6730469..19b4ddf 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc
@@ -335,60 +335,60 @@ // TODO(turbofan): IA32 SSE LoadUint32() should take an operand. __ LoadUint32(i.OutputDoubleRegister(), i.InputRegister(0)); break; - case kSSELoad: - __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); + case kIA32Movsxbl: + __ movsx_b(i.OutputRegister(), i.MemoryOperand()); break; - case kSSEStore: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movsd(operand, i.InputDoubleRegister(index)); - break; - } - case kIA32LoadWord8: + case kIA32Movzxbl: __ movzx_b(i.OutputRegister(), i.MemoryOperand()); break; - case kIA32StoreWord8: { + case kIA32Movb: { int index = 0; Operand operand = i.MemoryOperand(&index); - __ mov_b(operand, i.InputRegister(index)); + if (HasImmediateInput(instr, index)) { + __ mov_b(operand, i.InputInt8(index)); + } else { + __ mov_b(operand, i.InputRegister(index)); + } break; } - case kIA32StoreWord8I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ mov_b(operand, i.InputInt8(index)); + case kIA32Movsxwl: + __ movsx_w(i.OutputRegister(), i.MemoryOperand()); break; - } - case kIA32LoadWord16: + case kIA32Movzxwl: __ movzx_w(i.OutputRegister(), i.MemoryOperand()); break; - case kIA32StoreWord16: { + case kIA32Movw: { int index = 0; Operand operand = i.MemoryOperand(&index); - __ mov_w(operand, i.InputRegister(index)); + if (HasImmediateInput(instr, index)) { + __ mov_w(operand, i.InputInt16(index)); + } else { + __ mov_w(operand, i.InputRegister(index)); + } break; } - case kIA32StoreWord16I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ mov_w(operand, i.InputInt16(index)); + case kIA32Movl: + if (instr->HasOutput()) { + __ mov(i.OutputRegister(), i.MemoryOperand()); + } else { + int index = 0; + Operand operand = i.MemoryOperand(&index); + if (HasImmediateInput(instr, index)) { + __ mov(operand, i.InputImmediate(index)); + } else { + __ mov(operand, i.InputRegister(index)); + } + } break; - } - case kIA32LoadWord32: - __ mov(i.OutputRegister(), i.MemoryOperand()); + case kIA32Movsd: + if (instr->HasOutput()) { + __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); + } else { + int index = 0; + Operand operand = i.MemoryOperand(&index); + __ movsd(operand, i.InputDoubleRegister(index)); + } break; - case kIA32StoreWord32: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ mov(operand, i.InputRegister(index)); - break; - } - case kIA32StoreWord32I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ mov(operand, i.InputImmediate(index)); - break; - } case kIA32StoreWriteBarrier: { Register object = i.InputRegister(0); Register index = i.InputRegister(1);
diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index 0b0944e..9ddff37 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h
@@ -43,17 +43,14 @@ V(SSEFloat64ToUint32) \ V(SSEInt32ToFloat64) \ V(SSEUint32ToFloat64) \ - V(SSELoad) \ - V(SSEStore) \ - V(IA32LoadWord8) \ - V(IA32StoreWord8) \ - V(IA32StoreWord8I) \ - V(IA32LoadWord16) \ - V(IA32StoreWord16) \ - V(IA32StoreWord16I) \ - V(IA32LoadWord32) \ - V(IA32StoreWord32) \ - V(IA32StoreWord32I) \ + V(IA32Movsxbl) \ + V(IA32Movzxbl) \ + V(IA32Movb) \ + V(IA32Movsxwl) \ + V(IA32Movzxwl) \ + V(IA32Movw) \ + V(IA32Movl) \ + V(IA32Movsd) \ V(IA32StoreWriteBarrier)
diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index ef7d36a..03f35fe 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc
@@ -42,6 +42,7 @@ void InstructionSelector::VisitLoad(Node* node) { MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); + MachineType typ = TypeOf(OpParameter<MachineType>(node)); IA32OperandGenerator g(this); Node* base = node->InputAt(0); Node* index = node->InputAt(1); @@ -53,18 +54,18 @@ // TODO(titzer): signed/unsigned small loads switch (rep) { case kRepFloat64: - opcode = kSSELoad; + opcode = kIA32Movsd; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kIA32LoadWord8; + opcode = typ == kTypeInt32 ? kIA32Movsxbl : kIA32Movzxbl; break; case kRepWord16: - opcode = kIA32LoadWord16; + opcode = typ == kTypeInt32 ? kIA32Movsxwl : kIA32Movzxwl; break; case kRepTagged: // Fall through. case kRepWord32: - opcode = kIA32LoadWord32; + opcode = kIA32Movl; break; default: UNREACHABLE(); @@ -109,13 +110,11 @@ return; } DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind); - bool is_immediate = false; InstructionOperand* val; if (rep == kRepFloat64) { val = g.UseDoubleRegister(value); } else { - is_immediate = g.CanBeImmediate(value); - if (is_immediate) { + if (g.CanBeImmediate(value)) { val = g.UseImmediate(value); } else if (rep == kRepWord8 || rep == kRepBit) { val = g.UseByteRegister(value); @@ -126,18 +125,18 @@ ArchOpcode opcode; switch (rep) { case kRepFloat64: - opcode = kSSEStore; + opcode = kIA32Movsd; break; case kRepBit: // Fall through. case kRepWord8: - opcode = is_immediate ? kIA32StoreWord8I : kIA32StoreWord8; + opcode = kIA32Movb; break; case kRepWord16: - opcode = is_immediate ? kIA32StoreWord16I : kIA32StoreWord16; + opcode = kIA32Movw; break; case kRepTagged: // Fall through. case kRepWord32: - opcode = is_immediate ? kIA32StoreWord32I : kIA32StoreWord32; + opcode = kIA32Movl; break; default: UNREACHABLE();
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 0d014a5..143bd69 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc
@@ -284,9 +284,8 @@ if (buffer->descriptor->ReturnCount() == 1) { buffer->output_nodes.push_back(call); } else { + buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), NULL); call->CollectProjections(&buffer->output_nodes); - DCHECK(buffer->output_nodes.size() <= - static_cast<size_t>(buffer->descriptor->ReturnCount())); } // Filter out the outputs that aren't live because no projection uses them. @@ -1039,7 +1038,7 @@ case IrOpcode::kHeapConstant: return g->UseImmediate(input); default: - return g->Use(input); + return g->UseUnique(input); } }
diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h index 31f3175..da01351 100644 --- a/src/compiler/instruction.h +++ b/src/compiler/instruction.h
@@ -405,12 +405,14 @@ class Instruction : public ZoneObject { public: size_t OutputCount() const { return OutputCountField::decode(bit_field_); } - InstructionOperand* Output() const { return OutputAt(0); } InstructionOperand* OutputAt(size_t i) const { DCHECK(i < OutputCount()); return operands_[i]; } + bool HasOutput() const { return OutputCount() == 1; } + InstructionOperand* Output() const { return OutputAt(0); } + size_t InputCount() const { return InputCountField::decode(bit_field_); } InstructionOperand* InputAt(size_t i) const { DCHECK(i < InputCount());
diff --git a/src/compiler/machine-type.cc b/src/compiler/machine-type.cc index 33ac20f..b27727c 100644 --- a/src/compiler/machine-type.cc +++ b/src/compiler/machine-type.cc
@@ -11,11 +11,12 @@ #define PRINT(bit) \ if (type & bit) { \ - if (before) os << "+"; \ + if (before) os << "|"; \ os << #bit; \ before = true; \ } + OStream& operator<<(OStream& os, const MachineType& type) { bool before = false; PRINT(kRepBit); @@ -35,6 +36,10 @@ PRINT(kTypeAny); return os; } -} -} -} // namespace v8::internal::compiler + + +#undef PRINT + +} // namespace compiler +} // namespace internal +} // namespace v8
diff --git a/src/compiler/machine-type.h b/src/compiler/machine-type.h index a26b644..3b1b9bd 100644 --- a/src/compiler/machine-type.h +++ b/src/compiler/machine-type.h
@@ -70,6 +70,12 @@ const MachineType kMachAnyTagged = static_cast<MachineType>(kRepTagged | kTypeAny); +// Gets only the type of the given type. +inline MachineType TypeOf(MachineType machine_type) { + int result = machine_type & kTypeMask; + return static_cast<MachineType>(result); +} + // Gets only the representation of the given type. inline MachineType RepresentationOf(MachineType machine_type) { int result = machine_type & kRepMask; @@ -97,8 +103,9 @@ return kPointerSize; } } -} -} -} // namespace v8::internal::compiler + +} // namespace compiler +} // namespace internal +} // namespace v8 #endif // V8_COMPILER_MACHINE_TYPE_H_
diff --git a/src/compiler/node.cc b/src/compiler/node.cc index c60822e..dcb3bfe 100644 --- a/src/compiler/node.cc +++ b/src/compiler/node.cc
@@ -11,10 +11,16 @@ namespace compiler { void Node::CollectProjections(NodeVector* projections) { + for (size_t i = 0; i < projections->size(); i++) { + (*projections)[i] = NULL; + } for (UseIter i = uses().begin(); i != uses().end(); ++i) { if ((*i)->opcode() != IrOpcode::kProjection) continue; - DCHECK_GE(OpParameter<int32_t>(*i), 0); - projections->push_back(*i); + int32_t index = OpParameter<int32_t>(*i); + DCHECK_GE(index, 0); + DCHECK_LT(index, static_cast<int32_t>(projections->size())); + DCHECK_EQ(NULL, (*projections)[index]); + (*projections)[index] = *i; } }
diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 091dd60..9506525 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc
@@ -391,24 +391,6 @@ case kX64PushI: __ pushq(i.InputImmediate(0)); break; - case kX64Movl: { - RegisterOrOperand input = i.InputRegisterOrOperand(0); - if (input.type == kRegister) { - __ movl(i.OutputRegister(), input.reg); - } else { - __ movl(i.OutputRegister(), input.operand); - } - break; - } - case kX64Movsxlq: { - RegisterOrOperand input = i.InputRegisterOrOperand(0); - if (input.type == kRegister) { - __ movsxlq(i.OutputRegister(), input.reg); - } else { - __ movsxlq(i.OutputRegister(), input.operand); - } - break; - } case kX64CallCodeObject: { if (HasImmediateInput(instr, 0)) { Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); @@ -532,75 +514,91 @@ break; } - case kSSELoad: - __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); + case kX64Movsd: + if (instr->HasOutput()) { + __ movsd(i.OutputDoubleRegister(), i.MemoryOperand()); + } else { + int index = 0; + Operand operand = i.MemoryOperand(&index); + __ movsd(operand, i.InputDoubleRegister(index)); + } break; - case kSSEStore: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movsd(operand, i.InputDoubleRegister(index)); + case kX64Movsxbl: + __ movsxbl(i.OutputRegister(), i.MemoryOperand()); break; - } - case kX64LoadWord8: + case kX64Movzxbl: __ movzxbl(i.OutputRegister(), i.MemoryOperand()); break; - case kX64StoreWord8: { + case kX64Movb: { int index = 0; Operand operand = i.MemoryOperand(&index); - __ movb(operand, i.InputRegister(index)); + if (HasImmediateInput(instr, index)) { + __ movb(operand, Immediate(i.InputInt8(index))); + } else { + __ movb(operand, i.InputRegister(index)); + } break; } - case kX64StoreWord8I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movb(operand, Immediate(i.InputInt8(index))); + case kX64Movsxwl: + __ movsxwl(i.OutputRegister(), i.MemoryOperand()); break; - } - case kX64LoadWord16: + case kX64Movzxwl: __ movzxwl(i.OutputRegister(), i.MemoryOperand()); break; - case kX64StoreWord16: { + case kX64Movw: { int index = 0; Operand operand = i.MemoryOperand(&index); - __ movw(operand, i.InputRegister(index)); + if (HasImmediateInput(instr, index)) { + __ movw(operand, Immediate(i.InputInt16(index))); + } else { + __ movw(operand, i.InputRegister(index)); + } break; } - case kX64StoreWord16I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movw(operand, Immediate(i.InputInt16(index))); + case kX64Movl: + if (instr->HasOutput()) { + if (instr->addressing_mode() == kMode_None) { + RegisterOrOperand input = i.InputRegisterOrOperand(0); + if (input.type == kRegister) { + __ movl(i.OutputRegister(), input.reg); + } else { + __ movl(i.OutputRegister(), input.operand); + } + } else { + __ movl(i.OutputRegister(), i.MemoryOperand()); + } + } else { + int index = 0; + Operand operand = i.MemoryOperand(&index); + if (HasImmediateInput(instr, index)) { + __ movl(operand, i.InputImmediate(index)); + } else { + __ movl(operand, i.InputRegister(index)); + } + } + break; + case kX64Movsxlq: { + RegisterOrOperand input = i.InputRegisterOrOperand(0); + if (input.type == kRegister) { + __ movsxlq(i.OutputRegister(), input.reg); + } else { + __ movsxlq(i.OutputRegister(), input.operand); + } break; } - case kX64LoadWord32: - __ movl(i.OutputRegister(), i.MemoryOperand()); + case kX64Movq: + if (instr->HasOutput()) { + __ movq(i.OutputRegister(), i.MemoryOperand()); + } else { + int index = 0; + Operand operand = i.MemoryOperand(&index); + if (HasImmediateInput(instr, index)) { + __ movq(operand, i.InputImmediate(index)); + } else { + __ movq(operand, i.InputRegister(index)); + } + } break; - case kX64StoreWord32: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movl(operand, i.InputRegister(index)); - break; - } - case kX64StoreWord32I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movl(operand, i.InputImmediate(index)); - break; - } - case kX64LoadWord64: - __ movq(i.OutputRegister(), i.MemoryOperand()); - break; - case kX64StoreWord64: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movq(operand, i.InputRegister(index)); - break; - } - case kX64StoreWord64I: { - int index = 0; - Operand operand = i.MemoryOperand(&index); - __ movq(operand, i.InputImmediate(index)); - break; - } case kX64StoreWriteBarrier: { Register object = i.InputRegister(0); Register index = i.InputRegister(1);
diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h index 1345ce7..b0a1595 100644 --- a/src/compiler/x64/instruction-codes-x64.h +++ b/src/compiler/x64/instruction-codes-x64.h
@@ -46,8 +46,6 @@ V(X64Ror32) \ V(X64Push) \ V(X64PushI) \ - V(X64Movsxlq) \ - V(X64Movl) \ V(X64CallCodeObject) \ V(X64CallAddress) \ V(PopStack) \ @@ -62,20 +60,16 @@ V(SSEFloat64ToUint32) \ V(SSEInt32ToFloat64) \ V(SSEUint32ToFloat64) \ - V(SSELoad) \ - V(SSEStore) \ - V(X64LoadWord8) \ - V(X64StoreWord8) \ - V(X64StoreWord8I) \ - V(X64LoadWord16) \ - V(X64StoreWord16) \ - V(X64StoreWord16I) \ - V(X64LoadWord32) \ - V(X64StoreWord32) \ - V(X64StoreWord32I) \ - V(X64LoadWord64) \ - V(X64StoreWord64) \ - V(X64StoreWord64I) \ + V(X64Movsd) \ + V(X64Movsxbl) \ + V(X64Movzxbl) \ + V(X64Movb) \ + V(X64Movsxwl) \ + V(X64Movzxwl) \ + V(X64Movw) \ + V(X64Movl) \ + V(X64Movsxlq) \ + V(X64Movq) \ V(X64StoreWriteBarrier)
diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 1dad9ee..138a63d 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc
@@ -57,6 +57,7 @@ void InstructionSelector::VisitLoad(Node* node) { MachineType rep = RepresentationOf(OpParameter<MachineType>(node)); + MachineType typ = TypeOf(OpParameter<MachineType>(node)); X64OperandGenerator g(this); Node* base = node->InputAt(0); Node* index = node->InputAt(1); @@ -68,21 +69,21 @@ // TODO(titzer): signed/unsigned small loads switch (rep) { case kRepFloat64: - opcode = kSSELoad; + opcode = kX64Movsd; break; case kRepBit: // Fall through. case kRepWord8: - opcode = kX64LoadWord8; + opcode = typ == kTypeInt32 ? kX64Movsxbl : kX64Movzxbl; break; case kRepWord16: - opcode = kX64LoadWord16; + opcode = typ == kTypeInt32 ? kX64Movsxwl : kX64Movzxwl; break; case kRepWord32: - opcode = kX64LoadWord32; + opcode = kX64Movl; break; case kRepTagged: // Fall through. case kRepWord64: - opcode = kX64LoadWord64; + opcode = kX64Movq; break; default: UNREACHABLE(); @@ -123,13 +124,11 @@ return; } DCHECK_EQ(kNoWriteBarrier, store_rep.write_barrier_kind); - bool is_immediate = false; InstructionOperand* val; if (rep == kRepFloat64) { val = g.UseDoubleRegister(value); } else { - is_immediate = g.CanBeImmediate(value); - if (is_immediate) { + if (g.CanBeImmediate(value)) { val = g.UseImmediate(value); } else if (rep == kRepWord8 || rep == kRepBit) { val = g.UseByteRegister(value); @@ -140,21 +139,21 @@ ArchOpcode opcode; switch (rep) { case kRepFloat64: - opcode = kSSEStore; + opcode = kX64Movsd; break; case kRepBit: // Fall through. case kRepWord8: - opcode = is_immediate ? kX64StoreWord8I : kX64StoreWord8; + opcode = kX64Movb; break; case kRepWord16: - opcode = is_immediate ? kX64StoreWord16I : kX64StoreWord16; + opcode = kX64Movw; break; case kRepWord32: - opcode = is_immediate ? kX64StoreWord32I : kX64StoreWord32; + opcode = kX64Movl; break; case kRepTagged: // Fall through. case kRepWord64: - opcode = is_immediate ? kX64StoreWord64I : kX64StoreWord64; + opcode = kX64Movq; break; default: UNREACHABLE();
diff --git a/src/contexts.h b/src/contexts.h index 63c9955..e8d2291 100644 --- a/src/contexts.h +++ b/src/contexts.h
@@ -201,7 +201,8 @@ V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \ V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \ V(ITERATOR_SYMBOL_INDEX, Symbol, iterator_symbol) \ - V(UNSCOPABLES_SYMBOL_INDEX, Symbol, unscopables_symbol) + V(UNSCOPABLES_SYMBOL_INDEX, Symbol, unscopables_symbol) \ + V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) // JSFunctions are pairs (context, function code), sometimes also called // closures. A Context object is used to represent function contexts and @@ -396,6 +397,7 @@ SET_ITERATOR_MAP_INDEX, ITERATOR_SYMBOL_INDEX, UNSCOPABLES_SYMBOL_INDEX, + ARRAY_VALUES_ITERATOR_INDEX, // Properties from here are treated as weak references by the full GC. // Scavenge treats them as strong references.
diff --git a/src/data-flow.cc b/src/data-flow.cc index 9494525..bd92ea0 100644 --- a/src/data-flow.cc +++ b/src/data-flow.cc
@@ -45,7 +45,7 @@ int count = 0; for (int i = 0; i < data_length_; i++) { int data = data_[i]; - if (data != 0) count += base::bits::CountSetBits32(data); + if (data != 0) count += base::bits::CountPopulation32(data); } return count; }
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index 5209a51..e6415f4 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc
@@ -442,23 +442,6 @@ } -static int FindPatchAddressForReturnAddress(Code* code, int pc) { - DeoptimizationInputData* input_data = - DeoptimizationInputData::cast(code->deoptimization_data()); - int patch_count = input_data->ReturnAddressPatchCount(); - for (int i = 0; i < patch_count; i++) { - int return_pc = input_data->ReturnAddressPc(i)->value(); - int patch_pc = input_data->PatchedAddressPc(i)->value(); - // If the supplied pc matches the return pc or if the address - // has been already patched, return the patch pc. - if (pc == return_pc || pc == patch_pc) { - return patch_pc; - } - } - return -1; -} - - // For all marked Turbofanned code on stack, change the return address to go // to the deoptimization block. void Deoptimizer::PatchStackForMarkedCode(Isolate* isolate) { @@ -474,7 +457,8 @@ Address* pc_address = it.frame()->pc_address(); int pc_offset = static_cast<int>(*pc_address - code->instruction_start()); - int new_pc_offset = FindPatchAddressForReturnAddress(code, pc_offset); + SafepointEntry safepoint_entry = code->GetSafepointEntry(*pc_address); + unsigned new_pc_offset = safepoint_entry.deoptimization_pc(); if (FLAG_trace_deopt) { CodeTracer::Scope scope(isolate->GetCodeTracer()); @@ -484,8 +468,8 @@ new_pc_offset); } - CHECK_LE(0, new_pc_offset); - *pc_address += new_pc_offset - pc_offset; + CHECK(new_pc_offset != Safepoint::kNoDeoptimizationPc); + *pc_address += static_cast<int>(new_pc_offset) - pc_offset; } } }
diff --git a/src/factory.cc b/src/factory.cc index 5ecdfcf..70fa986 100644 --- a/src/factory.cc +++ b/src/factory.cc
@@ -2174,7 +2174,7 @@ if (prototype->IsTheHole()) { #ifdef DEBUG LookupIterator it(handle(JSObject::cast(result->prototype())), - constructor_string(), LookupIterator::CHECK_PROPERTY); + constructor_string(), LookupIterator::OWN_PROPERTY); MaybeHandle<Object> maybe_prop = Object::GetProperty(&it); DCHECK(it.IsFound()); DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 03ee2a1..7796700 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h
@@ -335,7 +335,7 @@ DEFINE_BOOL(turbo_types, false, "use typed lowering in TurboFan") DEFINE_BOOL(turbo_source_positions, false, "track source code positions when building TurboFan IR") -DEFINE_BOOL(context_specialization, true, +DEFINE_BOOL(context_specialization, false, "enable context specialization in TurboFan") DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan") DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
diff --git a/src/frames.cc b/src/frames.cc index b22fafd..a4e77ff 100644 --- a/src/frames.cc +++ b/src/frames.cc
@@ -1579,9 +1579,7 @@ // ------------------------------------------------------------------------- -int NumRegs(RegList reglist) { - return base::bits::CountSetBits32(reglist); -} +int NumRegs(RegList reglist) { return base::bits::CountPopulation32(reglist); } struct JSCallerSavedCodeData {
diff --git a/src/heap/heap.cc b/src/heap/heap.cc index 119d150..a3d653d 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc
@@ -2863,6 +2863,8 @@ set_elements_transition_symbol(*factory->NewPrivateSymbol()); set_frozen_symbol(*factory->NewPrivateSymbol()); set_megamorphic_symbol(*factory->NewPrivateSymbol()); + set_premonomorphic_symbol(*factory->NewPrivateSymbol()); + set_generic_symbol(*factory->NewPrivateSymbol()); set_nonexistent_symbol(*factory->NewPrivateSymbol()); set_normal_ic_symbol(*factory->NewPrivateSymbol()); set_observed_symbol(*factory->NewPrivateSymbol());
diff --git a/src/heap/heap.h b/src/heap/heap.h index 1b56f25..8b4a021 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h
@@ -183,6 +183,8 @@ V(Symbol, observed_symbol, ObservedSymbol) \ V(Symbol, uninitialized_symbol, UninitializedSymbol) \ V(Symbol, megamorphic_symbol, MegamorphicSymbol) \ + V(Symbol, premonomorphic_symbol, PremonomorphicSymbol) \ + V(Symbol, generic_symbol, GenericSymbol) \ V(Symbol, stack_trace_symbol, StackTraceSymbol) \ V(Symbol, detailed_stack_trace_symbol, DetailedStackTraceSymbol) \ V(Symbol, normal_ic_symbol, NormalICSymbol) \ @@ -294,6 +296,10 @@ V(String_string, "String") \ V(symbol_string, "symbol") \ V(Symbol_string, "Symbol") \ + V(Map_string, "Map") \ + V(Set_string, "Set") \ + V(WeakMap_string, "WeakMap") \ + V(WeakSet_string, "WeakSet") \ V(for_string, "for") \ V(for_api_string, "for_api") \ V(for_intern_string, "for_intern") \
diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 1ad5d95..16d91c4 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc
@@ -5341,8 +5341,7 @@ } Handle<GlobalObject> global(current_info()->global_object()); - LookupIterator it(global, variable->name(), - LookupIterator::CHECK_PROPERTY); + LookupIterator it(global, variable->name(), LookupIterator::OWN_PROPERTY); GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD); if (type == kUseCell && @@ -5797,7 +5796,7 @@ HConstant::cast(checked_object->ActualValue())->handle(isolate())); if (object->IsJSObject()) { - LookupIterator it(object, info->name(), LookupIterator::CHECK_PROPERTY); + LookupIterator it(object, info->name(), LookupIterator::OWN_PROPERTY); Handle<Object> value = JSObject::GetDataProperty(&it); CHECK(it.IsFound()); return New<HConstant>(value); @@ -6463,7 +6462,7 @@ HValue* value, BailoutId ast_id) { Handle<GlobalObject> global(current_info()->global_object()); - LookupIterator it(global, var->name(), LookupIterator::CHECK_PROPERTY); + LookupIterator it(global, var->name(), LookupIterator::OWN_PROPERTY); GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); if (type == kUseCell) { Handle<PropertyCell> cell = it.GetPropertyCell(); @@ -9055,7 +9054,7 @@ // access check is not enabled we assume that the function will not change // and generate optimized code for calling the function. Handle<GlobalObject> global(current_info()->global_object()); - LookupIterator it(global, var->name(), LookupIterator::CHECK_PROPERTY); + LookupIterator it(global, var->name(), LookupIterator::OWN_PROPERTY); GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD); if (type == kUseCell && !current_info()->global_object()->IsAccessCheckNeeded()) { @@ -10699,7 +10698,7 @@ !current_info()->global_object()->IsAccessCheckNeeded()) { Handle<String> name = proxy->name(); Handle<GlobalObject> global(current_info()->global_object()); - LookupIterator it(global, name, LookupIterator::CHECK_PROPERTY); + LookupIterator it(global, name, LookupIterator::OWN_PROPERTY); Handle<Object> value = JSObject::GetDataProperty(&it); if (it.IsFound() && value->IsJSFunction()) { Handle<JSFunction> candidate = Handle<JSFunction>::cast(value);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 6a5f99e..1714e4a 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc
@@ -9,7 +9,7 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic/ic-compiler.h" +#include "src/ic/handler-compiler.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" @@ -2557,7 +2557,7 @@ ProfileEntryHookStub::MaybeCallEntryHook(masm); // Enter the exit frame that transitions from JavaScript to C++. - __ EnterExitFrame(save_doubles_ == kSaveFPRegs); + __ EnterExitFrame(save_doubles()); // ebx: pointer to C function (C callee-saved) // ebp: frame pointer (restored after C call) @@ -2565,7 +2565,7 @@ // edi: number of arguments including receiver (C callee-saved) // esi: pointer to the first argument (C callee-saved) - // Result returned in eax, or eax+edx if result_size_ is 2. + // Result returned in eax, or eax+edx if result size is 2. // Check stack alignment. if (FLAG_debug_code) { @@ -2613,7 +2613,7 @@ } // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(save_doubles_ == kSaveFPRegs); + __ LeaveExitFrame(save_doubles()); __ ret(0); // Handling of exception.
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h index d0d5216..8ee0a92 100644 --- a/src/ia32/code-stubs-ia32.h +++ b/src/ia32/code-stubs-ia32.h
@@ -30,7 +30,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -70,7 +70,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -98,7 +98,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop( @@ -157,7 +157,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { + uint32_t MinorKey() const { return DictionaryBits::encode(dictionary_.code()) | ResultBits::encode(result_.code()) | IndexBits::encode(index_.code()) | @@ -406,7 +406,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) |
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 395ae39..9796cf3 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc
@@ -900,7 +900,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -2828,6 +2828,19 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ mov(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(eax)); + __ mov(LoadIC::SlotRegister(), + Immediate(Smi::FromInt(instr->hydrogen()->slot()))); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(esi)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); @@ -2835,13 +2848,7 @@ __ mov(LoadIC::NameRegister(), instr->name()); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(eax)); - __ mov(LoadIC::SlotRegister(), - Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -2978,13 +2985,7 @@ __ mov(LoadIC::NameRegister(), instr->name()); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(eax)); - __ mov(LoadIC::SlotRegister(), - Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3211,13 +3212,7 @@ DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ mov(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(eax)); - __ mov(LoadIC::SlotRegister(), - Immediate(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h index d2f85f1..7c5896b 100644 --- a/src/ia32/lithium-codegen-ia32.h +++ b/src/ia32/lithium-codegen-ia32.h
@@ -319,6 +319,9 @@ void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); + template <class T> + void EmitVectorLoadICRegisters(T* instr); + void EmitReturn(LReturn* instr, bool dynamic_frame_alignment); // Emits code for pushing either a tagged constant, a (non-double)
diff --git a/src/ic/arm/handler-compiler-arm.cc b/src/ic/arm/handler-compiler-arm.cc new file mode 100644 index 0000000..7722af6 --- /dev/null +++ b/src/ic/arm/handler-compiler-arm.cc
@@ -0,0 +1,866 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_ARM + +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + // ----------- S t a t e ------------- + // -- r0 : receiver + // -- r2 : name + // -- lr : return address + // ----------------------------------- + { + FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); + + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ ldr(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); + } + + // Restore context register. + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} + + +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- lr : return address + // ----------------------------------- + { + FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ ldr(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver, value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ pop(r0); + + // Restore context register. + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} + + +void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( + MacroAssembler* masm, Label* miss_label, Register receiver, + Handle<Name> name, Register scratch0, Register scratch1) { + DCHECK(name->IsUniqueName()); + DCHECK(!receiver.is(scratch0)); + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); + __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); + + Label done; + + const int kInterceptorOrAccessCheckNeededMask = + (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); + + // Bail out if the receiver has a named interceptor or requires access checks. + Register map = scratch1; + __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); + __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); + __ b(ne, miss_label); + + // Check that receiver is a JSObject. + __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE)); + __ b(lt, miss_label); + + // Load properties array. + Register properties = scratch0; + __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + // Check that the properties array is a dictionary. + __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); + Register tmp = properties; + __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); + __ cmp(map, tmp); + __ b(ne, miss_label); + + // Restore the temporarily used register. + __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + + + NameDictionaryLookupStub::GenerateNegativeLookup( + masm, miss_label, &done, receiver, properties, name, scratch1); + __ bind(&done); + __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); +} + + +void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( + MacroAssembler* masm, int index, Register prototype, Label* miss) { + Isolate* isolate = masm->isolate(); + // Get the global function with the given index. + Handle<JSFunction> function( + JSFunction::cast(isolate->native_context()->get(index))); + + // Check we're still in the same context. + Register scratch = prototype; + const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); + __ ldr(scratch, MemOperand(cp, offset)); + __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); + __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index))); + __ Move(ip, function); + __ cmp(ip, scratch); + __ b(ne, miss); + + // Load its initial map. The global functions all have initial maps. + __ Move(prototype, Handle<Map>(function->initial_map())); + // Load the prototype from the initial map. + __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); +} + + +void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( + MacroAssembler* masm, Register receiver, Register scratch1, + Register scratch2, Label* miss_label) { + __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); + __ mov(r0, scratch1); + __ Ret(); +} + + +// Generate code to check that a global property cell is empty. Create +// the property cell at compilation time if no cell exists for the +// property. +void PropertyHandlerCompiler::GenerateCheckPropertyCell( + MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, + Register scratch, Label* miss) { + Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); + DCHECK(cell->value()->IsTheHole()); + __ mov(scratch, Operand(cell)); + __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(scratch, ip); + __ b(ne, miss); +} + + +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, + Handle<JSObject> holder_obj) { + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); + __ push(name); + Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); + DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); + Register scratch = name; + __ mov(scratch, Operand(interceptor)); + __ push(scratch); + __ push(receiver); + __ push(holder); +} + + +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), + NamedLoadHandlerCompiler::kInterceptorArgsLength); +} + + +// Generate call to api function. +void PropertyHandlerCompiler::GenerateFastApiCall( + MacroAssembler* masm, const CallOptimization& optimization, + Handle<Map> receiver_map, Register receiver, Register scratch_in, + bool is_store, int argc, Register* values) { + DCHECK(!receiver.is(scratch_in)); + __ push(receiver); + // Write the arguments to stack frame. + for (int i = 0; i < argc; i++) { + Register arg = values[argc - 1 - i]; + DCHECK(!receiver.is(arg)); + DCHECK(!scratch_in.is(arg)); + __ push(arg); + } + DCHECK(optimization.is_simple_api_call()); + + // Abi for CallApiFunctionStub. + Register callee = r0; + Register call_data = r4; + Register holder = r2; + Register api_function_address = r1; + + // Put holder in place. + CallOptimization::HolderLookup holder_lookup; + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + __ Move(holder, receiver); + break; + case CallOptimization::kHolderFound: + __ Move(holder, api_holder); + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); + break; + } + + Isolate* isolate = masm->isolate(); + Handle<JSFunction> function = optimization.constant_function(); + Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); + Handle<Object> call_data_obj(api_call_info->data(), isolate); + + // Put callee in place. + __ Move(callee, function); + + bool call_data_undefined = false; + // Put call_data in place. + if (isolate->heap()->InNewSpace(*call_data_obj)) { + __ Move(call_data, api_call_info); + __ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); + } else if (call_data_obj->IsUndefined()) { + call_data_undefined = true; + __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); + } else { + __ Move(call_data, call_data_obj); + } + + // Put api_function_address in place. + Address function_address = v8::ToCData<Address>(api_call_info->callback()); + ApiFunction fun(function_address); + ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; + ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); + __ mov(api_function_address, Operand(ref)); + + // Jump to stub. + CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); + __ TailCallStub(&stub); +} + + +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // The return address is in lr. + Label slow, miss; + + Register key = LoadIC::NameRegister(); + Register receiver = LoadIC::ReceiverRegister(); + DCHECK(receiver.is(r1)); + DCHECK(key.is(r2)); + + __ UntagAndJumpIfNotSmi(r6, key, &miss); + __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ LoadFromNumberDictionary(&slow, r4, key, r0, r6, r3, r5); + __ Ret(); + + __ bind(&slow); + __ IncrementCounter( + masm->isolate()->counters()->keyed_load_external_array_slow(), 1, r2, r3); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); + + // Miss case, call the runtime. + __ bind(&miss); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +#undef __ +#define __ ACCESS_MASM(masm()) + + +void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, + Handle<Name> name) { + if (!label->is_unused()) { + __ bind(label); + __ mov(this->name(), Operand(name)); + } +} + + +// Generate StoreTransition code, value is passed in r0 register. +// When leaving generated code after success, the receiver_reg and name_reg +// may be clobbered. Upon branch to miss_label, the receiver and name +// registers have their original values. +void NamedStoreHandlerCompiler::GenerateStoreTransition( + Handle<Map> transition, Handle<Name> name, Register receiver_reg, + Register storage_reg, Register value_reg, Register scratch1, + Register scratch2, Register scratch3, Label* miss_label, Label* slow) { + // r0 : value + Label exit; + + int descriptor = transition->LastAdded(); + DescriptorArray* descriptors = transition->instance_descriptors(); + PropertyDetails details = descriptors->GetDetails(descriptor); + Representation representation = details.representation(); + DCHECK(!representation.IsNone()); + + if (details.type() == CONSTANT) { + Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); + __ Move(scratch1, constant); + __ cmp(value_reg, scratch1); + __ b(ne, miss_label); + } else if (representation.IsSmi()) { + __ JumpIfNotSmi(value_reg, miss_label); + } else if (representation.IsHeapObject()) { + __ JumpIfSmi(value_reg, miss_label); + HeapType* field_type = descriptors->GetFieldType(descriptor); + HeapType::Iterator<Map> it = field_type->Classes(); + if (!it.Done()) { + __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); + Label do_store; + while (true) { + __ CompareMap(scratch1, it.Current(), &do_store); + it.Advance(); + if (it.Done()) { + __ b(ne, miss_label); + break; + } + __ b(eq, &do_store); + } + __ bind(&do_store); + } + } else if (representation.IsDouble()) { + Label do_store, heap_number; + __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex); + __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow, + TAG_RESULT, MUTABLE); + + __ JumpIfNotSmi(value_reg, &heap_number); + __ SmiUntag(scratch1, value_reg); + __ vmov(s0, scratch1); + __ vcvt_f64_s32(d0, s0); + __ jmp(&do_store); + + __ bind(&heap_number); + __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, + DONT_DO_SMI_CHECK); + __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); + + __ bind(&do_store); + __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); + } + + // Stub never generated for objects that require access checks. + DCHECK(!transition->is_access_check_needed()); + + // Perform map transition for the receiver if necessary. + if (details.type() == FIELD && + Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { + // The properties must be extended before we can store the value. + // We jump to a runtime call that extends the properties array. + __ push(receiver_reg); + __ mov(r2, Operand(transition)); + __ Push(r2, r0); + __ TailCallExternalReference( + ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), + isolate()), + 3, 1); + return; + } + + // Update the map of the object. + __ mov(scratch1, Operand(transition)); + __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); + + // Update the write barrier for the map field. + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + if (details.type() == CONSTANT) { + DCHECK(value_reg.is(r0)); + __ Ret(); + return; + } + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= transition->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + if (index < 0) { + // Set the property straight into the object. + int offset = transition->instance_size() + (index * kPointerSize); + if (representation.IsDouble()) { + __ str(storage_reg, FieldMemOperand(receiver_reg, offset)); + } else { + __ str(value_reg, FieldMemOperand(receiver_reg, offset)); + } + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ mov(storage_reg, value_reg); + } + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kLRHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); + } + } else { + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array + __ ldr(scratch1, + FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); + if (representation.IsDouble()) { + __ str(storage_reg, FieldMemOperand(scratch1, offset)); + } else { + __ str(value_reg, FieldMemOperand(scratch1, offset)); + } + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ mov(storage_reg, value_reg); + } + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kLRHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); + } + } + + // Return the value (register r0). + DCHECK(value_reg.is(r0)); + __ bind(&exit); + __ Ret(); +} + + +void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, + Register value_reg, + Label* miss_label) { + DCHECK(lookup->representation().IsHeapObject()); + __ JumpIfSmi(value_reg, miss_label); + HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); + __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); + Label do_store; + while (true) { + __ CompareMap(scratch1(), it.Current(), &do_store); + it.Advance(); + if (it.Done()) { + __ b(ne, miss_label); + break; + } + __ b(eq, &do_store); + } + __ bind(&do_store); + + StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), + lookup->representation()); + GenerateTailCall(masm(), stub.GetCode()); +} + + +Register PropertyHandlerCompiler::CheckPrototypes( + Register object_reg, Register holder_reg, Register scratch1, + Register scratch2, Handle<Name> name, Label* miss, + PrototypeCheckType check) { + Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); + + // Make sure there's no overlap between holder and object registers. + DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); + + // Keep track of the current object in register reg. + Register reg = object_reg; + int depth = 0; + + Handle<JSObject> current = Handle<JSObject>::null(); + if (type()->IsConstant()) { + current = Handle<JSObject>::cast(type()->AsConstant()->Value()); + } + Handle<JSObject> prototype = Handle<JSObject>::null(); + Handle<Map> current_map = receiver_map; + Handle<Map> holder_map(holder()->map()); + // Traverse the prototype chain and check the maps in the prototype chain for + // fast and global objects or do negative lookup for normal objects. + while (!current_map.is_identical_to(holder_map)) { + ++depth; + + // Only global objects and objects that do not require access + // checks are allowed in stubs. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + + prototype = handle(JSObject::cast(current_map->prototype())); + if (current_map->is_dictionary_map() && + !current_map->IsJSGlobalObjectMap()) { + DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. + if (!name->IsUniqueName()) { + DCHECK(name->IsString()); + name = factory()->InternalizeString(Handle<String>::cast(name)); + } + DCHECK(current.is_null() || + current->property_dictionary()->FindEntry(name) == + NameDictionary::kNotFound); + + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); + + __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + reg = holder_reg; // From now on the object will be in holder_reg. + __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } else { + Register map_reg = scratch1; + if (depth != 1 || check == CHECK_ALL_MAPS) { + // CheckMap implicitly loads the map of |reg| into |map_reg|. + __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK); + } else { + __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + } + + // Check access rights to the global object. This has to happen after + // the map check so that we know that the object is actually a global + // object. + // This allows us to install generated handlers for accesses to the + // global proxy (as opposed to using slow ICs). See corresponding code + // in LookupForRead(). + if (current_map->IsJSGlobalProxyMap()) { + __ CheckAccessGlobalProxy(reg, scratch2, miss); + } else if (current_map->IsJSGlobalObjectMap()) { + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); + } + + reg = holder_reg; // From now on the object will be in holder_reg. + + // Two possible reasons for loading the prototype from the map: + // (1) Can't store references to new space in code. + // (2) Handler is shared for all receivers with the same prototype + // map (but not necessarily the same prototype instance). + bool load_prototype_from_map = + heap()->InNewSpace(*prototype) || depth == 1; + if (load_prototype_from_map) { + __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } else { + __ mov(reg, Operand(prototype)); + } + } + + // Go to the next object in the prototype chain. + current = prototype; + current_map = handle(current->map()); + } + + // Log the check depth. + LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); + + if (depth != 0 || check == CHECK_ALL_MAPS) { + // Check the holder map. + __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); + } + + // Perform security check for access to the global object. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + if (current_map->IsJSGlobalProxyMap()) { + __ CheckAccessGlobalProxy(reg, scratch1, miss); + } + + // Return the register containing the holder. + return reg; +} + + +void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ b(&success); + __ bind(miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + __ bind(&success); + } +} + + +void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ b(&success); + GenerateRestoreName(miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + __ bind(&success); + } +} + + +void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { + // Return the constant value. + __ Move(r0, value); + __ Ret(); +} + + +void NamedLoadHandlerCompiler::GenerateLoadCallback( + Register reg, Handle<ExecutableAccessorInfo> callback) { + // Build AccessorInfo::args_ list on the stack and push property name below + // the exit frame to make GC aware of them and store pointers to them. + STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); + STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); + STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); + STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); + STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); + DCHECK(!scratch2().is(reg)); + DCHECK(!scratch3().is(reg)); + DCHECK(!scratch4().is(reg)); + __ push(receiver()); + if (heap()->InNewSpace(callback->data())) { + __ Move(scratch3(), callback); + __ ldr(scratch3(), + FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); + } else { + __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); + } + __ push(scratch3()); + __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); + __ mov(scratch4(), scratch3()); + __ Push(scratch3(), scratch4()); + __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate()))); + __ Push(scratch4(), reg); + __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ + __ push(name()); + + // Abi for CallApiGetter + Register getter_address_reg = r2; + + Address getter_address = v8::ToCData<Address>(callback->getter()); + ApiFunction fun(getter_address); + ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; + ExternalReference ref = ExternalReference(&fun, type, isolate()); + __ mov(getter_address_reg, Operand(ref)); + + CallApiGetterStub stub(isolate()); + __ TailCallStub(&stub); +} + + +void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( + LookupIterator* it, Register holder_reg) { + DCHECK(holder()->HasNamedInterceptor()); + DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); + + // 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->property_kind() == 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()); + } + // 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(), + IC::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); + __ 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()); + PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), + holder()); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); + __ TailCallExternalReference( + ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( + Handle<JSObject> object, Handle<Name> name, + Handle<ExecutableAccessorInfo> callback) { + Register holder_reg = Frontend(receiver(), name); + + __ push(receiver()); // receiver + __ push(holder_reg); + __ mov(ip, Operand(callback)); // callback info + __ push(ip); + __ mov(ip, Operand(name)); + __ Push(ip, value()); + + // Do tail-call to the runtime system. + ExternalReference store_callback_property = + ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); + __ TailCallExternalReference(store_callback_property, 5, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( + Handle<Name> name) { + __ Push(receiver(), this->name(), value()); + + // Do tail-call to the runtime system. + ExternalReference store_ic_property = ExternalReference( + IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); + __ TailCallExternalReference(store_ic_property, 3, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( + Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { + Label miss; + FrontendHeader(receiver(), name, &miss); + + // Get the value from the cell. + Register result = StoreIC::ValueRegister(); + __ mov(result, Operand(cell)); + __ ldr(result, FieldMemOperand(result, Cell::kValueOffset)); + + // Check for deleted property if property can actually be deleted. + if (is_configurable) { + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ cmp(result, ip); + __ b(eq, &miss); + } + + Counters* counters = isolate()->counters(); + __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); + __ Ret(); + + FrontendFooter(name, &miss); + + // Return the generated code. + return GetCode(kind(), Code::NORMAL, name); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_ARM
diff --git a/src/ic/arm/ic-arm.cc b/src/ic/arm/ic-arm.cc index 9c6b894..57bd5a4 100644 --- a/src/ic/arm/ic-arm.cc +++ b/src/ic/arm/ic-arm.cc
@@ -733,30 +733,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - static void KeyedStoreGenerateGenericHelper( MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
diff --git a/src/ic/arm/ic-compiler-arm.cc b/src/ic/arm/ic-compiler-arm.cc index c5b0903..ba038ab 100644 --- a/src/ic/arm/ic-compiler-arm.cc +++ b/src/ic/arm/ic-compiler-arm.cc
@@ -6,7 +6,6 @@ #if V8_TARGET_ARCH_ARM -#include "src/ic/call-optimization.h" #include "src/ic/ic-compiler.h" namespace v8 { @@ -15,198 +14,16 @@ #define __ ACCESS_MASM(masm) -void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( - MacroAssembler* masm, Label* miss_label, Register receiver, - Handle<Name> name, Register scratch0, Register scratch1) { - DCHECK(name->IsUniqueName()); - DCHECK(!receiver.is(scratch0)); - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); - __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); - Label done; + __ mov(r0, Operand(Smi::FromInt(strict_mode))); + __ Push(r0); - const int kInterceptorOrAccessCheckNeededMask = - (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); - - // Bail out if the receiver has a named interceptor or requires access checks. - Register map = scratch1; - __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); - __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); - __ b(ne, miss_label); - - // Check that receiver is a JSObject. - __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); - __ cmp(scratch0, Operand(FIRST_SPEC_OBJECT_TYPE)); - __ b(lt, miss_label); - - // Load properties array. - Register properties = scratch0; - __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - // Check that the properties array is a dictionary. - __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); - Register tmp = properties; - __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); - __ cmp(map, tmp); - __ b(ne, miss_label); - - // Restore the temporarily used register. - __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - - - NameDictionaryLookupStub::GenerateNegativeLookup( - masm, miss_label, &done, receiver, properties, name, scratch1); - __ bind(&done); - __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); -} - - -void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype, Label* miss) { - Isolate* isolate = masm->isolate(); - // Get the global function with the given index. - Handle<JSFunction> function( - JSFunction::cast(isolate->native_context()->get(index))); - - // Check we're still in the same context. - Register scratch = prototype; - const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); - __ ldr(scratch, MemOperand(cp, offset)); - __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); - __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index))); - __ Move(ip, function); - __ cmp(ip, scratch); - __ b(ne, miss); - - // Load its initial map. The global functions all have initial maps. - __ Move(prototype, Handle<Map>(function->initial_map())); - // Load the prototype from the initial map. - __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); -} - - -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ mov(r0, scratch1); - __ Ret(); -} - - -// Generate code to check that a global property cell is empty. Create -// the property cell at compilation time if no cell exists for the -// property. -void PropertyHandlerCompiler::GenerateCheckPropertyCell( - MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, - Register scratch, Label* miss) { - Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); - DCHECK(cell->value()->IsTheHole()); - __ mov(scratch, Operand(cell)); - __ ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(scratch, ip); - __ b(ne, miss); -} - - -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); - __ push(name); - Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); - DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); - Register scratch = name; - __ mov(scratch, Operand(interceptor)); - __ push(scratch); - __ push(receiver); - __ push(holder); -} - - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, IC::UtilityId id) { - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); - __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), - NamedLoadHandlerCompiler::kInterceptorArgsLength); -} - - -// Generate call to api function. -void PropertyHandlerCompiler::GenerateFastApiCall( - MacroAssembler* masm, const CallOptimization& optimization, - Handle<Map> receiver_map, Register receiver, Register scratch_in, - bool is_store, int argc, Register* values) { - DCHECK(!receiver.is(scratch_in)); - __ push(receiver); - // Write the arguments to stack frame. - for (int i = 0; i < argc; i++) { - Register arg = values[argc - 1 - i]; - DCHECK(!receiver.is(arg)); - DCHECK(!scratch_in.is(arg)); - __ push(arg); - } - DCHECK(optimization.is_simple_api_call()); - - // Abi for CallApiFunctionStub. - Register callee = r0; - Register call_data = r4; - Register holder = r2; - Register api_function_address = r1; - - // Put holder in place. - CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = - optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); - switch (holder_lookup) { - case CallOptimization::kHolderIsReceiver: - __ Move(holder, receiver); - break; - case CallOptimization::kHolderFound: - __ Move(holder, api_holder); - break; - case CallOptimization::kHolderNotFound: - UNREACHABLE(); - break; - } - - Isolate* isolate = masm->isolate(); - Handle<JSFunction> function = optimization.constant_function(); - Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); - Handle<Object> call_data_obj(api_call_info->data(), isolate); - - // Put callee in place. - __ Move(callee, function); - - bool call_data_undefined = false; - // Put call_data in place. - if (isolate->heap()->InNewSpace(*call_data_obj)) { - __ Move(call_data, api_call_info); - __ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); - } else if (call_data_obj->IsUndefined()) { - call_data_undefined = true; - __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); - } else { - __ Move(call_data, call_data_obj); - } - - // Put api_function_address in place. - Address function_address = v8::ToCData<Address>(api_call_info->callback()); - ApiFunction fun(function_address); - ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; - ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); - __ mov(api_function_address, Operand(ref)); - - // Jump to stub. - CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); - __ TailCallStub(&stub); + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); } @@ -214,613 +31,6 @@ #define __ ACCESS_MASM(masm()) -void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, - Handle<Name> name) { - if (!label->is_unused()) { - __ bind(label); - __ mov(this->name(), Operand(name)); - } -} - - -// Generate StoreTransition code, value is passed in r0 register. -// When leaving generated code after success, the receiver_reg and name_reg -// may be clobbered. Upon branch to miss_label, the receiver and name -// registers have their original values. -void NamedStoreHandlerCompiler::GenerateStoreTransition( - Handle<Map> transition, Handle<Name> name, Register receiver_reg, - Register storage_reg, Register value_reg, Register scratch1, - Register scratch2, Register scratch3, Label* miss_label, Label* slow) { - // r0 : value - Label exit; - - int descriptor = transition->LastAdded(); - DescriptorArray* descriptors = transition->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - Representation representation = details.representation(); - DCHECK(!representation.IsNone()); - - if (details.type() == CONSTANT) { - Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); - __ Move(scratch1, constant); - __ cmp(value_reg, scratch1); - __ b(ne, miss_label); - } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); - } else if (representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_label); - HeapType* field_type = descriptors->GetFieldType(descriptor); - HeapType::Iterator<Map> it = field_type->Classes(); - if (!it.Done()) { - __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); - Label do_store; - while (true) { - __ CompareMap(scratch1, it.Current(), &do_store); - it.Advance(); - if (it.Done()) { - __ b(ne, miss_label); - break; - } - __ b(eq, &do_store); - } - __ bind(&do_store); - } - } else if (representation.IsDouble()) { - Label do_store, heap_number; - __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex); - __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow, - TAG_RESULT, MUTABLE); - - __ JumpIfNotSmi(value_reg, &heap_number); - __ SmiUntag(scratch1, value_reg); - __ vmov(s0, scratch1); - __ vcvt_f64_s32(d0, s0); - __ jmp(&do_store); - - __ bind(&heap_number); - __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, - DONT_DO_SMI_CHECK); - __ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); - - __ bind(&do_store); - __ vstr(d0, FieldMemOperand(storage_reg, HeapNumber::kValueOffset)); - } - - // Stub never generated for objects that require access checks. - DCHECK(!transition->is_access_check_needed()); - - // Perform map transition for the receiver if necessary. - if (details.type() == FIELD && - Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { - // The properties must be extended before we can store the value. - // We jump to a runtime call that extends the properties array. - __ push(receiver_reg); - __ mov(r2, Operand(transition)); - __ Push(r2, r0); - __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); - return; - } - - // Update the map of the object. - __ mov(scratch1, Operand(transition)); - __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); - - // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, - kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - - if (details.type() == CONSTANT) { - DCHECK(value_reg.is(r0)); - __ Ret(); - return; - } - - int index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); - - // Adjust for the number of properties stored in the object. Even in the - // face of a transition we can use the old map here because the size of the - // object and the number of in-object properties is not going to change. - index -= transition->inobject_properties(); - - // TODO(verwaest): Share this code as a code stub. - SmiCheck smi_check = - representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; - if (index < 0) { - // Set the property straight into the object. - int offset = transition->instance_size() + (index * kPointerSize); - if (representation.IsDouble()) { - __ str(storage_reg, FieldMemOperand(receiver_reg, offset)); - } else { - __ str(value_reg, FieldMemOperand(receiver_reg, offset)); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ mov(storage_reg, value_reg); - } - __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, - kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, smi_check); - } - } else { - // Write to the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - // Get the properties array - __ ldr(scratch1, - FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); - if (representation.IsDouble()) { - __ str(storage_reg, FieldMemOperand(scratch1, offset)); - } else { - __ str(value_reg, FieldMemOperand(scratch1, offset)); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ mov(storage_reg, value_reg); - } - __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, - kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, smi_check); - } - } - - // Return the value (register r0). - DCHECK(value_reg.is(r0)); - __ bind(&exit); - __ Ret(); -} - - -void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, - Register value_reg, - Label* miss_label) { - DCHECK(lookup->representation().IsHeapObject()); - __ JumpIfSmi(value_reg, miss_label); - HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); - __ ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); - Label do_store; - while (true) { - __ CompareMap(scratch1(), it.Current(), &do_store); - it.Advance(); - if (it.Done()) { - __ b(ne, miss_label); - break; - } - __ b(eq, &do_store); - } - __ bind(&do_store); - - StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), - lookup->representation()); - GenerateTailCall(masm(), stub.GetCode()); -} - - -Register PropertyHandlerCompiler::CheckPrototypes( - Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - PrototypeCheckType check) { - Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); - - // Make sure there's no overlap between holder and object registers. - DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && - !scratch2.is(scratch1)); - - // Keep track of the current object in register reg. - Register reg = object_reg; - int depth = 0; - - Handle<JSObject> current = Handle<JSObject>::null(); - if (type()->IsConstant()) { - current = Handle<JSObject>::cast(type()->AsConstant()->Value()); - } - Handle<JSObject> prototype = Handle<JSObject>::null(); - Handle<Map> current_map = receiver_map; - Handle<Map> holder_map(holder()->map()); - // Traverse the prototype chain and check the maps in the prototype chain for - // fast and global objects or do negative lookup for normal objects. - while (!current_map.is_identical_to(holder_map)) { - ++depth; - - // Only global objects and objects that do not require access - // checks are allowed in stubs. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - - prototype = handle(JSObject::cast(current_map->prototype())); - if (current_map->is_dictionary_map() && - !current_map->IsJSGlobalObjectMap()) { - DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. - if (!name->IsUniqueName()) { - DCHECK(name->IsString()); - name = factory()->InternalizeString(Handle<String>::cast(name)); - } - DCHECK(current.is_null() || - current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); - - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, - scratch2); - - __ ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); - } else { - Register map_reg = scratch1; - if (depth != 1 || check == CHECK_ALL_MAPS) { - // CheckMap implicitly loads the map of |reg| into |map_reg|. - __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK); - } else { - __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - } - - // Check access rights to the global object. This has to happen after - // the map check so that we know that the object is actually a global - // object. - // This allows us to install generated handlers for accesses to the - // global proxy (as opposed to using slow ICs). See corresponding code - // in LookupForRead(). - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch2, miss); - } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), - name, scratch2, miss); - } - - reg = holder_reg; // From now on the object will be in holder_reg. - - // Two possible reasons for loading the prototype from the map: - // (1) Can't store references to new space in code. - // (2) Handler is shared for all receivers with the same prototype - // map (but not necessarily the same prototype instance). - bool load_prototype_from_map = - heap()->InNewSpace(*prototype) || depth == 1; - if (load_prototype_from_map) { - __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); - } else { - __ mov(reg, Operand(prototype)); - } - } - - // Go to the next object in the prototype chain. - current = prototype; - current_map = handle(current->map()); - } - - // Log the check depth. - LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - - if (depth != 0 || check == CHECK_ALL_MAPS) { - // Check the holder map. - __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Perform security check for access to the global object. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch1, miss); - } - - // Return the register containing the holder. - return reg; -} - - -void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ b(&success); - __ bind(miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ b(&success); - GenerateRestoreName(miss, name); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { - // Return the constant value. - __ Move(r0, value); - __ Ret(); -} - - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle<ExecutableAccessorInfo> callback) { - // Build AccessorInfo::args_ list on the stack and push property name below - // the exit frame to make GC aware of them and store pointers to them. - STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); - STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); - STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); - STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); - STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); - DCHECK(!scratch2().is(reg)); - DCHECK(!scratch3().is(reg)); - DCHECK(!scratch4().is(reg)); - __ push(receiver()); - if (heap()->InNewSpace(callback->data())) { - __ Move(scratch3(), callback); - __ ldr(scratch3(), - FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); - } else { - __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); - } - __ push(scratch3()); - __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); - __ mov(scratch4(), scratch3()); - __ Push(scratch3(), scratch4()); - __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate()))); - __ Push(scratch4(), reg); - __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ - __ push(name()); - - // Abi for CallApiGetter - Register getter_address_reg = r2; - - Address getter_address = v8::ToCData<Address>(callback->getter()); - ApiFunction fun(getter_address); - ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; - ExternalReference ref = ExternalReference(&fun, type, isolate()); - __ mov(getter_address_reg, Operand(ref)); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); - - // 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->property_kind() == 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()); - } - // 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(), - IC::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); - __ 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()); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - - ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); - __ TailCallExternalReference( - ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( - Handle<JSObject> object, Handle<Name> name, - Handle<ExecutableAccessorInfo> callback) { - Register holder_reg = Frontend(receiver(), name); - - __ push(receiver()); // receiver - __ push(holder_reg); - __ mov(ip, Operand(callback)); // callback info - __ push(ip); - __ mov(ip, Operand(name)); - __ Push(ip, value()); - - // Do tail-call to the runtime system. - ExternalReference store_callback_property = - ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); - __ TailCallExternalReference(store_callback_property, 5, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- lr : return address - // ----------------------------------- - { - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ldr(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver, value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ pop(r0); - - // Restore context register. - __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( - Handle<Name> name) { - __ Push(receiver(), this->name(), value()); - - // Do tail-call to the runtime system. - ExternalReference store_ic_property = ExternalReference( - IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); - __ TailCallExternalReference(store_ic_property, 3, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - // ----------- S t a t e ------------- - // -- r0 : receiver - // -- r2 : name - // -- lr : return address - // ----------------------------------- - { - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ldr(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - FrontendHeader(receiver(), name, &miss); - - // Get the value from the cell. - Register result = StoreIC::ValueRegister(); - __ mov(result, Operand(cell)); - __ ldr(result, FieldMemOperand(result, Cell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ cmp(result, ip); - __ b(eq, &miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, name); -} - - Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, CodeHandleList* handlers, Handle<Name> name, @@ -909,51 +119,6 @@ #undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // The return address is in lr. - Label slow, miss; - - Register key = LoadIC::NameRegister(); - Register receiver = LoadIC::ReceiverRegister(); - DCHECK(receiver.is(r1)); - DCHECK(key.is(r2)); - - __ UntagAndJumpIfNotSmi(r6, key, &miss); - __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ LoadFromNumberDictionary(&slow, r4, key, r0, r6, r3, r5); - __ Ret(); - - __ bind(&slow); - __ IncrementCounter( - masm->isolate()->counters()->keyed_load_external_array_slow(), 1, r2, r3); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - // Miss case, call the runtime. - __ bind(&miss); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); -} - - -void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), - StoreIC::ValueRegister()); - - __ mov(r0, Operand(Smi::FromInt(strict_mode))); - __ Push(r0); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - -#undef __ } } // namespace v8::internal
diff --git a/src/ic/arm64/handler-compiler-arm64.cc b/src/ic/arm64/handler-compiler-arm64.cc new file mode 100644 index 0000000..a5d0bb4 --- /dev/null +++ b/src/ic/arm64/handler-compiler-arm64.cc
@@ -0,0 +1,872 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_ARM64 + +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( + MacroAssembler* masm, Label* miss_label, Register receiver, + Handle<Name> name, Register scratch0, Register scratch1) { + DCHECK(!AreAliased(receiver, scratch0, scratch1)); + DCHECK(name->IsUniqueName()); + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); + __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); + + Label done; + + const int kInterceptorOrAccessCheckNeededMask = + (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); + + // Bail out if the receiver has a named interceptor or requires access checks. + Register map = scratch1; + __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); + __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask); + __ B(ne, miss_label); + + // Check that receiver is a JSObject. + __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); + __ Cmp(scratch0, FIRST_SPEC_OBJECT_TYPE); + __ B(lt, miss_label); + + // Load properties array. + Register properties = scratch0; + __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); + // Check that the properties array is a dictionary. + __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); + __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label); + + NameDictionaryLookupStub::GenerateNegativeLookup( + masm, miss_label, &done, receiver, properties, name, scratch1); + __ Bind(&done); + __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); +} + + +void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( + MacroAssembler* masm, int index, Register prototype, Label* miss) { + Isolate* isolate = masm->isolate(); + // Get the global function with the given index. + Handle<JSFunction> function( + JSFunction::cast(isolate->native_context()->get(index))); + + // Check we're still in the same context. + Register scratch = prototype; + __ Ldr(scratch, GlobalObjectMemOperand()); + __ Ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); + __ Ldr(scratch, ContextMemOperand(scratch, index)); + __ Cmp(scratch, Operand(function)); + __ B(ne, miss); + + // Load its initial map. The global functions all have initial maps. + __ Mov(prototype, Operand(Handle<Map>(function->initial_map()))); + // Load the prototype from the initial map. + __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); +} + + +void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( + MacroAssembler* masm, Register receiver, Register scratch1, + Register scratch2, Label* miss_label) { + __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); + // TryGetFunctionPrototype can't put the result directly in x0 because the + // 3 inputs registers can't alias and we call this function from + // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly + // move the result in x0. + __ Mov(x0, scratch1); + __ Ret(); +} + + +// Generate code to check that a global property cell is empty. Create +// the property cell at compilation time if no cell exists for the +// property. +void PropertyHandlerCompiler::GenerateCheckPropertyCell( + MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, + Register scratch, Label* miss) { + Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); + DCHECK(cell->value()->IsTheHole()); + __ Mov(scratch, Operand(cell)); + __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); + __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); +} + + +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, + Handle<JSObject> holder_obj) { + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); + + __ Push(name); + Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); + DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); + Register scratch = name; + __ Mov(scratch, Operand(interceptor)); + __ Push(scratch, receiver, holder); +} + + +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + + __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), + NamedLoadHandlerCompiler::kInterceptorArgsLength); +} + + +// Generate call to api function. +void PropertyHandlerCompiler::GenerateFastApiCall( + MacroAssembler* masm, const CallOptimization& optimization, + Handle<Map> receiver_map, Register receiver, Register scratch, + bool is_store, int argc, Register* values) { + DCHECK(!AreAliased(receiver, scratch)); + + MacroAssembler::PushPopQueue queue(masm); + queue.Queue(receiver); + // Write the arguments to the stack frame. + for (int i = 0; i < argc; i++) { + Register arg = values[argc - 1 - i]; + DCHECK(!AreAliased(receiver, scratch, arg)); + queue.Queue(arg); + } + queue.PushQueued(); + + DCHECK(optimization.is_simple_api_call()); + + // Abi for CallApiFunctionStub. + Register callee = x0; + Register call_data = x4; + Register holder = x2; + Register api_function_address = x1; + + // Put holder in place. + CallOptimization::HolderLookup holder_lookup; + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + __ Mov(holder, receiver); + break; + case CallOptimization::kHolderFound: + __ LoadObject(holder, api_holder); + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); + break; + } + + Isolate* isolate = masm->isolate(); + Handle<JSFunction> function = optimization.constant_function(); + Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); + Handle<Object> call_data_obj(api_call_info->data(), isolate); + + // Put callee in place. + __ LoadObject(callee, function); + + bool call_data_undefined = false; + // Put call_data in place. + if (isolate->heap()->InNewSpace(*call_data_obj)) { + __ LoadObject(call_data, api_call_info); + __ Ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); + } else if (call_data_obj->IsUndefined()) { + call_data_undefined = true; + __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); + } else { + __ LoadObject(call_data, call_data_obj); + } + + // Put api_function_address in place. + Address function_address = v8::ToCData<Address>(api_call_info->callback()); + ApiFunction fun(function_address); + ExternalReference ref = ExternalReference( + &fun, ExternalReference::DIRECT_API_CALL, masm->isolate()); + __ Mov(api_function_address, ref); + + // Jump to stub. + CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); + __ TailCallStub(&stub); +} + + +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- lr : return address + // ----------------------------------- + Label miss; + + { + FrameScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ Push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ Ldr(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver, value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ Pop(x0); + + // Restore context register. + __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} + + +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + { + FrameScope scope(masm, StackFrame::INTERNAL); + + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ Ldr(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); + } + + // Restore context register. + __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} + + +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // The return address is in lr. + Label slow, miss; + + Register result = x0; + Register key = LoadIC::NameRegister(); + Register receiver = LoadIC::ReceiverRegister(); + DCHECK(receiver.is(x1)); + DCHECK(key.is(x2)); + + __ JumpIfNotSmi(key, &miss); + __ Ldr(x4, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ LoadFromNumberDictionary(&slow, x4, key, result, x7, x3, x5, x6); + __ Ret(); + + __ Bind(&slow); + __ IncrementCounter( + masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x4, x3); + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); + + // Miss case, call the runtime. + __ Bind(&miss); + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver, name and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow"); + + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +#undef __ +#define __ ACCESS_MASM(masm()) + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( + Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { + Label miss; + FrontendHeader(receiver(), name, &miss); + + // Get the value from the cell. + Register result = StoreIC::ValueRegister(); + __ Mov(result, Operand(cell)); + __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset)); + + // Check for deleted property if property can actually be deleted. + if (is_configurable) { + __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss); + } + + Counters* counters = isolate()->counters(); + __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); + __ Ret(); + + FrontendFooter(name, &miss); + + // Return the generated code. + return GetCode(kind(), Code::NORMAL, name); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( + Handle<Name> name) { + Label miss; + + ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreInterceptor"); + + __ Push(receiver(), this->name(), value()); + + // Do tail-call to the runtime system. + ExternalReference store_ic_property = ExternalReference( + IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); + __ TailCallExternalReference(store_ic_property, 3, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } + + +void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, + Handle<Name> name) { + if (!label->is_unused()) { + __ Bind(label); + __ Mov(this->name(), Operand(name)); + } +} + + +// Generate StoreTransition code, value is passed in x0 register. +// When leaving generated code after success, the receiver_reg and storage_reg +// may be clobbered. Upon branch to miss_label, the receiver and name registers +// have their original values. +void NamedStoreHandlerCompiler::GenerateStoreTransition( + Handle<Map> transition, Handle<Name> name, Register receiver_reg, + Register storage_reg, Register value_reg, Register scratch1, + Register scratch2, Register scratch3, Label* miss_label, Label* slow) { + Label exit; + + DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2, + scratch3)); + + // We don't need scratch3. + scratch3 = NoReg; + + int descriptor = transition->LastAdded(); + DescriptorArray* descriptors = transition->instance_descriptors(); + PropertyDetails details = descriptors->GetDetails(descriptor); + Representation representation = details.representation(); + DCHECK(!representation.IsNone()); + + if (details.type() == CONSTANT) { + Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); + __ LoadObject(scratch1, constant); + __ Cmp(value_reg, scratch1); + __ B(ne, miss_label); + } else if (representation.IsSmi()) { + __ JumpIfNotSmi(value_reg, miss_label); + } else if (representation.IsHeapObject()) { + __ JumpIfSmi(value_reg, miss_label); + HeapType* field_type = descriptors->GetFieldType(descriptor); + HeapType::Iterator<Map> it = field_type->Classes(); + if (!it.Done()) { + __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); + Label do_store; + while (true) { + __ CompareMap(scratch1, it.Current()); + it.Advance(); + if (it.Done()) { + __ B(ne, miss_label); + break; + } + __ B(eq, &do_store); + } + __ Bind(&do_store); + } + } else if (representation.IsDouble()) { + UseScratchRegisterScope temps(masm()); + DoubleRegister temp_double = temps.AcquireD(); + __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag); + + Label do_store; + __ JumpIfSmi(value_reg, &do_store); + + __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, + DONT_DO_SMI_CHECK); + __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); + + __ Bind(&do_store); + __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double, + NoReg, MUTABLE); + } + + // Stub never generated for objects that require access checks. + DCHECK(!transition->is_access_check_needed()); + + // Perform map transition for the receiver if necessary. + if (details.type() == FIELD && + Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { + // The properties must be extended before we can store the value. + // We jump to a runtime call that extends the properties array. + __ Mov(scratch1, Operand(transition)); + __ Push(receiver_reg, scratch1, value_reg); + __ TailCallExternalReference( + ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), + isolate()), + 3, 1); + return; + } + + // Update the map of the object. + __ Mov(scratch1, Operand(transition)); + __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); + + // Update the write barrier for the map field. + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + + if (details.type() == CONSTANT) { + DCHECK(value_reg.is(x0)); + __ Ret(); + return; + } + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= transition->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + Register prop_reg = representation.IsDouble() ? storage_reg : value_reg; + if (index < 0) { + // Set the property straight into the object. + int offset = transition->instance_size() + (index * kPointerSize); + __ Str(prop_reg, FieldMemOperand(receiver_reg, offset)); + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ Mov(storage_reg, value_reg); + } + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kLRHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); + } + } else { + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array + __ Ldr(scratch1, + FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ Str(prop_reg, FieldMemOperand(scratch1, offset)); + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ Mov(storage_reg, value_reg); + } + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kLRHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); + } + } + + __ Bind(&exit); + // Return the value (register x0). + DCHECK(value_reg.is(x0)); + __ Ret(); +} + + +void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, + Register value_reg, + Label* miss_label) { + DCHECK(lookup->representation().IsHeapObject()); + __ JumpIfSmi(value_reg, miss_label); + HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); + __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); + Label do_store; + while (true) { + __ CompareMap(scratch1(), it.Current()); + it.Advance(); + if (it.Done()) { + __ B(ne, miss_label); + break; + } + __ B(eq, &do_store); + } + __ Bind(&do_store); + + StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), + lookup->representation()); + GenerateTailCall(masm(), stub.GetCode()); +} + + +Register PropertyHandlerCompiler::CheckPrototypes( + Register object_reg, Register holder_reg, Register scratch1, + Register scratch2, Handle<Name> name, Label* miss, + PrototypeCheckType check) { + Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); + + // object_reg and holder_reg registers can alias. + DCHECK(!AreAliased(object_reg, scratch1, scratch2)); + DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); + + // Keep track of the current object in register reg. + Register reg = object_reg; + int depth = 0; + + Handle<JSObject> current = Handle<JSObject>::null(); + if (type()->IsConstant()) { + current = Handle<JSObject>::cast(type()->AsConstant()->Value()); + } + Handle<JSObject> prototype = Handle<JSObject>::null(); + Handle<Map> current_map = receiver_map; + Handle<Map> holder_map(holder()->map()); + // Traverse the prototype chain and check the maps in the prototype chain for + // fast and global objects or do negative lookup for normal objects. + while (!current_map.is_identical_to(holder_map)) { + ++depth; + + // Only global objects and objects that do not require access + // checks are allowed in stubs. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + + prototype = handle(JSObject::cast(current_map->prototype())); + if (current_map->is_dictionary_map() && + !current_map->IsJSGlobalObjectMap()) { + DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. + if (!name->IsUniqueName()) { + DCHECK(name->IsString()); + name = factory()->InternalizeString(Handle<String>::cast(name)); + } + DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( + name) == NameDictionary::kNotFound)); + + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); + + __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); + reg = holder_reg; // From now on the object will be in holder_reg. + __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); + } else { + // Two possible reasons for loading the prototype from the map: + // (1) Can't store references to new space in code. + // (2) Handler is shared for all receivers with the same prototype + // map (but not necessarily the same prototype instance). + bool load_prototype_from_map = + heap()->InNewSpace(*prototype) || depth == 1; + Register map_reg = scratch1; + __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); + + if (depth != 1 || check == CHECK_ALL_MAPS) { + __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK); + } + + // Check access rights to the global object. This has to happen after + // the map check so that we know that the object is actually a global + // object. + // This allows us to install generated handlers for accesses to the + // global proxy (as opposed to using slow ICs). See corresponding code + // in LookupForRead(). + if (current_map->IsJSGlobalProxyMap()) { + UseScratchRegisterScope temps(masm()); + __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss); + } else if (current_map->IsJSGlobalObjectMap()) { + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); + } + + reg = holder_reg; // From now on the object will be in holder_reg. + + if (load_prototype_from_map) { + __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); + } else { + __ Mov(reg, Operand(prototype)); + } + } + + // Go to the next object in the prototype chain. + current = prototype; + current_map = handle(current->map()); + } + + // Log the check depth. + LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); + + // Check the holder map. + if (depth != 0 || check == CHECK_ALL_MAPS) { + // Check the holder map. + __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); + } + + // Perform security check for access to the global object. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + if (current_map->IsJSGlobalProxyMap()) { + __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); + } + + // Return the register containing the holder. + return reg; +} + + +void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ B(&success); + + __ Bind(miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + __ Bind(&success); + } +} + + +void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ B(&success); + + GenerateRestoreName(miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + __ Bind(&success); + } +} + + +void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { + // Return the constant value. + __ LoadObject(x0, value); + __ Ret(); +} + + +void NamedLoadHandlerCompiler::GenerateLoadCallback( + Register reg, Handle<ExecutableAccessorInfo> callback) { + DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg)); + + // Build ExecutableAccessorInfo::args_ list on the stack and push property + // name below the exit frame to make GC aware of them and store pointers to + // them. + STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); + STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); + STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); + STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); + STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); + + __ Push(receiver()); + + if (heap()->InNewSpace(callback->data())) { + __ Mov(scratch3(), Operand(callback)); + __ Ldr(scratch3(), + FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); + } else { + __ Mov(scratch3(), Operand(Handle<Object>(callback->data(), isolate()))); + } + __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex); + __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate()))); + __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name()); + + Register args_addr = scratch2(); + __ Add(args_addr, __ StackPointer(), kPointerSize); + + // Stack at this point: + // sp[40] callback data + // sp[32] undefined + // sp[24] undefined + // sp[16] isolate + // args_addr -> sp[8] reg + // sp[0] name + + // Abi for CallApiGetter. + Register getter_address_reg = x2; + + // Set up the call. + Address getter_address = v8::ToCData<Address>(callback->getter()); + ApiFunction fun(getter_address); + ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; + ExternalReference ref = ExternalReference(&fun, type, isolate()); + __ Mov(getter_address_reg, ref); + + CallApiGetterStub stub(isolate()); + __ TailCallStub(&stub); +} + + +void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( + LookupIterator* it, Register holder_reg) { + DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), + scratch3())); + DCHECK(holder()->HasNamedInterceptor()); + DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); + + // 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->property_kind() == 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()); + } + // 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(), + IC::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); + 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()); + PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), + holder()); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); + __ TailCallExternalReference( + ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( + Handle<JSObject> object, Handle<Name> name, + Handle<ExecutableAccessorInfo> callback) { + ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback"); + Register holder_reg = Frontend(receiver(), name); + + // Stub never generated for non-global objects that require access checks. + DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded()); + + // receiver() and holder_reg can alias. + DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value())); + DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value())); + __ Mov(scratch1(), Operand(callback)); + __ Mov(scratch2(), Operand(name)); + __ Push(receiver(), holder_reg, scratch1(), scratch2(), value()); + + // Do tail-call to the runtime system. + ExternalReference store_callback_property = + ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); + __ TailCallExternalReference(store_callback_property, 5, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ic/arm64/ic-arm64.cc b/src/ic/arm64/ic-arm64.cc index bffa603..6985ea5 100644 --- a/src/ic/arm64/ic-arm64.cc +++ b/src/ic/arm64/ic-arm64.cc
@@ -775,20 +775,6 @@ } -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - ASM_LOCATION("KeyedStoreIC::GenerateSlow"); - - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - static void KeyedStoreGenerateGenericHelper( MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, @@ -1069,25 +1055,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // ---------- S t a t e -------------- - // -- x0 : value - // -- x1 : receiver - // -- x2 : name - // -- lr : return address - // ----------------------------------- - - // Push receiver, name and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - Condition CompareIC::ComputeCondition(Token::Value op) { switch (op) { case Token::EQ_STRICT:
diff --git a/src/ic/arm64/ic-compiler-arm64.cc b/src/ic/arm64/ic-compiler-arm64.cc index 3e7f8f5..64b5050 100644 --- a/src/ic/arm64/ic-compiler-arm64.cc +++ b/src/ic/arm64/ic-compiler-arm64.cc
@@ -6,7 +6,6 @@ #if V8_TARGET_ARCH_ARM64 -#include "src/ic/call-optimization.h" #include "src/ic/ic-compiler.h" namespace v8 { @@ -14,195 +13,18 @@ #define __ ACCESS_MASM(masm) +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + ASM_LOCATION("PropertyICCompiler::GenerateRuntimeSetProperty"); -void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( - MacroAssembler* masm, Label* miss_label, Register receiver, - Handle<Name> name, Register scratch0, Register scratch1) { - DCHECK(!AreAliased(receiver, scratch0, scratch1)); - DCHECK(name->IsUniqueName()); - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); - __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); - Label done; + __ Mov(x10, Smi::FromInt(strict_mode)); + __ Push(x10); - const int kInterceptorOrAccessCheckNeededMask = - (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); - - // Bail out if the receiver has a named interceptor or requires access checks. - Register map = scratch1; - __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); - __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask); - __ B(ne, miss_label); - - // Check that receiver is a JSObject. - __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); - __ Cmp(scratch0, FIRST_SPEC_OBJECT_TYPE); - __ B(lt, miss_label); - - // Load properties array. - Register properties = scratch0; - __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - // Check that the properties array is a dictionary. - __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset)); - __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label); - - NameDictionaryLookupStub::GenerateNegativeLookup( - masm, miss_label, &done, receiver, properties, name, scratch1); - __ Bind(&done); - __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); -} - - -void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype, Label* miss) { - Isolate* isolate = masm->isolate(); - // Get the global function with the given index. - Handle<JSFunction> function( - JSFunction::cast(isolate->native_context()->get(index))); - - // Check we're still in the same context. - Register scratch = prototype; - __ Ldr(scratch, GlobalObjectMemOperand()); - __ Ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); - __ Ldr(scratch, ContextMemOperand(scratch, index)); - __ Cmp(scratch, Operand(function)); - __ B(ne, miss); - - // Load its initial map. The global functions all have initial maps. - __ Mov(prototype, Operand(Handle<Map>(function->initial_map()))); - // Load the prototype from the initial map. - __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); -} - - -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - // TryGetFunctionPrototype can't put the result directly in x0 because the - // 3 inputs registers can't alias and we call this function from - // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly - // move the result in x0. - __ Mov(x0, scratch1); - __ Ret(); -} - - -// Generate code to check that a global property cell is empty. Create -// the property cell at compilation time if no cell exists for the -// property. -void PropertyHandlerCompiler::GenerateCheckPropertyCell( - MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, - Register scratch, Label* miss) { - Handle<Cell> cell = JSGlobalObject::EnsurePropertyCell(global, name); - DCHECK(cell->value()->IsTheHole()); - __ Mov(scratch, Operand(cell)); - __ Ldr(scratch, FieldMemOperand(scratch, Cell::kValueOffset)); - __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss); -} - - -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); - - __ Push(name); - Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); - DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); - Register scratch = name; - __ Mov(scratch, Operand(interceptor)); - __ Push(scratch, receiver, holder); -} - - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, IC::UtilityId id) { - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); - - __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), - NamedLoadHandlerCompiler::kInterceptorArgsLength); -} - - -// Generate call to api function. -void PropertyHandlerCompiler::GenerateFastApiCall( - MacroAssembler* masm, const CallOptimization& optimization, - Handle<Map> receiver_map, Register receiver, Register scratch, - bool is_store, int argc, Register* values) { - DCHECK(!AreAliased(receiver, scratch)); - - MacroAssembler::PushPopQueue queue(masm); - queue.Queue(receiver); - // Write the arguments to the stack frame. - for (int i = 0; i < argc; i++) { - Register arg = values[argc - 1 - i]; - DCHECK(!AreAliased(receiver, scratch, arg)); - queue.Queue(arg); - } - queue.PushQueued(); - - DCHECK(optimization.is_simple_api_call()); - - // Abi for CallApiFunctionStub. - Register callee = x0; - Register call_data = x4; - Register holder = x2; - Register api_function_address = x1; - - // Put holder in place. - CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = - optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); - switch (holder_lookup) { - case CallOptimization::kHolderIsReceiver: - __ Mov(holder, receiver); - break; - case CallOptimization::kHolderFound: - __ LoadObject(holder, api_holder); - break; - case CallOptimization::kHolderNotFound: - UNREACHABLE(); - break; - } - - Isolate* isolate = masm->isolate(); - Handle<JSFunction> function = optimization.constant_function(); - Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); - Handle<Object> call_data_obj(api_call_info->data(), isolate); - - // Put callee in place. - __ LoadObject(callee, function); - - bool call_data_undefined = false; - // Put call_data in place. - if (isolate->heap()->InNewSpace(*call_data_obj)) { - __ LoadObject(call_data, api_call_info); - __ Ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); - } else if (call_data_obj->IsUndefined()) { - call_data_undefined = true; - __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); - } else { - __ LoadObject(call_data, call_data_obj); - } - - // Put api_function_address in place. - Address function_address = v8::ToCData<Address>(api_call_info->callback()); - ApiFunction fun(function_address); - ExternalReference ref = ExternalReference( - &fun, ExternalReference::DIRECT_API_CALL, masm->isolate()); - __ Mov(api_function_address, ref); - - // Jump to stub. - CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); - __ TailCallStub(&stub); + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); } @@ -210,621 +32,6 @@ #define __ ACCESS_MASM(masm()) -void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, - Handle<Name> name) { - if (!label->is_unused()) { - __ Bind(label); - __ Mov(this->name(), Operand(name)); - } -} - - -// Generate StoreTransition code, value is passed in x0 register. -// When leaving generated code after success, the receiver_reg and storage_reg -// may be clobbered. Upon branch to miss_label, the receiver and name registers -// have their original values. -void NamedStoreHandlerCompiler::GenerateStoreTransition( - Handle<Map> transition, Handle<Name> name, Register receiver_reg, - Register storage_reg, Register value_reg, Register scratch1, - Register scratch2, Register scratch3, Label* miss_label, Label* slow) { - Label exit; - - DCHECK(!AreAliased(receiver_reg, storage_reg, value_reg, scratch1, scratch2, - scratch3)); - - // We don't need scratch3. - scratch3 = NoReg; - - int descriptor = transition->LastAdded(); - DescriptorArray* descriptors = transition->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - Representation representation = details.representation(); - DCHECK(!representation.IsNone()); - - if (details.type() == CONSTANT) { - Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); - __ LoadObject(scratch1, constant); - __ Cmp(value_reg, scratch1); - __ B(ne, miss_label); - } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); - } else if (representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_label); - HeapType* field_type = descriptors->GetFieldType(descriptor); - HeapType::Iterator<Map> it = field_type->Classes(); - if (!it.Done()) { - __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); - Label do_store; - while (true) { - __ CompareMap(scratch1, it.Current()); - it.Advance(); - if (it.Done()) { - __ B(ne, miss_label); - break; - } - __ B(eq, &do_store); - } - __ Bind(&do_store); - } - } else if (representation.IsDouble()) { - UseScratchRegisterScope temps(masm()); - DoubleRegister temp_double = temps.AcquireD(); - __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag); - - Label do_store; - __ JumpIfSmi(value_reg, &do_store); - - __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, - DONT_DO_SMI_CHECK); - __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); - - __ Bind(&do_store); - __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double, - NoReg, MUTABLE); - } - - // Stub never generated for objects that require access checks. - DCHECK(!transition->is_access_check_needed()); - - // Perform map transition for the receiver if necessary. - if (details.type() == FIELD && - Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { - // The properties must be extended before we can store the value. - // We jump to a runtime call that extends the properties array. - __ Mov(scratch1, Operand(transition)); - __ Push(receiver_reg, scratch1, value_reg); - __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); - return; - } - - // Update the map of the object. - __ Mov(scratch1, Operand(transition)); - __ Str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); - - // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, - kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); - - if (details.type() == CONSTANT) { - DCHECK(value_reg.is(x0)); - __ Ret(); - return; - } - - int index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); - - // Adjust for the number of properties stored in the object. Even in the - // face of a transition we can use the old map here because the size of the - // object and the number of in-object properties is not going to change. - index -= transition->inobject_properties(); - - // TODO(verwaest): Share this code as a code stub. - SmiCheck smi_check = - representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; - Register prop_reg = representation.IsDouble() ? storage_reg : value_reg; - if (index < 0) { - // Set the property straight into the object. - int offset = transition->instance_size() + (index * kPointerSize); - __ Str(prop_reg, FieldMemOperand(receiver_reg, offset)); - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ Mov(storage_reg, value_reg); - } - __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, - kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, smi_check); - } - } else { - // Write to the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - // Get the properties array - __ Ldr(scratch1, - FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); - __ Str(prop_reg, FieldMemOperand(scratch1, offset)); - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ Mov(storage_reg, value_reg); - } - __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, - kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, smi_check); - } - } - - __ Bind(&exit); - // Return the value (register x0). - DCHECK(value_reg.is(x0)); - __ Ret(); -} - - -void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, - Register value_reg, - Label* miss_label) { - DCHECK(lookup->representation().IsHeapObject()); - __ JumpIfSmi(value_reg, miss_label); - HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); - __ Ldr(scratch1(), FieldMemOperand(value_reg, HeapObject::kMapOffset)); - Label do_store; - while (true) { - __ CompareMap(scratch1(), it.Current()); - it.Advance(); - if (it.Done()) { - __ B(ne, miss_label); - break; - } - __ B(eq, &do_store); - } - __ Bind(&do_store); - - StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), - lookup->representation()); - GenerateTailCall(masm(), stub.GetCode()); -} - - -Register PropertyHandlerCompiler::CheckPrototypes( - Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - PrototypeCheckType check) { - Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); - - // object_reg and holder_reg registers can alias. - DCHECK(!AreAliased(object_reg, scratch1, scratch2)); - DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); - - // Keep track of the current object in register reg. - Register reg = object_reg; - int depth = 0; - - Handle<JSObject> current = Handle<JSObject>::null(); - if (type()->IsConstant()) { - current = Handle<JSObject>::cast(type()->AsConstant()->Value()); - } - Handle<JSObject> prototype = Handle<JSObject>::null(); - Handle<Map> current_map = receiver_map; - Handle<Map> holder_map(holder()->map()); - // Traverse the prototype chain and check the maps in the prototype chain for - // fast and global objects or do negative lookup for normal objects. - while (!current_map.is_identical_to(holder_map)) { - ++depth; - - // Only global objects and objects that do not require access - // checks are allowed in stubs. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - - prototype = handle(JSObject::cast(current_map->prototype())); - if (current_map->is_dictionary_map() && - !current_map->IsJSGlobalObjectMap()) { - DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. - if (!name->IsUniqueName()) { - DCHECK(name->IsString()); - name = factory()->InternalizeString(Handle<String>::cast(name)); - } - DCHECK(current.is_null() || (current->property_dictionary()->FindEntry( - name) == NameDictionary::kNotFound)); - - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, - scratch2); - - __ Ldr(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset)); - } else { - // Two possible reasons for loading the prototype from the map: - // (1) Can't store references to new space in code. - // (2) Handler is shared for all receivers with the same prototype - // map (but not necessarily the same prototype instance). - bool load_prototype_from_map = - heap()->InNewSpace(*prototype) || depth == 1; - Register map_reg = scratch1; - __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); - - if (depth != 1 || check == CHECK_ALL_MAPS) { - __ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Check access rights to the global object. This has to happen after - // the map check so that we know that the object is actually a global - // object. - // This allows us to install generated handlers for accesses to the - // global proxy (as opposed to using slow ICs). See corresponding code - // in LookupForRead(). - if (current_map->IsJSGlobalProxyMap()) { - UseScratchRegisterScope temps(masm()); - __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss); - } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), - name, scratch2, miss); - } - - reg = holder_reg; // From now on the object will be in holder_reg. - - if (load_prototype_from_map) { - __ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); - } else { - __ Mov(reg, Operand(prototype)); - } - } - - // Go to the next object in the prototype chain. - current = prototype; - current_map = handle(current->map()); - } - - // Log the check depth. - LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - - // Check the holder map. - if (depth != 0 || check == CHECK_ALL_MAPS) { - // Check the holder map. - __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Perform security check for access to the global object. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); - } - - // Return the register containing the holder. - return reg; -} - - -void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ B(&success); - - __ Bind(miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - __ Bind(&success); - } -} - - -void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ B(&success); - - GenerateRestoreName(miss, name); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - __ Bind(&success); - } -} - - -void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { - // Return the constant value. - __ LoadObject(x0, value); - __ Ret(); -} - - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle<ExecutableAccessorInfo> callback) { - DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg)); - - // Build ExecutableAccessorInfo::args_ list on the stack and push property - // name below the exit frame to make GC aware of them and store pointers to - // them. - STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); - STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); - STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); - STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); - STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); - - __ Push(receiver()); - - if (heap()->InNewSpace(callback->data())) { - __ Mov(scratch3(), Operand(callback)); - __ Ldr(scratch3(), - FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); - } else { - __ Mov(scratch3(), Operand(Handle<Object>(callback->data(), isolate()))); - } - __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex); - __ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate()))); - __ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name()); - - Register args_addr = scratch2(); - __ Add(args_addr, __ StackPointer(), kPointerSize); - - // Stack at this point: - // sp[40] callback data - // sp[32] undefined - // sp[24] undefined - // sp[16] isolate - // args_addr -> sp[8] reg - // sp[0] name - - // Abi for CallApiGetter. - Register getter_address_reg = x2; - - // Set up the call. - Address getter_address = v8::ToCData<Address>(callback->getter()); - ApiFunction fun(getter_address); - ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; - ExternalReference ref = ExternalReference(&fun, type, isolate()); - __ Mov(getter_address_reg, ref); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(), - scratch3())); - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); - - // 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->property_kind() == 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()); - } - // 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(), - IC::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); - 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()); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - - ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); - __ TailCallExternalReference( - ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( - Handle<JSObject> object, Handle<Name> name, - Handle<ExecutableAccessorInfo> callback) { - ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback"); - Register holder_reg = Frontend(receiver(), name); - - // Stub never generated for non-global objects that require access checks. - DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded()); - - // receiver() and holder_reg can alias. - DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value())); - DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value())); - __ Mov(scratch1(), Operand(callback)); - __ Mov(scratch2(), Operand(name)); - __ Push(receiver(), holder_reg, scratch1(), scratch2(), value()); - - // Do tail-call to the runtime system. - ExternalReference store_callback_property = - ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); - __ TailCallExternalReference(store_callback_property, 5, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- lr : return address - // ----------------------------------- - Label miss; - - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ Push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ Ldr(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver, value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ Pop(x0); - - // Restore context register. - __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( - Handle<Name> name) { - Label miss; - - ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreInterceptor"); - - __ Push(receiver(), this->name(), value()); - - // Do tail-call to the runtime system. - ExternalReference store_ic_property = ExternalReference( - IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); - __ TailCallExternalReference(store_ic_property, 3, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } - - -#undef __ -#define __ ACCESS_MASM(masm) - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ Ldr(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - FrontendHeader(receiver(), name, &miss); - - // Get the value from the cell. - Register result = StoreIC::ValueRegister(); - __ Mov(result, Operand(cell)); - __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); - __ Ret(); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, name); -} - - Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, CodeHandleList* handlers, Handle<Name> name, @@ -915,51 +122,6 @@ #undef __ -#define __ ACCESS_MASM(masm) - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // The return address is in lr. - Label slow, miss; - - Register result = x0; - Register key = LoadIC::NameRegister(); - Register receiver = LoadIC::ReceiverRegister(); - DCHECK(receiver.is(x1)); - DCHECK(key.is(x2)); - - __ JumpIfNotSmi(key, &miss); - __ Ldr(x4, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ LoadFromNumberDictionary(&slow, x4, key, result, x7, x3, x5, x6); - __ Ret(); - - __ Bind(&slow); - __ IncrementCounter( - masm->isolate()->counters()->keyed_load_external_array_slow(), 1, x4, x3); - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - // Miss case, call the runtime. - __ Bind(&miss); - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); -} - - -void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - ASM_LOCATION("PropertyICCompiler::GenerateRuntimeSetProperty"); - - __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), - StoreIC::ValueRegister()); - - __ Mov(x10, Smi::FromInt(strict_mode)); - __ Push(x10); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - -#undef __ } } // namespace v8::internal
diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc new file mode 100644 index 0000000..5c747c1 --- /dev/null +++ b/src/ic/handler-compiler.cc
@@ -0,0 +1,392 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" +#include "src/ic/ic-inl.h" + +namespace v8 { +namespace internal { + + +Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, + Handle<Map> stub_holder, + Code::Kind kind, + CacheHolderFlag cache_holder, + Code::StubType type) { + Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); + Object* probe = stub_holder->FindInCodeCache(*name, flags); + if (probe->IsCode()) return handle(Code::cast(probe)); + return Handle<Code>::null(); +} + + +Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent( + Handle<Name> name, Handle<HeapType> type) { + Isolate* isolate = name->GetIsolate(); + Handle<Map> receiver_map = IC::TypeToMap(*type, isolate); + if (receiver_map->prototype()->IsNull()) { + // TODO(jkummerow/verwaest): If there is no prototype and the property + // is nonexistent, introduce a builtin to handle this (fast properties + // -> return undefined, dictionary properties -> do negative lookup). + return Handle<Code>(); + } + CacheHolderFlag flag; + Handle<Map> stub_holder_map = + IC::GetHandlerCacheHolder(*type, false, isolate, &flag); + + // If no dictionary mode 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 there are dictionary + // mode objects involved, we need to do negative lookups in the stub and + // therefore the stub will be specific to the name. + Handle<Name> cache_name = + receiver_map->is_dictionary_map() + ? name + : Handle<Name>::cast(isolate->factory()->nonexistent_symbol()); + Handle<Map> current_map = stub_holder_map; + Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); + while (true) { + if (current_map->is_dictionary_map()) cache_name = name; + if (current_map->prototype()->IsNull()) break; + last = handle(JSObject::cast(current_map->prototype())); + current_map = handle(last->map()); + } + // Compile the stub that is either shared for all names or + // name specific if there are global objects involved. + Handle<Code> handler = PropertyHandlerCompiler::Find( + cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); + if (!handler.is_null()) return handler; + + NamedLoadHandlerCompiler compiler(isolate, type, last, flag); + handler = compiler.CompileLoadNonexistent(cache_name); + Map::UpdateCodeCache(stub_holder_map, cache_name, handler); + return handler; +} + + +Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, + Code::StubType type, + Handle<Name> name) { + Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder()); + Handle<Code> code = GetCodeWithFlags(flags, name); + PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name)); + return code; +} + + +#define __ ACCESS_MASM(masm()) + + +Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, + Handle<Name> name, + Label* miss) { + PrototypeCheckType check_type = CHECK_ALL_MAPS; + int function_index = -1; + if (type()->Is(HeapType::String())) { + function_index = Context::STRING_FUNCTION_INDEX; + } else if (type()->Is(HeapType::Symbol())) { + function_index = Context::SYMBOL_FUNCTION_INDEX; + } else if (type()->Is(HeapType::Number())) { + function_index = Context::NUMBER_FUNCTION_INDEX; + } else if (type()->Is(HeapType::Boolean())) { + function_index = Context::BOOLEAN_FUNCTION_INDEX; + } else { + check_type = SKIP_RECEIVER; + } + + if (check_type == CHECK_ALL_MAPS) { + GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index, + scratch1(), miss); + Object* function = isolate()->native_context()->get(function_index); + Object* prototype = JSFunction::cast(function)->instance_prototype(); + set_type_for_object(handle(prototype, isolate())); + object_reg = scratch1(); + } + + // Check that the maps starting from the prototype haven't changed. + return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, + miss, check_type); +} + + +// Frontend for store uses the name register. It has to be restored before a +// miss. +Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, + Handle<Name> name, + Label* miss) { + return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, + miss, SKIP_RECEIVER); +} + + +Register PropertyHandlerCompiler::Frontend(Register object_reg, + Handle<Name> name) { + Label miss; + Register reg = FrontendHeader(object_reg, name, &miss); + FrontendFooter(name, &miss); + return reg; +} + + +void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, + Label* miss, + Register scratch1, + Register scratch2) { + Register holder_reg; + Handle<Map> last_map; + if (holder().is_null()) { + holder_reg = receiver(); + last_map = IC::TypeToMap(*type(), isolate()); + // If |type| has null as its prototype, |holder()| is + // Handle<JSObject>::null(). + DCHECK(last_map->prototype() == isolate()->heap()->null_value()); + } else { + holder_reg = FrontendHeader(receiver(), name, miss); + last_map = handle(holder()->map()); + } + + if (last_map->is_dictionary_map()) { + if (last_map->IsJSGlobalObjectMap()) { + Handle<JSGlobalObject> global = + holder().is_null() + ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value()) + : Handle<JSGlobalObject>::cast(holder()); + GenerateCheckPropertyCell(masm(), global, name, scratch1, miss); + } else { + if (!name->IsUniqueName()) { + DCHECK(name->IsString()); + name = factory()->InternalizeString(Handle<String>::cast(name)); + } + DCHECK(holder().is_null() || + holder()->property_dictionary()->FindEntry(name) == + NameDictionary::kNotFound); + GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, + scratch2); + } + } +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, + FieldIndex field) { + Register reg = Frontend(receiver(), name); + __ Move(receiver(), reg); + LoadFieldStub stub(isolate(), field); + GenerateTailCall(masm(), stub.GetCode()); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, + int constant_index) { + Register reg = Frontend(receiver(), name); + __ Move(receiver(), reg); + LoadConstantStub stub(isolate(), constant_index); + GenerateTailCall(masm(), stub.GetCode()); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( + Handle<Name> name) { + Label miss; + NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); + GenerateLoadConstant(isolate()->factory()->undefined_value()); + FrontendFooter(name, &miss); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( + Handle<Name> name, Handle<ExecutableAccessorInfo> callback) { + Register reg = Frontend(receiver(), name); + GenerateLoadCallback(reg, callback); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( + Handle<Name> name, const CallOptimization& call_optimization) { + DCHECK(call_optimization.is_simple_api_call()); + Frontend(receiver(), name); + Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate()); + GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(), + scratch1(), false, 0, NULL); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( + LookupIterator* it) { + // So far the most popular follow ups for interceptor loads are FIELD and + // ExecutableAccessorInfo, so inline only them. Other cases may be added + // later. + bool inline_followup = it->state() == LookupIterator::PROPERTY; + if (inline_followup) { + switch (it->property_kind()) { + case LookupIterator::DATA: + inline_followup = it->property_details().type() == FIELD; + break; + case LookupIterator::ACCESSOR: { + Handle<Object> accessors = it->GetAccessors(); + inline_followup = accessors->IsExecutableAccessorInfo(); + if (!inline_followup) break; + Handle<ExecutableAccessorInfo> info = + Handle<ExecutableAccessorInfo>::cast(accessors); + inline_followup = info->getter() != NULL && + ExecutableAccessorInfo::IsCompatibleReceiverType( + isolate(), info, type()); + } + } + } + + Register reg = Frontend(receiver(), it->name()); + 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(), Code::FAST, it->name()); +} + + +void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( + LookupIterator* it, Register interceptor_reg) { + Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); + + set_type_for_object(holder()); + set_holder(real_named_property_holder); + Register reg = Frontend(interceptor_reg, it->name()); + + switch (it->property_kind()) { + case LookupIterator::DATA: { + DCHECK_EQ(FIELD, it->property_details().type()); + __ Move(receiver(), reg); + LoadFieldStub stub(isolate(), it->GetFieldIndex()); + GenerateTailCall(masm(), stub.GetCode()); + break; + } + case LookupIterator::ACCESSOR: + Handle<ExecutableAccessorInfo> info = + Handle<ExecutableAccessorInfo>::cast(it->GetAccessors()); + DCHECK_NE(NULL, info->getter()); + GenerateLoadCallback(reg, info); + } +} + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( + Handle<Name> name, Handle<JSFunction> getter) { + Frontend(receiver(), name); + GenerateLoadViaGetter(masm(), type(), receiver(), getter); + return GetCode(kind(), Code::FAST, name); +} + + +// TODO(verwaest): Cleanup. holder() is actually the receiver. +Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( + Handle<Map> transition, Handle<Name> name) { + Label miss, slow; + + // Ensure no transitions to deprecated maps are followed. + __ CheckMapDeprecated(transition, scratch1(), &miss); + + // Check that we are allowed to write this. + bool is_nonexistent = holder()->map() == transition->GetBackPointer(); + if (is_nonexistent) { + // Find the top object. + Handle<JSObject> last; + PrototypeIterator iter(isolate(), holder()); + while (!iter.IsAtEnd()) { + last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); + iter.Advance(); + } + if (!last.is_null()) set_holder(last); + NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); + } else { + FrontendHeader(receiver(), name, &miss); + DCHECK(holder()->HasFastProperties()); + } + + GenerateStoreTransition(transition, name, receiver(), this->name(), value(), + scratch1(), scratch2(), scratch3(), &miss, &slow); + + GenerateRestoreName(&miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + GenerateRestoreName(&slow, name); + TailCallBuiltin(masm(), SlowBuiltin(kind())); + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { + Label miss; + GenerateStoreField(it, value(), &miss); + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + return GetCode(kind(), Code::FAST, it->name()); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( + Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) { + Frontend(receiver(), name); + GenerateStoreViaSetter(masm(), type(), receiver(), setter); + + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( + Handle<JSObject> object, Handle<Name> name, + const CallOptimization& call_optimization) { + Frontend(receiver(), name); + Register values[] = {value()}; + GenerateFastApiCall(masm(), call_optimization, handle(object->map()), + receiver(), scratch1(), true, 1, values); + return GetCode(kind(), Code::FAST, name); +} + + +#undef __ + + +void ElementHandlerCompiler::CompileElementHandlers( + MapHandleList* receiver_maps, CodeHandleList* handlers) { + for (int i = 0; i < receiver_maps->length(); ++i) { + Handle<Map> receiver_map = receiver_maps->at(i); + Handle<Code> cached_stub; + + if ((receiver_map->instance_type() & kNotStringTag) == 0) { + cached_stub = isolate()->builtins()->KeyedLoadIC_String(); + } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { + cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); + } else { + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; + ElementsKind elements_kind = receiver_map->elements_kind(); + + if (IsFastElementsKind(elements_kind) || + IsExternalArrayElementsKind(elements_kind) || + IsFixedTypedArrayElementsKind(elements_kind)) { + cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind) + .GetCode(); + } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { + cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments(); + } else { + DCHECK(elements_kind == DICTIONARY_ELEMENTS); + cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); + } + } + + handlers->Add(cached_stub); + } +} +} +} // namespace v8::internal
diff --git a/src/ic/handler-compiler.h b/src/ic/handler-compiler.h new file mode 100644 index 0000000..af54e2c --- /dev/null +++ b/src/ic/handler-compiler.h
@@ -0,0 +1,277 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_IC_HANDLER_COMPILER_H_ +#define V8_IC_HANDLER_COMPILER_H_ + +#include "src/ic/access-compiler.h" + +namespace v8 { +namespace internal { + +class CallOptimization; + +enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; + +class PropertyHandlerCompiler : public PropertyAccessCompiler { + public: + static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind, + CacheHolderFlag cache_holder, Code::StubType type); + + protected: + PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, + Handle<HeapType> type, Handle<JSObject> holder, + CacheHolderFlag cache_holder) + : PropertyAccessCompiler(isolate, kind, cache_holder), + type_(type), + holder_(holder) {} + + virtual ~PropertyHandlerCompiler() {} + + virtual Register FrontendHeader(Register object_reg, Handle<Name> name, + Label* miss) { + UNREACHABLE(); + return receiver(); + } + + virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); } + + Register Frontend(Register object_reg, Handle<Name> name); + void NonexistentFrontendHeader(Handle<Name> name, Label* miss, + Register scratch1, Register scratch2); + + // TODO(verwaest): Make non-static. + static void GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + Handle<Map> receiver_map, Register receiver, + Register scratch, bool is_store, int argc, + Register* values); + + // Helper function used to check that the dictionary doesn't contain + // the property. This function may return false negatives, so miss_label + // must always call a backup property check that is complete. + // This function is safe to call if the receiver has fast properties. + // Name must be unique and receiver must be a heap object. + static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, + Label* miss_label, + Register receiver, + Handle<Name> name, Register r0, + Register r1); + + // Generate code to check that a global property cell is empty. Create + // the property cell at compilation time if no cell exists for the + // property. + static void GenerateCheckPropertyCell(MacroAssembler* masm, + Handle<JSGlobalObject> global, + Handle<Name> name, Register scratch, + Label* miss); + + // Generates code that verifies that the property holder has not changed + // (checking maps of objects in the prototype chain for fast and global + // objects or doing negative lookup for slow objects, ensures that the + // property cells for global objects are still empty) and checks that the map + // of the holder has not changed. If necessary the function also generates + // code for security check in case of global object holders. Helps to make + // sure that the current IC is still valid. + // + // The scratch and holder registers are always clobbered, but the object + // register is only clobbered if it the same as the holder register. The + // function returns a register containing the holder - either object_reg or + // holder_reg. + Register CheckPrototypes(Register object_reg, Register holder_reg, + Register scratch1, Register scratch2, + Handle<Name> name, Label* miss, + PrototypeCheckType check = CHECK_ALL_MAPS); + + Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name); + void set_type_for_object(Handle<Object> object) { + type_ = IC::CurrentTypeOf(object, isolate()); + } + void set_holder(Handle<JSObject> holder) { holder_ = holder; } + Handle<HeapType> type() const { return type_; } + Handle<JSObject> holder() const { return holder_; } + + private: + Handle<HeapType> type_; + Handle<JSObject> holder_; +}; + + +class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { + public: + NamedLoadHandlerCompiler(Isolate* isolate, Handle<HeapType> type, + Handle<JSObject> holder, + CacheHolderFlag cache_holder) + : PropertyHandlerCompiler(isolate, Code::LOAD_IC, type, holder, + cache_holder) {} + + virtual ~NamedLoadHandlerCompiler() {} + + Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index); + + Handle<Code> CompileLoadCallback(Handle<Name> name, + Handle<ExecutableAccessorInfo> callback); + + Handle<Code> CompileLoadCallback(Handle<Name> name, + const CallOptimization& call_optimization); + + Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index); + + // The LookupIterator is used to perform a lookup behind the interceptor. If + // the iterator points to a LookupIterator::PROPERTY, its access will be + // inlined. + Handle<Code> CompileLoadInterceptor(LookupIterator* it); + + Handle<Code> CompileLoadViaGetter(Handle<Name> name, + Handle<JSFunction> getter); + + Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name, + bool is_configurable); + + // Static interface + static Handle<Code> ComputeLoadNonexistent(Handle<Name> name, + Handle<HeapType> type); + + static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<HeapType> type, + Register receiver, + Handle<JSFunction> getter); + + static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { + GenerateLoadViaGetter(masm, Handle<HeapType>::null(), no_reg, + Handle<JSFunction>()); + } + + static void GenerateLoadFunctionPrototype(MacroAssembler* masm, + Register receiver, + Register scratch1, + Register scratch2, + Label* miss_label); + + // These constants describe the structure of the interceptor arguments on the + // stack. The arguments are pushed by the (platform-specific) + // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and + // LoadWithInterceptor. + static const int kInterceptorArgsNameIndex = 0; + static const int kInterceptorArgsInfoIndex = 1; + static const int kInterceptorArgsThisIndex = 2; + static const int kInterceptorArgsHolderIndex = 3; + static const int kInterceptorArgsLength = 4; + + protected: + virtual Register FrontendHeader(Register object_reg, Handle<Name> name, + Label* miss); + + virtual void FrontendFooter(Handle<Name> name, Label* miss); + + private: + Handle<Code> CompileLoadNonexistent(Handle<Name> name); + void GenerateLoadConstant(Handle<Object> value); + void GenerateLoadCallback(Register reg, + Handle<ExecutableAccessorInfo> callback); + void GenerateLoadCallback(const CallOptimization& call_optimization, + Handle<Map> receiver_map); + void GenerateLoadInterceptor(Register holder_reg); + void GenerateLoadInterceptorWithFollowup(LookupIterator* it, + Register holder_reg); + void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); + + // Generates prototype loading code that uses the objects from the + // context we were in when this function was called. If the context + // has changed, a jump to miss is performed. This ties the generated + // code to a particular context and so must not be used in cases + // where the generated code is not allowed to have references to + // objects from a context. + static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, + int index, + Register prototype, + Label* miss); + + + Register scratch4() { return registers_[5]; } +}; + + +class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { + public: + explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type, + Handle<JSObject> holder) + : PropertyHandlerCompiler(isolate, Code::STORE_IC, type, holder, + kCacheOnReceiver) {} + + virtual ~NamedStoreHandlerCompiler() {} + + Handle<Code> CompileStoreTransition(Handle<Map> transition, + Handle<Name> name); + Handle<Code> CompileStoreField(LookupIterator* it); + Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, + Handle<ExecutableAccessorInfo> callback); + Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, + const CallOptimization& call_optimization); + Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name, + Handle<JSFunction> setter); + Handle<Code> CompileStoreInterceptor(Handle<Name> name); + + static void GenerateStoreViaSetter(MacroAssembler* masm, + Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter); + + static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { + GenerateStoreViaSetter(masm, Handle<HeapType>::null(), no_reg, + Handle<JSFunction>()); + } + + static void GenerateSlow(MacroAssembler* masm); + + protected: + virtual Register FrontendHeader(Register object_reg, Handle<Name> name, + Label* miss); + + virtual void FrontendFooter(Handle<Name> name, Label* miss); + void GenerateRestoreName(Label* label, Handle<Name> name); + + private: + void GenerateStoreTransition(Handle<Map> transition, Handle<Name> name, + Register receiver_reg, Register name_reg, + Register value_reg, Register scratch1, + Register scratch2, Register scratch3, + Label* miss_label, Label* slow); + + void GenerateStoreField(LookupIterator* lookup, Register value_reg, + Label* miss_label); + + static Builtins::Name SlowBuiltin(Code::Kind kind) { + switch (kind) { + case Code::STORE_IC: + return Builtins::kStoreIC_Slow; + case Code::KEYED_STORE_IC: + return Builtins::kKeyedStoreIC_Slow; + default: + UNREACHABLE(); + } + return Builtins::kStoreIC_Slow; + } + + static Register value(); +}; + + +class ElementHandlerCompiler : public PropertyHandlerCompiler { + public: + explicit ElementHandlerCompiler(Isolate* isolate) + : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, + Handle<HeapType>::null(), + Handle<JSObject>::null(), kCacheOnReceiver) {} + + virtual ~ElementHandlerCompiler() {} + + void CompileElementHandlers(MapHandleList* receiver_maps, + CodeHandleList* handlers); + + static void GenerateLoadDictionaryElement(MacroAssembler* masm); + static void GenerateStoreSlow(MacroAssembler* masm); +}; +} +} // namespace v8::internal + +#endif // V8_IC_HANDLER_COMPILER_H_
diff --git a/src/x87/stub-cache-x87.cc b/src/ic/ia32/handler-compiler-ia32.cc similarity index 68% copy from src/x87/stub-cache-x87.cc copy to src/ic/ia32/handler-compiler-ia32.cc index dedbaa6..48b8adc 100644 --- a/src/x87/stub-cache-x87.cc +++ b/src/ic/ia32/handler-compiler-ia32.cc
@@ -1,14 +1,13 @@ -// Copyright 2012 the V8 project authors. All rights reserved. +// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/v8.h" -#if V8_TARGET_ARCH_X87 +#if V8_TARGET_ARCH_IA32 -#include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/stub-cache.h" +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" namespace v8 { namespace internal { @@ -16,101 +15,80 @@ #define __ ACCESS_MASM(masm) -static void ProbeTable(Isolate* isolate, - MacroAssembler* masm, - Code::Flags flags, - StubCache::Table table, - Register name, - Register receiver, - // Number of the cache entry pointer-size scaled. - Register offset, - Register extra) { - ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); - ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); - ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- ecx : key + // -- edx : receiver + // -- esp[0] : return address + // ----------------------------------- + DCHECK(edx.is(LoadIC::ReceiverRegister())); + DCHECK(ecx.is(LoadIC::NameRegister())); + Label slow, miss; - Label miss; + // This stub is meant to be tail-jumped to, the receiver must already + // have been verified by the caller to not be a smi. + __ JumpIfNotSmi(ecx, &miss); + __ mov(ebx, ecx); + __ SmiUntag(ebx); + __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); - // Multiply by 3 because there are 3 fields per entry (name, code, map). - __ lea(offset, Operand(offset, offset, times_2, 0)); + // Push receiver on the stack to free up a register for the dictionary + // probing. + __ push(edx); + __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax); + // Pop receiver before returning. + __ pop(edx); + __ ret(0); - if (extra.is_valid()) { - // Get the code entry from the cache. - __ mov(extra, Operand::StaticArray(offset, times_1, value_offset)); + __ bind(&slow); + __ pop(edx); - // Check that the key in the entry matches the name. - __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); - __ j(not_equal, &miss); + // ----------- S t a t e ------------- + // -- ecx : key + // -- edx : receiver + // -- esp[0] : return address + // ----------------------------------- + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - // Check the map matches. - __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); - __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ j(not_equal, &miss); + __ bind(&miss); + // ----------- S t a t e ------------- + // -- ecx : key + // -- edx : receiver + // -- esp[0] : return address + // ----------------------------------- + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} - // Check that the flags match what we're looking for. - __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); - __ and_(offset, ~Code::kFlagsNotUsedInLookup); - __ cmp(offset, flags); - __ j(not_equal, &miss); -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + { + FrameScope scope(masm, StackFrame::INTERNAL); + + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ mov(receiver, + FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); } -#endif - // Jump to the first instruction in the code stub. - __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag)); - __ jmp(extra); - - __ bind(&miss); - } else { - // Save the offset on the stack. - __ push(offset); - - // Check that the key in the entry matches the name. - __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); - __ j(not_equal, &miss); - - // Check the map matches. - __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); - __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ j(not_equal, &miss); - - // Restore offset register. - __ mov(offset, Operand(esp, 0)); - - // Get the code entry from the cache. - __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); - - // Check that the flags match what we're looking for. - __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); - __ and_(offset, ~Code::kFlagsNotUsedInLookup); - __ cmp(offset, flags); - __ j(not_equal, &miss); - -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); - } -#endif - - // Restore offset and re-load code entry from cache. - __ pop(offset); - __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); - - // Jump to the first instruction in the code stub. - __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag)); - __ jmp(offset); - - // Pop at miss. - __ bind(&miss); - __ pop(offset); + // Restore context register. + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); } + __ ret(0); } @@ -147,89 +125,13 @@ __ j(not_equal, miss_label); Label done; - NameDictionaryLookupStub::GenerateNegativeLookup(masm, - miss_label, - &done, - properties, - name, - scratch1); + NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, + properties, name, scratch1); __ bind(&done); __ DecrementCounter(counters->negative_lookups_miss(), 1); } -void StubCache::GenerateProbe(MacroAssembler* masm, - Code::Flags flags, - Register receiver, - Register name, - Register scratch, - Register extra, - Register extra2, - Register extra3) { - Label miss; - - // Assert that code is valid. The multiplying code relies on the entry size - // being 12. - DCHECK(sizeof(Entry) == 12); - - // Assert the flags do not name a specific type. - DCHECK(Code::ExtractTypeFromFlags(flags) == 0); - - // Assert that there are no register conflicts. - DCHECK(!scratch.is(receiver)); - DCHECK(!scratch.is(name)); - DCHECK(!extra.is(receiver)); - DCHECK(!extra.is(name)); - DCHECK(!extra.is(scratch)); - - // Assert scratch and extra registers are valid, and extra2/3 are unused. - DCHECK(!scratch.is(no_reg)); - DCHECK(extra2.is(no_reg)); - DCHECK(extra3.is(no_reg)); - - Register offset = scratch; - scratch = no_reg; - - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(receiver, &miss); - - // Get the map of the receiver and compute the hash. - __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); - __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ xor_(offset, flags); - // We mask out the last two bits because they are not part of the hash and - // they are always 01 for maps. Also in the two 'and' instructions below. - __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); - // ProbeTable expects the offset to be pointer scaled, which it is, because - // the heap object tag size is 2 and the pointer size log 2 is also 2. - DCHECK(kCacheIndexShift == kPointerSizeLog2); - - // Probe the primary table. - ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra); - - // Primary miss: Compute hash for secondary probe. - __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); - __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ xor_(offset, flags); - __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); - __ sub(offset, name); - __ add(offset, Immediate(flags)); - __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift); - - // Probe the secondary table. - ProbeTable( - isolate(), masm, flags, kSecondary, name, receiver, offset, extra); - - // Cache miss: Fall-through and let caller handle the miss by - // entering the runtime system. - __ bind(&miss); - __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); -} - - void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( MacroAssembler* masm, int index, Register prototype, Label* miss) { // Get the global function with the given index. @@ -259,40 +161,6 @@ } -static void PushInterceptorArguments(MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); - __ push(name); - Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); - DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); - Register scratch = name; - __ mov(scratch, Immediate(interceptor)); - __ push(scratch); - __ push(receiver); - __ push(holder); -} - - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - Handle<JSObject> holder_obj, - IC::UtilityId id) { - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); - __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), - NamedLoadHandlerCompiler::kInterceptorArgsLength); -} - - // Generate call to api function. // This function uses push() to generate smaller, faster code than // the version above. It is an optimization that should will be removed @@ -307,7 +175,7 @@ __ push(receiver); // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - Register arg = values[argc-1-i]; + Register arg = values[argc - 1 - i]; DCHECK(!receiver.is(arg)); DCHECK(!scratch_in.is(arg)); __ push(arg); @@ -325,16 +193,15 @@ // Put holder in place. CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( - receiver_map, - &holder_lookup); + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); switch (holder_lookup) { case CallOptimization::kHolderIsReceiver: __ Move(holder, receiver); break; case CallOptimization::kHolderFound: __ LoadHeapObject(holder, api_holder); - break; + break; case CallOptimization::kHolderNotFound: UNREACHABLE(); break; @@ -376,8 +243,7 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, Register scratch, Label* miss) { - Handle<PropertyCell> cell = - JSGlobalObject::EnsurePropertyCell(global, name); + Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); DCHECK(cell->value()->IsTheHole()); Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); if (masm->serializer_enabled()) { @@ -391,9 +257,107 @@ } -void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, - Handle<Code> code) { - __ jmp(code, RelocInfo::CODE_TARGET); +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- esp[0] : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ mov(receiver, + FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ push(receiver); + __ push(value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ pop(eax); + + // Restore context register. + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + } + __ ret(0); +} + + +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, + Handle<JSObject> holder_obj) { + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); + __ push(name); + Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); + DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); + Register scratch = name; + __ mov(scratch, Immediate(interceptor)); + __ push(scratch); + __ push(receiver); + __ push(holder); +} + + +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), + NamedLoadHandlerCompiler::kInterceptorArgsLength); +} + + +static void StoreIC_PushArgs(MacroAssembler* masm) { + Register receiver = StoreIC::ReceiverRegister(); + Register name = StoreIC::NameRegister(); + Register value = StoreIC::ValueRegister(); + + DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value)); + + __ pop(ebx); + __ push(receiver); + __ push(name); + __ push(value); + __ push(ebx); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Return address is on the stack. + StoreIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + // Return address is on the stack. + StoreIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); } @@ -427,7 +391,7 @@ __ CmpObject(value_reg, constant); __ j(not_equal, miss_label); } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); + __ JumpIfNotSmi(value_reg, miss_label); } else if (representation.IsHeapObject()) { __ JumpIfSmi(value_reg, miss_label); HeapType* field_type = descriptors->GetFieldType(descriptor); @@ -451,19 +415,17 @@ __ JumpIfNotSmi(value_reg, &heap_number); __ SmiUntag(value_reg); - __ push(value_reg); - __ fild_s(Operand(esp, 0)); - __ pop(value_reg); + __ Cvtsi2sd(xmm0, value_reg); __ SmiTag(value_reg); __ jmp(&do_store); __ bind(&heap_number); __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, DONT_DO_SMI_CHECK); - __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset)); + __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); __ bind(&do_store); - __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset)); + __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); } // Stub never generated for objects that require access checks. @@ -491,12 +453,8 @@ __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, - scratch2, - OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); if (details.type() == CONSTANT) { DCHECK(value_reg.is(eax)); @@ -512,8 +470,8 @@ // object and the number of in-object properties is not going to change. index -= transition->inobject_properties(); - SmiCheck smi_check = representation.IsTagged() - ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; // TODO(verwaest): Share this code as a code stub. if (index < 0) { // Set the property straight into the object. @@ -529,12 +487,8 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(receiver_reg, - offset, - storage_reg, - scratch1, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); } } else { // Write to the properties array. @@ -552,12 +506,8 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(scratch1, - offset, - storage_reg, - receiver_reg, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); } } @@ -599,8 +549,8 @@ // Make sure there's no overlap between holder and object registers. DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) - && !scratch2.is(scratch1)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); // Keep track of the current object in register reg. Register reg = object_reg; @@ -632,10 +582,10 @@ } DCHECK(current.is_null() || current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); + NameDictionary::kNotFound); - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, - scratch1, scratch2); + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); reg = holder_reg; // From now on the object will be in holder_reg. @@ -660,9 +610,8 @@ if (current_map->IsJSGlobalProxyMap()) { __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell( - masm(), Handle<JSGlobalObject>::cast(current), name, - scratch2, miss); + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); } if (load_prototype_from_map) { @@ -885,55 +834,6 @@ } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - __ push(value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ pop(eax); - - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( Handle<Name> name) { __ pop(scratch1()); // remove the return address @@ -952,93 +852,9 @@ } -Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( - MapHandleList* receiver_maps, CodeHandleList* handler_stubs, - MapHandleList* transitioned_maps) { - Label miss; - __ JumpIfSmi(receiver(), &miss, Label::kNear); - __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); - for (int i = 0; i < receiver_maps->length(); ++i) { - __ cmp(scratch1(), receiver_maps->at(i)); - if (transitioned_maps->at(i).is_null()) { - __ j(equal, handler_stubs->at(i)); - } else { - Label next_map; - __ j(not_equal, &next_map, Label::kNear); - __ mov(transition_map(), Immediate(transitioned_maps->at(i))); - __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); - __ bind(&next_map); - } - } - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); -} - - -Register* PropertyAccessCompiler::load_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3, scratch4. - Register receiver = LoadIC::ReceiverRegister(); - Register name = LoadIC::NameRegister(); - static Register registers[] = { receiver, name, ebx, eax, edi, no_reg }; - return registers; -} - - -Register* PropertyAccessCompiler::store_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3. - Register receiver = StoreIC::ReceiverRegister(); - Register name = StoreIC::NameRegister(); - DCHECK(ebx.is(KeyedStoreIC::MapRegister())); - static Register registers[] = { receiver, name, ebx, edi, no_reg }; - return registers; -} - - Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { Label miss; @@ -1074,113 +890,8 @@ } -Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, - CodeHandleList* handlers, - Handle<Name> name, - Code::StubType type, - IcCheckType check) { - Label miss; - - if (check == PROPERTY && - (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { - // In case we are compiling an IC for dictionary loads and stores, just - // check whether the name is unique. - if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { - __ JumpIfNotUniqueName(this->name(), &miss); - } else { - __ cmp(this->name(), Immediate(name)); - __ j(not_equal, &miss); - } - } - - Label number_case; - Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; - __ JumpIfSmi(receiver(), smi_target); - - // Polymorphic keyed stores may use the map register - Register map_reg = scratch1(); - DCHECK(kind() != Code::KEYED_STORE_IC || - map_reg.is(KeyedStoreIC::MapRegister())); - __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset)); - int receiver_count = types->length(); - int number_of_handled_maps = 0; - for (int current = 0; current < receiver_count; ++current) { - Handle<HeapType> type = types->at(current); - Handle<Map> map = IC::TypeToMap(*type, isolate()); - if (!map->is_deprecated()) { - number_of_handled_maps++; - __ cmp(map_reg, map); - if (type->Is(HeapType::Number())) { - DCHECK(!number_case.is_unused()); - __ bind(&number_case); - } - __ j(equal, handlers->at(current)); - } - } - DCHECK(number_of_handled_maps != 0); - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - InlineCacheState state = - number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; - return GetCode(kind(), type, name, state); -} - - #undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - DCHECK(edx.is(LoadIC::ReceiverRegister())); - DCHECK(ecx.is(LoadIC::NameRegister())); - Label slow, miss; - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - __ JumpIfNotSmi(ecx, &miss); - __ mov(ebx, ecx); - __ SmiUntag(ebx); - __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); - - // Push receiver on the stack to free up a register for the dictionary - // probing. - __ push(edx); - __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax); - // Pop receiver before returning. - __ pop(edx); - __ ret(0); - - __ bind(&slow); - __ pop(edx); - - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - __ bind(&miss); - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); } +} // namespace v8::internal - -#undef __ - -} } // namespace v8::internal - -#endif // V8_TARGET_ARCH_X87 +#endif // V8_TARGET_ARCH_IA32
diff --git a/src/ic/ia32/ic-compiler-ia32.cc b/src/ic/ia32/ic-compiler-ia32.cc index fb1542d..4fce7cc 100644 --- a/src/ic/ia32/ic-compiler-ia32.cc +++ b/src/ic/ia32/ic-compiler-ia32.cc
@@ -6,7 +6,6 @@ #if V8_TARGET_ARCH_IA32 -#include "src/ic/call-optimization.h" #include "src/ic/ic-compiler.h" namespace v8 { @@ -14,842 +13,27 @@ #define __ ACCESS_MASM(masm) -void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( - MacroAssembler* masm, Label* miss_label, Register receiver, - Handle<Name> name, Register scratch0, Register scratch1) { - DCHECK(name->IsUniqueName()); - DCHECK(!receiver.is(scratch0)); - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->negative_lookups(), 1); - __ IncrementCounter(counters->negative_lookups_miss(), 1); - __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + // Return address is on the stack. + DCHECK(!ebx.is(StoreIC::ReceiverRegister()) && + !ebx.is(StoreIC::NameRegister()) && !ebx.is(StoreIC::ValueRegister())); + __ pop(ebx); + __ push(StoreIC::ReceiverRegister()); + __ push(StoreIC::NameRegister()); + __ push(StoreIC::ValueRegister()); + __ push(Immediate(Smi::FromInt(strict_mode))); + __ push(ebx); // return address - const int kInterceptorOrAccessCheckNeededMask = - (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); - - // Bail out if the receiver has a named interceptor or requires access checks. - __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset), - kInterceptorOrAccessCheckNeededMask); - __ j(not_zero, miss_label); - - // Check that receiver is a JSObject. - __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE); - __ j(below, miss_label); - - // Load properties array. - Register properties = scratch0; - __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); - - // Check that the properties array is a dictionary. - __ cmp(FieldOperand(properties, HeapObject::kMapOffset), - Immediate(masm->isolate()->factory()->hash_table_map())); - __ j(not_equal, miss_label); - - Label done; - NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, - properties, name, scratch1); - __ bind(&done); - __ DecrementCounter(counters->negative_lookups_miss(), 1); -} - - -void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype, Label* miss) { - // Get the global function with the given index. - Handle<JSFunction> function( - JSFunction::cast(masm->isolate()->native_context()->get(index))); - // Check we're still in the same context. - Register scratch = prototype; - const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); - __ mov(scratch, Operand(esi, offset)); - __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset)); - __ cmp(Operand(scratch, Context::SlotOffset(index)), function); - __ j(not_equal, miss); - - // Load its initial map. The global functions all have initial maps. - __ Move(prototype, Immediate(Handle<Map>(function->initial_map()))); - // Load the prototype from the initial map. - __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); -} - - -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register scratch1, - Register scratch2, Label* miss_label) { - __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); - __ mov(eax, scratch1); - __ ret(0); -} - - -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); - __ push(name); - Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); - DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); - Register scratch = name; - __ mov(scratch, Immediate(interceptor)); - __ push(scratch); - __ push(receiver); - __ push(holder); -} - - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, IC::UtilityId id) { - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); - __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), - NamedLoadHandlerCompiler::kInterceptorArgsLength); -} - - -// Generate call to api function. -// This function uses push() to generate smaller, faster code than -// the version above. It is an optimization that should will be removed -// when api call ICs are generated in hydrogen. -void PropertyHandlerCompiler::GenerateFastApiCall( - MacroAssembler* masm, const CallOptimization& optimization, - Handle<Map> receiver_map, Register receiver, Register scratch_in, - bool is_store, int argc, Register* values) { - // Copy return value. - __ pop(scratch_in); - // receiver - __ push(receiver); - // Write the arguments to stack frame. - for (int i = 0; i < argc; i++) { - Register arg = values[argc - 1 - i]; - DCHECK(!receiver.is(arg)); - DCHECK(!scratch_in.is(arg)); - __ push(arg); - } - __ push(scratch_in); - // Stack now matches JSFunction abi. - DCHECK(optimization.is_simple_api_call()); - - // Abi for CallApiFunctionStub. - Register callee = eax; - Register call_data = ebx; - Register holder = ecx; - Register api_function_address = edx; - Register scratch = edi; // scratch_in is no longer valid. - - // Put holder in place. - CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = - optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); - switch (holder_lookup) { - case CallOptimization::kHolderIsReceiver: - __ Move(holder, receiver); - break; - case CallOptimization::kHolderFound: - __ LoadHeapObject(holder, api_holder); - break; - case CallOptimization::kHolderNotFound: - UNREACHABLE(); - break; - } - - Isolate* isolate = masm->isolate(); - Handle<JSFunction> function = optimization.constant_function(); - Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); - Handle<Object> call_data_obj(api_call_info->data(), isolate); - - // Put callee in place. - __ LoadHeapObject(callee, function); - - bool call_data_undefined = false; - // Put call_data in place. - if (isolate->heap()->InNewSpace(*call_data_obj)) { - __ mov(scratch, api_call_info); - __ mov(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset)); - } else if (call_data_obj->IsUndefined()) { - call_data_undefined = true; - __ mov(call_data, Immediate(isolate->factory()->undefined_value())); - } else { - __ mov(call_data, call_data_obj); - } - - // Put api_function_address in place. - Address function_address = v8::ToCData<Address>(api_call_info->callback()); - __ mov(api_function_address, Immediate(function_address)); - - // Jump to stub. - CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); - __ TailCallStub(&stub); -} - - -// Generate code to check that a global property cell is empty. Create -// the property cell at compilation time if no cell exists for the -// property. -void PropertyHandlerCompiler::GenerateCheckPropertyCell( - MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, - Register scratch, Label* miss) { - Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); - DCHECK(cell->value()->IsTheHole()); - Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); - if (masm->serializer_enabled()) { - __ mov(scratch, Immediate(cell)); - __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset), - Immediate(the_hole)); - } else { - __ cmp(Operand::ForCell(cell), Immediate(the_hole)); - } - __ j(not_equal, miss); + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); } #undef __ #define __ ACCESS_MASM(masm()) - -void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, - Handle<Name> name) { - if (!label->is_unused()) { - __ bind(label); - __ mov(this->name(), Immediate(name)); - } -} - - -// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if -// store is successful. -void NamedStoreHandlerCompiler::GenerateStoreTransition( - Handle<Map> transition, Handle<Name> name, Register receiver_reg, - Register storage_reg, Register value_reg, Register scratch1, - Register scratch2, Register unused, Label* miss_label, Label* slow) { - int descriptor = transition->LastAdded(); - DescriptorArray* descriptors = transition->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - Representation representation = details.representation(); - DCHECK(!representation.IsNone()); - - if (details.type() == CONSTANT) { - Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); - __ CmpObject(value_reg, constant); - __ j(not_equal, miss_label); - } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); - } else if (representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_label); - HeapType* field_type = descriptors->GetFieldType(descriptor); - HeapType::Iterator<Map> it = field_type->Classes(); - if (!it.Done()) { - Label do_store; - while (true) { - __ CompareMap(value_reg, it.Current()); - it.Advance(); - if (it.Done()) { - __ j(not_equal, miss_label); - break; - } - __ j(equal, &do_store, Label::kNear); - } - __ bind(&do_store); - } - } else if (representation.IsDouble()) { - Label do_store, heap_number; - __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE); - - __ JumpIfNotSmi(value_reg, &heap_number); - __ SmiUntag(value_reg); - __ Cvtsi2sd(xmm0, value_reg); - __ SmiTag(value_reg); - __ jmp(&do_store); - - __ bind(&heap_number); - __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, - DONT_DO_SMI_CHECK); - __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); - - __ bind(&do_store); - __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); - } - - // Stub never generated for objects that require access checks. - DCHECK(!transition->is_access_check_needed()); - - // Perform map transition for the receiver if necessary. - if (details.type() == FIELD && - Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { - // The properties must be extended before we can store the value. - // We jump to a runtime call that extends the properties array. - __ pop(scratch1); // Return address. - __ push(receiver_reg); - __ push(Immediate(transition)); - __ push(value_reg); - __ push(scratch1); - __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); - return; - } - - // Update the map of the object. - __ mov(scratch1, Immediate(transition)); - __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); - - // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, - kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - - if (details.type() == CONSTANT) { - DCHECK(value_reg.is(eax)); - __ ret(0); - return; - } - - int index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); - - // Adjust for the number of properties stored in the object. Even in the - // face of a transition we can use the old map here because the size of the - // object and the number of in-object properties is not going to change. - index -= transition->inobject_properties(); - - SmiCheck smi_check = - representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; - // TODO(verwaest): Share this code as a code stub. - if (index < 0) { - // Set the property straight into the object. - int offset = transition->instance_size() + (index * kPointerSize); - if (representation.IsDouble()) { - __ mov(FieldOperand(receiver_reg, offset), storage_reg); - } else { - __ mov(FieldOperand(receiver_reg, offset), value_reg); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ mov(storage_reg, value_reg); - } - __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, - kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); - } - } else { - // Write to the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - // Get the properties array (optimistically). - __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); - if (representation.IsDouble()) { - __ mov(FieldOperand(scratch1, offset), storage_reg); - } else { - __ mov(FieldOperand(scratch1, offset), value_reg); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ mov(storage_reg, value_reg); - } - __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, - kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); - } - } - - // Return the value (register eax). - DCHECK(value_reg.is(eax)); - __ ret(0); -} - - -void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, - Register value_reg, - Label* miss_label) { - DCHECK(lookup->representation().IsHeapObject()); - __ JumpIfSmi(value_reg, miss_label); - HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); - Label do_store; - while (true) { - __ CompareMap(value_reg, it.Current()); - it.Advance(); - if (it.Done()) { - __ j(not_equal, miss_label); - break; - } - __ j(equal, &do_store, Label::kNear); - } - __ bind(&do_store); - - StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), - lookup->representation()); - GenerateTailCall(masm(), stub.GetCode()); -} - - -Register PropertyHandlerCompiler::CheckPrototypes( - Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - PrototypeCheckType check) { - Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); - - // Make sure there's no overlap between holder and object registers. - DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && - !scratch2.is(scratch1)); - - // Keep track of the current object in register reg. - Register reg = object_reg; - int depth = 0; - - Handle<JSObject> current = Handle<JSObject>::null(); - if (type()->IsConstant()) - current = Handle<JSObject>::cast(type()->AsConstant()->Value()); - Handle<JSObject> prototype = Handle<JSObject>::null(); - Handle<Map> current_map = receiver_map; - Handle<Map> holder_map(holder()->map()); - // Traverse the prototype chain and check the maps in the prototype chain for - // fast and global objects or do negative lookup for normal objects. - while (!current_map.is_identical_to(holder_map)) { - ++depth; - - // Only global objects and objects that do not require access - // checks are allowed in stubs. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - - prototype = handle(JSObject::cast(current_map->prototype())); - if (current_map->is_dictionary_map() && - !current_map->IsJSGlobalObjectMap()) { - DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. - if (!name->IsUniqueName()) { - DCHECK(name->IsString()); - name = factory()->InternalizeString(Handle<String>::cast(name)); - } - DCHECK(current.is_null() || - current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); - - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, - scratch2); - - __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - } else { - bool in_new_space = heap()->InNewSpace(*prototype); - // Two possible reasons for loading the prototype from the map: - // (1) Can't store references to new space in code. - // (2) Handler is shared for all receivers with the same prototype - // map (but not necessarily the same prototype instance). - bool load_prototype_from_map = in_new_space || depth == 1; - if (depth != 1 || check == CHECK_ALL_MAPS) { - __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Check access rights to the global object. This has to happen after - // the map check so that we know that the object is actually a global - // object. - // This allows us to install generated handlers for accesses to the - // global proxy (as opposed to using slow ICs). See corresponding code - // in LookupForRead(). - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); - } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), - name, scratch2, miss); - } - - if (load_prototype_from_map) { - // Save the map in scratch1 for later. - __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - } - - reg = holder_reg; // From now on the object will be in holder_reg. - - if (load_prototype_from_map) { - __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - } else { - __ mov(reg, prototype); - } - } - - // Go to the next object in the prototype chain. - current = prototype; - current_map = handle(current->map()); - } - - // Log the check depth. - LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - - if (depth != 0 || check == CHECK_ALL_MAPS) { - // Check the holder map. - __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Perform security check for access to the global object. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); - } - - // Return the register containing the holder. - return reg; -} - - -void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ jmp(&success); - __ bind(miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ jmp(&success); - GenerateRestoreName(miss, name); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle<ExecutableAccessorInfo> callback) { - // Insert additional parameters into the stack frame above return address. - DCHECK(!scratch3().is(reg)); - __ pop(scratch3()); // Get return address to place it below. - - STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); - STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); - STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); - STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); - __ push(receiver()); // receiver - // Push data from ExecutableAccessorInfo. - if (isolate()->heap()->InNewSpace(callback->data())) { - DCHECK(!scratch2().is(reg)); - __ mov(scratch2(), Immediate(callback)); - __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset)); - } else { - __ push(Immediate(Handle<Object>(callback->data(), isolate()))); - } - __ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue - // ReturnValue default value - __ push(Immediate(isolate()->factory()->undefined_value())); - __ push(Immediate(reinterpret_cast<int>(isolate()))); - __ push(reg); // holder - - // Save a pointer to where we pushed the arguments. This will be - // passed as the const PropertyAccessorInfo& to the C++ callback. - __ push(esp); - - __ push(name()); // name - - __ push(scratch3()); // Restore return address. - - // Abi for CallApiGetter - Register getter_address = edx; - Address function_address = v8::ToCData<Address>(callback->getter()); - __ mov(getter_address, Immediate(function_address)); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - - -void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { - // Return the constant value. - __ LoadObject(eax, value); - __ ret(0); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); - - // 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->property_kind() == 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()); - - // 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(), - IC::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(BitCast<int32_t>(kZapValue))); - __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue))); - __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue))); - } - - __ 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()); - // Call the runtime system to load the interceptor. - __ pop(scratch2()); // save old return address - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - __ push(scratch2()); // restore old return address - - ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); - __ TailCallExternalReference( - ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( - Handle<JSObject> object, Handle<Name> name, - Handle<ExecutableAccessorInfo> callback) { - Register holder_reg = Frontend(receiver(), name); - - __ pop(scratch1()); // remove the return address - __ push(receiver()); - __ push(holder_reg); - __ Push(callback); - __ Push(name); - __ push(value()); - __ push(scratch1()); // restore return address - - // Do tail-call to the runtime system. - ExternalReference store_callback_property = - ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); - __ TailCallExternalReference(store_callback_property, 5, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - __ push(value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ pop(eax); - - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( - Handle<Name> name) { - __ pop(scratch1()); // remove the return address - __ push(receiver()); - __ push(this->name()); - __ push(value()); - __ push(scratch1()); // restore return address - - // Do tail-call to the runtime system. - ExternalReference store_ic_property = ExternalReference( - IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); - __ TailCallExternalReference(store_ic_property, 3, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( - MapHandleList* receiver_maps, CodeHandleList* handler_stubs, - MapHandleList* transitioned_maps) { - Label miss; - __ JumpIfSmi(receiver(), &miss, Label::kNear); - __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); - for (int i = 0; i < receiver_maps->length(); ++i) { - __ cmp(scratch1(), receiver_maps->at(i)); - if (transitioned_maps->at(i).is_null()) { - __ j(equal, handler_stubs->at(i)); - } else { - Label next_map; - __ j(not_equal, &next_map, Label::kNear); - __ mov(transition_map(), Immediate(transitioned_maps->at(i))); - __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); - __ bind(&next_map); - } - } - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); -} - - -Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ mov(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - - FrontendHeader(receiver(), name, &miss); - // Get the value from the cell. - Register result = StoreIC::ValueRegister(); - if (masm()->serializer_enabled()) { - __ mov(result, Immediate(cell)); - __ mov(result, FieldOperand(result, PropertyCell::kValueOffset)); - } else { - __ mov(result, Operand::ForCell(cell)); - } - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ cmp(result, factory()->the_hole_value()); - __ j(equal, &miss); - } else if (FLAG_debug_code) { - __ cmp(result, factory()->the_hole_value()); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->named_load_global_stub(), 1); - // The code above already loads the result into the return register. - __ ret(0); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, name); -} - - Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, CodeHandleList* handlers, Handle<Name> name, @@ -905,70 +89,29 @@ } -#undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - DCHECK(edx.is(LoadIC::ReceiverRegister())); - DCHECK(ecx.is(LoadIC::NameRegister())); - Label slow, miss; - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - __ JumpIfNotSmi(ecx, &miss); - __ mov(ebx, ecx); - __ SmiUntag(ebx); - __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset)); - - // Push receiver on the stack to free up a register for the dictionary - // probing. - __ push(edx); - __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax); - // Pop receiver before returning. - __ pop(edx); - __ ret(0); - - __ bind(&slow); - __ pop(edx); - - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - +Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( + MapHandleList* receiver_maps, CodeHandleList* handler_stubs, + MapHandleList* transitioned_maps) { + Label miss; + __ JumpIfSmi(receiver(), &miss, Label::kNear); + __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset)); + for (int i = 0; i < receiver_maps->length(); ++i) { + __ cmp(scratch1(), receiver_maps->at(i)); + if (transitioned_maps->at(i).is_null()) { + __ j(equal, handler_stubs->at(i)); + } else { + Label next_map; + __ j(not_equal, &next_map, Label::kNear); + __ mov(transition_map(), Immediate(transitioned_maps->at(i))); + __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET); + __ bind(&next_map); + } + } __ bind(&miss); - // ----------- S t a t e ------------- - // -- ecx : key - // -- edx : receiver - // -- esp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); -} + TailCallBuiltin(masm(), MissBuiltin(kind())); - -void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Return address is on the stack. - DCHECK(!ebx.is(StoreIC::ReceiverRegister()) && - !ebx.is(StoreIC::NameRegister()) && !ebx.is(StoreIC::ValueRegister())); - __ pop(ebx); - __ push(StoreIC::ReceiverRegister()); - __ push(StoreIC::NameRegister()); - __ push(StoreIC::ValueRegister()); - __ push(Immediate(Smi::FromInt(strict_mode))); - __ push(ebx); // return address - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); + // Return the generated code. + return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); }
diff --git a/src/ic/ia32/ic-ia32.cc b/src/ic/ia32/ic-ia32.cc index 4dd1a93..5f13078 100644 --- a/src/ic/ia32/ic-ia32.cc +++ b/src/ic/ia32/ic-ia32.cc
@@ -1018,26 +1018,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - #undef __
diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc index f555517..8b0b62a 100644 --- a/src/ic/ic-compiler.cc +++ b/src/ic/ic-compiler.cc
@@ -4,7 +4,7 @@ #include "src/v8.h" -#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" #include "src/ic/ic-inl.h" #include "src/ic/ic-compiler.h" @@ -25,15 +25,24 @@ } -Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name, - Handle<Map> stub_holder, - Code::Kind kind, - CacheHolderFlag cache_holder, - Code::StubType type) { - Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); - Object* probe = stub_holder->FindInCodeCache(*name, flags); - if (probe->IsCode()) return handle(Code::cast(probe)); - return Handle<Code>::null(); +bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { + for (int i = 0; i < types->length(); ++i) { + if (types->at(i)->Is(HeapType::Number())) return true; + } + return false; +} + + +Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, + Handle<Code> handler, + Handle<Name> name, + IcCheckType check) { + TypeHandleList types(1); + CodeHandleList handlers(1); + types.Add(type); + handlers.Add(handler); + Code::StubType stub_type = handler->type(); + return CompilePolymorphic(&types, &handlers, name, stub_type, check); } @@ -74,50 +83,6 @@ } -Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent( - Handle<Name> name, Handle<HeapType> type) { - Isolate* isolate = name->GetIsolate(); - Handle<Map> receiver_map = IC::TypeToMap(*type, isolate); - if (receiver_map->prototype()->IsNull()) { - // TODO(jkummerow/verwaest): If there is no prototype and the property - // is nonexistent, introduce a builtin to handle this (fast properties - // -> return undefined, dictionary properties -> do negative lookup). - return Handle<Code>(); - } - CacheHolderFlag flag; - Handle<Map> stub_holder_map = - IC::GetHandlerCacheHolder(*type, false, isolate, &flag); - - // If no dictionary mode 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 there are dictionary - // mode objects involved, we need to do negative lookups in the stub and - // therefore the stub will be specific to the name. - Handle<Name> cache_name = - receiver_map->is_dictionary_map() - ? name - : Handle<Name>::cast(isolate->factory()->nonexistent_symbol()); - Handle<Map> current_map = stub_holder_map; - Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); - while (true) { - if (current_map->is_dictionary_map()) cache_name = name; - if (current_map->prototype()->IsNull()) break; - last = handle(JSObject::cast(current_map->prototype())); - current_map = handle(last->map()); - } - // Compile the stub that is either shared for all names or - // name specific if there are global objects involved. - Handle<Code> handler = PropertyHandlerCompiler::Find( - cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); - if (!handler.is_null()) return handler; - - NamedLoadHandlerCompiler compiler(isolate, type, last, flag); - handler = compiler.CompileLoadNonexistent(cache_name); - Map::UpdateCodeCache(stub_holder_map, cache_name, handler); - return handler; -} - - Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic( Handle<Map> receiver_map) { Isolate* isolate = receiver_map->GetIsolate(); @@ -400,330 +365,6 @@ } -#define __ ACCESS_MASM(masm()) - - -Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg, - Handle<Name> name, - Label* miss) { - PrototypeCheckType check_type = CHECK_ALL_MAPS; - int function_index = -1; - if (type()->Is(HeapType::String())) { - function_index = Context::STRING_FUNCTION_INDEX; - } else if (type()->Is(HeapType::Symbol())) { - function_index = Context::SYMBOL_FUNCTION_INDEX; - } else if (type()->Is(HeapType::Number())) { - function_index = Context::NUMBER_FUNCTION_INDEX; - } else if (type()->Is(HeapType::Boolean())) { - function_index = Context::BOOLEAN_FUNCTION_INDEX; - } else { - check_type = SKIP_RECEIVER; - } - - if (check_type == CHECK_ALL_MAPS) { - GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index, - scratch1(), miss); - Object* function = isolate()->native_context()->get(function_index); - Object* prototype = JSFunction::cast(function)->instance_prototype(); - set_type_for_object(handle(prototype, isolate())); - object_reg = scratch1(); - } - - // Check that the maps starting from the prototype haven't changed. - return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name, - miss, check_type); -} - - -// Frontend for store uses the name register. It has to be restored before a -// miss. -Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg, - Handle<Name> name, - Label* miss) { - return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, - miss, SKIP_RECEIVER); -} - - -bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) { - for (int i = 0; i < types->length(); ++i) { - if (types->at(i)->Is(HeapType::Number())) return true; - } - return false; -} - - -Register PropertyHandlerCompiler::Frontend(Register object_reg, - Handle<Name> name) { - Label miss; - Register reg = FrontendHeader(object_reg, name, &miss); - FrontendFooter(name, &miss); - return reg; -} - - -void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, - Label* miss, - Register scratch1, - Register scratch2) { - Register holder_reg; - Handle<Map> last_map; - if (holder().is_null()) { - holder_reg = receiver(); - last_map = IC::TypeToMap(*type(), isolate()); - // If |type| has null as its prototype, |holder()| is - // Handle<JSObject>::null(). - DCHECK(last_map->prototype() == isolate()->heap()->null_value()); - } else { - holder_reg = FrontendHeader(receiver(), name, miss); - last_map = handle(holder()->map()); - } - - if (last_map->is_dictionary_map()) { - if (last_map->IsJSGlobalObjectMap()) { - Handle<JSGlobalObject> global = - holder().is_null() - ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value()) - : Handle<JSGlobalObject>::cast(holder()); - GenerateCheckPropertyCell(masm(), global, name, scratch1, miss); - } else { - if (!name->IsUniqueName()) { - DCHECK(name->IsString()); - name = factory()->InternalizeString(Handle<String>::cast(name)); - } - DCHECK(holder().is_null() || - holder()->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); - GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1, - scratch2); - } - } -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name, - FieldIndex field) { - Register reg = Frontend(receiver(), name); - __ Move(receiver(), reg); - LoadFieldStub stub(isolate(), field); - GenerateTailCall(masm(), stub.GetCode()); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name, - int constant_index) { - Register reg = Frontend(receiver(), name); - __ Move(receiver(), reg); - LoadConstantStub stub(isolate(), constant_index); - GenerateTailCall(masm(), stub.GetCode()); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( - Handle<Name> name) { - Label miss; - NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); - GenerateLoadConstant(isolate()->factory()->undefined_value()); - FrontendFooter(name, &miss); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( - Handle<Name> name, Handle<ExecutableAccessorInfo> callback) { - Register reg = Frontend(receiver(), name); - GenerateLoadCallback(reg, callback); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( - Handle<Name> name, const CallOptimization& call_optimization) { - DCHECK(call_optimization.is_simple_api_call()); - Frontend(receiver(), name); - Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate()); - GenerateFastApiCall(masm(), call_optimization, receiver_map, receiver(), - scratch1(), false, 0, NULL); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor( - LookupIterator* it) { - // So far the most popular follow ups for interceptor loads are FIELD and - // ExecutableAccessorInfo, so inline only them. Other cases may be added - // later. - bool inline_followup = it->state() == LookupIterator::PROPERTY; - if (inline_followup) { - switch (it->property_kind()) { - case LookupIterator::DATA: - inline_followup = it->property_details().type() == FIELD; - break; - case LookupIterator::ACCESSOR: { - Handle<Object> accessors = it->GetAccessors(); - inline_followup = accessors->IsExecutableAccessorInfo(); - if (!inline_followup) break; - Handle<ExecutableAccessorInfo> info = - Handle<ExecutableAccessorInfo>::cast(accessors); - inline_followup = info->getter() != NULL && - ExecutableAccessorInfo::IsCompatibleReceiverType( - isolate(), info, type()); - } - } - } - - Register reg = Frontend(receiver(), it->name()); - 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(), Code::FAST, it->name()); -} - - -void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor( - LookupIterator* it, Register interceptor_reg) { - Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>()); - - set_type_for_object(holder()); - set_holder(real_named_property_holder); - Register reg = Frontend(interceptor_reg, it->name()); - - switch (it->property_kind()) { - case LookupIterator::DATA: { - DCHECK_EQ(FIELD, it->property_details().type()); - __ Move(receiver(), reg); - LoadFieldStub stub(isolate(), it->GetFieldIndex()); - GenerateTailCall(masm(), stub.GetCode()); - break; - } - case LookupIterator::ACCESSOR: - Handle<ExecutableAccessorInfo> info = - Handle<ExecutableAccessorInfo>::cast(it->GetAccessors()); - DCHECK_NE(NULL, info->getter()); - GenerateLoadCallback(reg, info); - } -} - - -Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type, - Handle<Code> handler, - Handle<Name> name, - IcCheckType check) { - TypeHandleList types(1); - CodeHandleList handlers(1); - types.Add(type); - handlers.Add(handler); - Code::StubType stub_type = handler->type(); - return CompilePolymorphic(&types, &handlers, name, stub_type, check); -} - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter( - Handle<Name> name, Handle<JSFunction> getter) { - Frontend(receiver(), name); - GenerateLoadViaGetter(masm(), type(), receiver(), getter); - return GetCode(kind(), Code::FAST, name); -} - - -// TODO(verwaest): Cleanup. holder() is actually the receiver. -Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( - Handle<Map> transition, Handle<Name> name) { - Label miss, slow; - - // Ensure no transitions to deprecated maps are followed. - __ CheckMapDeprecated(transition, scratch1(), &miss); - - // Check that we are allowed to write this. - bool is_nonexistent = holder()->map() == transition->GetBackPointer(); - if (is_nonexistent) { - // Find the top object. - Handle<JSObject> last; - PrototypeIterator iter(isolate(), holder()); - while (!iter.IsAtEnd()) { - last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); - iter.Advance(); - } - if (!last.is_null()) set_holder(last); - NonexistentFrontendHeader(name, &miss, scratch1(), scratch2()); - } else { - FrontendHeader(receiver(), name, &miss); - DCHECK(holder()->HasFastProperties()); - } - - GenerateStoreTransition(transition, name, receiver(), this->name(), value(), - scratch1(), scratch2(), scratch3(), &miss, &slow); - - GenerateRestoreName(&miss, name); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - GenerateRestoreName(&slow, name); - TailCallBuiltin(masm(), SlowBuiltin(kind())); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { - Label miss; - GenerateStoreField(it, value(), &miss); - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - return GetCode(kind(), Code::FAST, it->name()); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter( - Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) { - Frontend(receiver(), name); - GenerateStoreViaSetter(masm(), type(), receiver(), setter); - - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( - Handle<JSObject> object, Handle<Name> name, - const CallOptimization& call_optimization) { - Frontend(receiver(), name); - Register values[] = {value()}; - GenerateFastApiCall(masm(), call_optimization, handle(object->map()), - receiver(), scratch1(), true, 1, values); - return GetCode(kind(), Code::FAST, name); -} - - -Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( - Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { - ElementsKind elements_kind = receiver_map->elements_kind(); - bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; - Handle<Code> stub; - if (receiver_map->has_fast_elements() || - receiver_map->has_external_array_elements() || - receiver_map->has_fixed_typed_array_elements()) { - stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, - store_mode).GetCode(); - } else { - stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) - .GetCode(); - } - - __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); - - TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); - - return GetCode(kind(), Code::NORMAL, factory()->empty_string()); -} - - -#undef __ - - Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name, InlineCacheState state) { @@ -736,48 +377,6 @@ } -Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind, - Code::StubType type, - Handle<Name> name) { - Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder()); - Handle<Code> code = GetCodeWithFlags(flags, name); - PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name)); - return code; -} - - -void ElementHandlerCompiler::CompileElementHandlers( - MapHandleList* receiver_maps, CodeHandleList* handlers) { - for (int i = 0; i < receiver_maps->length(); ++i) { - Handle<Map> receiver_map = receiver_maps->at(i); - Handle<Code> cached_stub; - - if ((receiver_map->instance_type() & kNotStringTag) == 0) { - cached_stub = isolate()->builtins()->KeyedLoadIC_String(); - } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { - cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); - } else { - bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; - ElementsKind elements_kind = receiver_map->elements_kind(); - - if (IsFastElementsKind(elements_kind) || - IsExternalArrayElementsKind(elements_kind) || - IsFixedTypedArrayElementsKind(elements_kind)) { - cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind) - .GetCode(); - } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { - cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments(); - } else { - DCHECK(elements_kind == DICTIONARY_ELEMENTS); - cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); - } - } - - handlers->Add(cached_stub); - } -} - - Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) { // Collect MONOMORPHIC stubs for all |receiver_maps|. @@ -827,11 +426,32 @@ } -void ElementHandlerCompiler::GenerateStoreDictionaryElement( - MacroAssembler* masm) { - KeyedStoreIC::GenerateSlow(masm); +#define __ ACCESS_MASM(masm()) + + +Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic( + Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { + ElementsKind elements_kind = receiver_map->elements_kind(); + bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; + Handle<Code> stub; + if (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements() || + receiver_map->has_fixed_typed_array_elements()) { + stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, + store_mode).GetCode(); + } else { + stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode) + .GetCode(); + } + + __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); + + TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss); + + return GetCode(kind(), Code::NORMAL, factory()->empty_string()); } +#undef __ } } // namespace v8::internal
diff --git a/src/ic/ic-compiler.h b/src/ic/ic-compiler.h index 15e00d2..8ee0c38 100644 --- a/src/ic/ic-compiler.h +++ b/src/ic/ic-compiler.h
@@ -5,19 +5,12 @@ #ifndef V8_IC_IC_COMPILER_H_ #define V8_IC_IC_COMPILER_H_ -#include "src/code-stubs.h" #include "src/ic/access-compiler.h" -#include "src/macro-assembler.h" -#include "src/objects.h" namespace v8 { namespace internal { -class CallOptimization; - - -enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER }; enum IcCheckType { ELEMENT, PROPERTY }; @@ -127,263 +120,6 @@ }; -class PropertyHandlerCompiler : public PropertyAccessCompiler { - public: - static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind, - CacheHolderFlag cache_holder, Code::StubType type); - - protected: - PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, - Handle<HeapType> type, Handle<JSObject> holder, - CacheHolderFlag cache_holder) - : PropertyAccessCompiler(isolate, kind, cache_holder), - type_(type), - holder_(holder) {} - - virtual ~PropertyHandlerCompiler() {} - - virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss) { - UNREACHABLE(); - return receiver(); - } - - virtual void FrontendFooter(Handle<Name> name, Label* miss) { UNREACHABLE(); } - - Register Frontend(Register object_reg, Handle<Name> name); - void NonexistentFrontendHeader(Handle<Name> name, Label* miss, - Register scratch1, Register scratch2); - - // TODO(verwaest): Make non-static. - static void GenerateFastApiCall(MacroAssembler* masm, - const CallOptimization& optimization, - Handle<Map> receiver_map, Register receiver, - Register scratch, bool is_store, int argc, - Register* values); - - // Helper function used to check that the dictionary doesn't contain - // the property. This function may return false negatives, so miss_label - // must always call a backup property check that is complete. - // This function is safe to call if the receiver has fast properties. - // Name must be unique and receiver must be a heap object. - static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, - Label* miss_label, - Register receiver, - Handle<Name> name, Register r0, - Register r1); - - // Generate code to check that a global property cell is empty. Create - // the property cell at compilation time if no cell exists for the - // property. - static void GenerateCheckPropertyCell(MacroAssembler* masm, - Handle<JSGlobalObject> global, - Handle<Name> name, Register scratch, - Label* miss); - - // Generates code that verifies that the property holder has not changed - // (checking maps of objects in the prototype chain for fast and global - // objects or doing negative lookup for slow objects, ensures that the - // property cells for global objects are still empty) and checks that the map - // of the holder has not changed. If necessary the function also generates - // code for security check in case of global object holders. Helps to make - // sure that the current IC is still valid. - // - // The scratch and holder registers are always clobbered, but the object - // register is only clobbered if it the same as the holder register. The - // function returns a register containing the holder - either object_reg or - // holder_reg. - Register CheckPrototypes(Register object_reg, Register holder_reg, - Register scratch1, Register scratch2, - Handle<Name> name, Label* miss, - PrototypeCheckType check = CHECK_ALL_MAPS); - - Handle<Code> GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name); - void set_type_for_object(Handle<Object> object) { - type_ = IC::CurrentTypeOf(object, isolate()); - } - void set_holder(Handle<JSObject> holder) { holder_ = holder; } - Handle<HeapType> type() const { return type_; } - Handle<JSObject> holder() const { return holder_; } - - private: - Handle<HeapType> type_; - Handle<JSObject> holder_; -}; - - -class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { - public: - NamedLoadHandlerCompiler(Isolate* isolate, Handle<HeapType> type, - Handle<JSObject> holder, - CacheHolderFlag cache_holder) - : PropertyHandlerCompiler(isolate, Code::LOAD_IC, type, holder, - cache_holder) {} - - virtual ~NamedLoadHandlerCompiler() {} - - Handle<Code> CompileLoadField(Handle<Name> name, FieldIndex index); - - Handle<Code> CompileLoadCallback(Handle<Name> name, - Handle<ExecutableAccessorInfo> callback); - - Handle<Code> CompileLoadCallback(Handle<Name> name, - const CallOptimization& call_optimization); - - Handle<Code> CompileLoadConstant(Handle<Name> name, int constant_index); - - // The LookupIterator is used to perform a lookup behind the interceptor. If - // the iterator points to a LookupIterator::PROPERTY, its access will be - // inlined. - Handle<Code> CompileLoadInterceptor(LookupIterator* it); - - Handle<Code> CompileLoadViaGetter(Handle<Name> name, - Handle<JSFunction> getter); - - Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name, - bool is_configurable); - - // Static interface - static Handle<Code> ComputeLoadNonexistent(Handle<Name> name, - Handle<HeapType> type); - - static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<HeapType> type, - Register receiver, - Handle<JSFunction> getter); - - static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) { - GenerateLoadViaGetter(masm, Handle<HeapType>::null(), no_reg, - Handle<JSFunction>()); - } - - static void GenerateLoadFunctionPrototype(MacroAssembler* masm, - Register receiver, - Register scratch1, - Register scratch2, - Label* miss_label); - - // These constants describe the structure of the interceptor arguments on the - // stack. The arguments are pushed by the (platform-specific) - // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and - // LoadWithInterceptor. - static const int kInterceptorArgsNameIndex = 0; - static const int kInterceptorArgsInfoIndex = 1; - static const int kInterceptorArgsThisIndex = 2; - static const int kInterceptorArgsHolderIndex = 3; - static const int kInterceptorArgsLength = 4; - - protected: - virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss); - - virtual void FrontendFooter(Handle<Name> name, Label* miss); - - private: - Handle<Code> CompileLoadNonexistent(Handle<Name> name); - void GenerateLoadConstant(Handle<Object> value); - void GenerateLoadCallback(Register reg, - Handle<ExecutableAccessorInfo> callback); - void GenerateLoadCallback(const CallOptimization& call_optimization, - Handle<Map> receiver_map); - void GenerateLoadInterceptor(Register holder_reg); - void GenerateLoadInterceptorWithFollowup(LookupIterator* it, - Register holder_reg); - void GenerateLoadPostInterceptor(LookupIterator* it, Register reg); - - // Generates prototype loading code that uses the objects from the - // context we were in when this function was called. If the context - // has changed, a jump to miss is performed. This ties the generated - // code to a particular context and so must not be used in cases - // where the generated code is not allowed to have references to - // objects from a context. - static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, - int index, - Register prototype, - Label* miss); - - - Register scratch4() { return registers_[5]; } -}; - - -class NamedStoreHandlerCompiler : public PropertyHandlerCompiler { - public: - explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<HeapType> type, - Handle<JSObject> holder) - : PropertyHandlerCompiler(isolate, Code::STORE_IC, type, holder, - kCacheOnReceiver) {} - - virtual ~NamedStoreHandlerCompiler() {} - - Handle<Code> CompileStoreTransition(Handle<Map> transition, - Handle<Name> name); - Handle<Code> CompileStoreField(LookupIterator* it); - Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, - Handle<ExecutableAccessorInfo> callback); - Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name, - const CallOptimization& call_optimization); - Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name, - Handle<JSFunction> setter); - Handle<Code> CompileStoreInterceptor(Handle<Name> name); - - static void GenerateStoreViaSetter(MacroAssembler* masm, - Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter); - - static void GenerateStoreViaSetterForDeopt(MacroAssembler* masm) { - GenerateStoreViaSetter(masm, Handle<HeapType>::null(), no_reg, - Handle<JSFunction>()); - } - - protected: - virtual Register FrontendHeader(Register object_reg, Handle<Name> name, - Label* miss); - - virtual void FrontendFooter(Handle<Name> name, Label* miss); - void GenerateRestoreName(Label* label, Handle<Name> name); - - private: - void GenerateStoreTransition(Handle<Map> transition, Handle<Name> name, - Register receiver_reg, Register name_reg, - Register value_reg, Register scratch1, - Register scratch2, Register scratch3, - Label* miss_label, Label* slow); - - void GenerateStoreField(LookupIterator* lookup, Register value_reg, - Label* miss_label); - - static Builtins::Name SlowBuiltin(Code::Kind kind) { - switch (kind) { - case Code::STORE_IC: - return Builtins::kStoreIC_Slow; - case Code::KEYED_STORE_IC: - return Builtins::kKeyedStoreIC_Slow; - default: - UNREACHABLE(); - } - return Builtins::kStoreIC_Slow; - } - - static Register value(); -}; - - -class ElementHandlerCompiler : public PropertyHandlerCompiler { - public: - explicit ElementHandlerCompiler(Isolate* isolate) - : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC, - Handle<HeapType>::null(), - Handle<JSObject>::null(), kCacheOnReceiver) {} - - virtual ~ElementHandlerCompiler() {} - - void CompileElementHandlers(MapHandleList* receiver_maps, - CodeHandleList* handlers); - - static void GenerateLoadDictionaryElement(MacroAssembler* masm); - static void GenerateStoreDictionaryElement(MacroAssembler* masm); -}; - - } } // namespace v8::internal
diff --git a/src/ic/ic.cc b/src/ic/ic.cc index 4c297ee..46bd435 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc
@@ -11,6 +11,7 @@ #include "src/conversions.h" #include "src/execution.h" #include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" #include "src/ic/ic-inl.h" #include "src/ic/ic-compiler.h" #include "src/ic/stub-cache.h" @@ -281,7 +282,7 @@ if (receiver->IsGlobalObject()) { Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); - LookupIterator it(global, name, LookupIterator::CHECK_PROPERTY); + LookupIterator it(global, name, LookupIterator::OWN_PROPERTY); if (!it.IsFound() || !it.HasProperty()) return false; Handle<PropertyCell> cell = it.GetPropertyCell(); return cell->type()->IsConstant(); @@ -970,7 +971,7 @@ 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); + LookupIterator it = *lookup; it.Next(); LookupForRead(&it); return compiler.CompileLoadInterceptor(&it);
diff --git a/src/ic/mips/OWNERS b/src/ic/mips/OWNERS new file mode 100644 index 0000000..5508ba6 --- /dev/null +++ b/src/ic/mips/OWNERS
@@ -0,0 +1,5 @@ +paul.lind@imgtec.com +gergely.kis@imgtec.com +akos.palfi@imgtec.com +balazs.kilvady@imgtec.com +dusan.milosavljevic@imgtec.com
diff --git a/src/ic/mips/access-compiler-mips.cc b/src/ic/mips/access-compiler-mips.cc new file mode 100644 index 0000000..7abf748 --- /dev/null +++ b/src/ic/mips/access-compiler-mips.cc
@@ -0,0 +1,46 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS + +#include "src/ic/access-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, + Handle<Code> code) { + __ Jump(code, RelocInfo::CODE_TARGET); +} + + +Register* PropertyAccessCompiler::load_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3, scratch4. + Register receiver = LoadIC::ReceiverRegister(); + Register name = LoadIC::NameRegister(); + static Register registers[] = {receiver, name, a3, a0, t0, t1}; + return registers; +} + + +Register* PropertyAccessCompiler::store_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3. + Register receiver = StoreIC::ReceiverRegister(); + Register name = StoreIC::NameRegister(); + DCHECK(a3.is(KeyedStoreIC::MapRegister())); + static Register registers[] = {receiver, name, a3, t0, t1}; + return registers; +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/stub-cache-mips.cc b/src/ic/mips/handler-compiler-mips.cc similarity index 66% rename from src/mips/stub-cache-mips.cc rename to src/ic/mips/handler-compiler-mips.cc index f8487d3..d533414 100644 --- a/src/mips/stub-cache-mips.cc +++ b/src/ic/mips/handler-compiler-mips.cc
@@ -1,4 +1,4 @@ -// Copyright 2012 the V8 project authors. All rights reserved. +// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,8 @@ #if V8_TARGET_ARCH_MIPS -#include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/stub-cache.h" +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" namespace v8 { namespace internal { @@ -16,81 +15,79 @@ #define __ ACCESS_MASM(masm) -static void ProbeTable(Isolate* isolate, - MacroAssembler* masm, - Code::Flags flags, - StubCache::Table table, - Register receiver, - Register name, - // Number of the cache entry, not scaled. - Register offset, - Register scratch, - Register scratch2, - Register offset_scratch) { - ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); - ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); - ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + // ----------- S t a t e ------------- + // -- a0 : receiver + // -- a2 : name + // -- ra : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); - uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); - uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address()); - uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address()); - - // Check the relative positions of the address fields. - DCHECK(value_off_addr > key_off_addr); - DCHECK((value_off_addr - key_off_addr) % 4 == 0); - DCHECK((value_off_addr - key_off_addr) < (256 * 4)); - DCHECK(map_off_addr > key_off_addr); - DCHECK((map_off_addr - key_off_addr) % 4 == 0); - DCHECK((map_off_addr - key_off_addr) < (256 * 4)); - - Label miss; - Register base_addr = scratch; - scratch = no_reg; - - // Multiply by 3 because there are 3 fields per entry (name, code, map). - __ sll(offset_scratch, offset, 1); - __ Addu(offset_scratch, offset_scratch, offset); - - // Calculate the base address of the entry. - __ li(base_addr, Operand(key_offset)); - __ sll(at, offset_scratch, kPointerSizeLog2); - __ Addu(base_addr, base_addr, at); - - // Check that the key in the entry matches the name. - __ lw(at, MemOperand(base_addr, 0)); - __ Branch(&miss, ne, name, Operand(at)); - - // Check the map matches. - __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr)); - __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ Branch(&miss, ne, at, Operand(scratch2)); - - // Get the code entry from the cache. - Register code = scratch2; - scratch2 = no_reg; - __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr)); - - // Check that the flags match what we're looking for. - Register flags_reg = base_addr; - base_addr = no_reg; - __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); - __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup)); - __ Branch(&miss, ne, flags_reg, Operand(flags)); - -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ lw(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); } -#endif - // Jump to the first instruction in the code stub. - __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ Jump(at); + // Restore context register. + __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} - // Miss: fall through. - __ bind(&miss); + +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- ra : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ lw(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver, value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ pop(v0); + + // Restore context register. + __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); } @@ -106,7 +103,7 @@ Label done; const int kInterceptorOrAccessCheckNeededMask = - (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); + (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); // Bail out if the receiver has a named interceptor or requires access checks. Register map = scratch1; @@ -132,110 +129,13 @@ __ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - NameDictionaryLookupStub::GenerateNegativeLookup(masm, - miss_label, - &done, - receiver, - properties, - name, - scratch1); + NameDictionaryLookupStub::GenerateNegativeLookup( + masm, miss_label, &done, receiver, properties, name, scratch1); __ bind(&done); __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void StubCache::GenerateProbe(MacroAssembler* masm, - Code::Flags flags, - Register receiver, - Register name, - Register scratch, - Register extra, - Register extra2, - Register extra3) { - Isolate* isolate = masm->isolate(); - Label miss; - - // Make sure that code is valid. The multiplying code relies on the - // entry size being 12. - DCHECK(sizeof(Entry) == 12); - - // Make sure the flags does not name a specific type. - DCHECK(Code::ExtractTypeFromFlags(flags) == 0); - - // Make sure that there are no register conflicts. - DCHECK(!scratch.is(receiver)); - DCHECK(!scratch.is(name)); - DCHECK(!extra.is(receiver)); - DCHECK(!extra.is(name)); - DCHECK(!extra.is(scratch)); - DCHECK(!extra2.is(receiver)); - DCHECK(!extra2.is(name)); - DCHECK(!extra2.is(scratch)); - DCHECK(!extra2.is(extra)); - - // Check register validity. - DCHECK(!scratch.is(no_reg)); - DCHECK(!extra.is(no_reg)); - DCHECK(!extra2.is(no_reg)); - DCHECK(!extra3.is(no_reg)); - - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, - extra2, extra3); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(receiver, &miss); - - // Get the map of the receiver and compute the hash. - __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); - __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ Addu(scratch, scratch, at); - uint32_t mask = kPrimaryTableSize - 1; - // We shift out the last two bits because they are not part of the hash and - // they are always 01 for maps. - __ srl(scratch, scratch, kCacheIndexShift); - __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask)); - __ And(scratch, scratch, Operand(mask)); - - // Probe the primary table. - ProbeTable(isolate, - masm, - flags, - kPrimary, - receiver, - name, - scratch, - extra, - extra2, - extra3); - - // Primary miss: Compute hash for secondary probe. - __ srl(at, name, kCacheIndexShift); - __ Subu(scratch, scratch, at); - uint32_t mask2 = kSecondaryTableSize - 1; - __ Addu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2)); - __ And(scratch, scratch, Operand(mask2)); - - // Probe the secondary table. - ProbeTable(isolate, - masm, - flags, - kSecondary, - receiver, - name, - scratch, - extra, - extra2, - extra3); - - // Cache miss: Fall-through and let caller handle the miss by - // entering the runtime system. - __ bind(&miss); - __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, - extra2, extra3); -} - - void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( MacroAssembler* masm, int index, Register prototype, Label* miss) { Isolate* isolate = masm->isolate(); @@ -268,6 +168,9 @@ } +// Generate code to check that a global property cell is empty. Create +// the property cell at compilation time if no cell exists for the +// property. void PropertyHandlerCompiler::GenerateCheckPropertyCell( MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, Register scratch, Label* miss) { @@ -280,10 +183,8 @@ } -static void PushInterceptorArguments(MacroAssembler* masm, - Register receiver, - Register holder, - Register name, +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); @@ -300,12 +201,8 @@ static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - Handle<JSObject> holder_obj, - IC::UtilityId id) { + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), NamedLoadHandlerCompiler::kInterceptorArgsLength); @@ -323,10 +220,10 @@ __ sw(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver. // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - Register arg = values[argc-1-i]; + Register arg = values[argc - 1 - i]; DCHECK(!receiver.is(arg)); DCHECK(!scratch_in.is(arg)); - __ sw(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg. + __ sw(arg, MemOperand(sp, (argc - 1 - i) * kPointerSize)); // Push arg. } DCHECK(optimization.is_simple_api_call()); @@ -338,16 +235,15 @@ // Put holder in place. CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( - receiver_map, - &holder_lookup); + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); switch (holder_lookup) { case CallOptimization::kHolderIsReceiver: __ Move(holder, receiver); break; case CallOptimization::kHolderFound: __ li(holder, api_holder); - break; + break; case CallOptimization::kHolderNotFound: UNREACHABLE(); break; @@ -385,9 +281,58 @@ } -void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, - Handle<Code> code) { - __ Jump(code, RelocInfo::CODE_TARGET); +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // The return address is in ra. + Label slow, miss; + + Register key = LoadIC::NameRegister(); + Register receiver = LoadIC::ReceiverRegister(); + DCHECK(receiver.is(a1)); + DCHECK(key.is(a2)); + + __ UntagAndJumpIfNotSmi(t2, key, &miss); + __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); + __ LoadFromNumberDictionary(&slow, t0, key, v0, t2, a3, t1); + __ Ret(); + + // Slow case, key and receiver still unmodified. + __ bind(&slow); + __ IncrementCounter( + masm->isolate()->counters()->keyed_load_external_array_slow(), 1, a2, a3); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); + + // Miss case, call the runtime. + __ bind(&miss); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); } @@ -459,8 +404,8 @@ __ jmp(&do_store); __ bind(&heap_number); - __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, - miss_label, DONT_DO_SMI_CHECK); + __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, + DONT_DO_SMI_CHECK); __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); __ bind(&do_store); @@ -479,9 +424,9 @@ __ li(a2, Operand(transition)); __ Push(a2, a0); __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); + ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), + isolate()), + 3, 1); return; } @@ -490,13 +435,8 @@ __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, - scratch2, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - OMIT_REMEMBERED_SET, + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kRAHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); if (details.type() == CONSTANT) { @@ -515,8 +455,8 @@ index -= transition->inobject_properties(); // TODO(verwaest): Share this code as a code stub. - SmiCheck smi_check = representation.IsTagged() - ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; if (index < 0) { // Set the property straight into the object. int offset = transition->instance_size() + (index * kPointerSize); @@ -531,21 +471,15 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(receiver_reg, - offset, - storage_reg, - scratch1, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kRAHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); } } else { // Write to the properties array. int offset = index * kPointerSize + FixedArray::kHeaderSize; // Get the properties array - __ lw(scratch1, - FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ lw(scratch1, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); if (representation.IsDouble()) { __ sw(storage_reg, FieldMemOperand(scratch1, offset)); } else { @@ -557,14 +491,9 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(scratch1, - offset, - storage_reg, - receiver_reg, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kRAHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); } } @@ -611,8 +540,8 @@ // Make sure there's no overlap between holder and object registers. DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) - && !scratch2.is(scratch1)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); // Keep track of the current object in register reg. Register reg = object_reg; @@ -645,10 +574,10 @@ } DCHECK(current.is_null() || current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); + NameDictionary::kNotFound); - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, - scratch1, scratch2); + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); reg = holder_reg; // From now on the object will be in holder_reg. @@ -671,9 +600,8 @@ if (current_map->IsJSGlobalProxyMap()) { __ CheckAccessGlobalProxy(reg, scratch2, miss); } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell( - masm(), Handle<JSGlobalObject>::cast(current), name, - scratch2, miss); + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); } reg = holder_reg; // From now on the object will be in holder_reg. @@ -762,8 +690,8 @@ __ push(receiver()); if (heap()->InNewSpace(callback->data())) { __ li(scratch3(), callback); - __ lw(scratch3(), FieldMemOperand(scratch3(), - ExecutableAccessorInfo::kDataOffset)); + __ lw(scratch3(), + FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); } else { __ li(scratch3(), Handle<Object>(callback->data(), isolate())); } @@ -772,8 +700,7 @@ __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize)); __ sw(scratch3(), MemOperand(sp, 3 * kPointerSize)); - __ li(scratch4(), - Operand(ExternalReference::isolate_address(isolate()))); + __ li(scratch4(), Operand(ExternalReference::isolate_address(isolate()))); __ sw(scratch4(), MemOperand(sp, 2 * kPointerSize)); __ sw(reg, MemOperand(sp, 1 * kPointerSize)); __ sw(name(), MemOperand(sp, 0 * kPointerSize)); @@ -872,7 +799,7 @@ Register holder_reg = Frontend(receiver(), name); __ Push(receiver(), holder_reg); // Receiver. - __ li(at, Operand(callback)); // Callback info. + __ li(at, Operand(callback)); // Callback info. __ push(at); __ li(at, Operand(name)); __ Push(at, value()); @@ -887,54 +814,6 @@ } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- ra : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ lw(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver, value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ pop(v0); - - // Restore context register. - __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( Handle<Name> name) { __ Push(receiver(), this->name(), value()); @@ -949,72 +828,9 @@ } -Register* PropertyAccessCompiler::load_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3, scratch4. - Register receiver = LoadIC::ReceiverRegister(); - Register name = LoadIC::NameRegister(); - static Register registers[] = { receiver, name, a3, a0, t0, t1 }; - return registers; -} - - -Register* PropertyAccessCompiler::store_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3. - Register receiver = StoreIC::ReceiverRegister(); - Register name = StoreIC::NameRegister(); - DCHECK(a3.is(KeyedStoreIC::MapRegister())); - static Register registers[] = { receiver, name, a3, t0, t1 }; - return registers; -} - - Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - // ----------- S t a t e ------------- - // -- a0 : receiver - // -- a2 : name - // -- ra : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ lw(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { Label miss; @@ -1044,130 +860,8 @@ } -Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, - CodeHandleList* handlers, - Handle<Name> name, - Code::StubType type, - IcCheckType check) { - Label miss; - - if (check == PROPERTY && - (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { - // In case we are compiling an IC for dictionary loads and stores, just - // check whether the name is unique. - if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { - __ JumpIfNotUniqueName(this->name(), &miss); - } else { - __ Branch(&miss, ne, this->name(), Operand(name)); - } - } - - Label number_case; - Register match = scratch2(); - Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; - __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. - - // Polymorphic keyed stores may use the map register - Register map_reg = scratch1(); - DCHECK(kind() != Code::KEYED_STORE_IC || - map_reg.is(KeyedStoreIC::MapRegister())); - - int receiver_count = types->length(); - int number_of_handled_maps = 0; - __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); - for (int current = 0; current < receiver_count; ++current) { - Handle<HeapType> type = types->at(current); - Handle<Map> map = IC::TypeToMap(*type, isolate()); - if (!map->is_deprecated()) { - number_of_handled_maps++; - // Check map and tail call if there's a match. - // Separate compare from branch, to provide path for above JumpIfSmi(). - __ Subu(match, map_reg, Operand(map)); - if (type->Is(HeapType::Number())) { - DCHECK(!number_case.is_unused()); - __ bind(&number_case); - } - __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, - eq, match, Operand(zero_reg)); - } - } - DCHECK(number_of_handled_maps != 0); - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - InlineCacheState state = - number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; - return GetCode(kind(), type, name, state); -} - - -Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( - MapHandleList* receiver_maps, CodeHandleList* handler_stubs, - MapHandleList* transitioned_maps) { - Label miss; - __ JumpIfSmi(receiver(), &miss); - - int receiver_count = receiver_maps->length(); - __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); - for (int i = 0; i < receiver_count; ++i) { - if (transitioned_maps->at(i).is_null()) { - __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, - scratch1(), Operand(receiver_maps->at(i))); - } else { - Label next_map; - __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i))); - __ li(transition_map(), Operand(transitioned_maps->at(i))); - __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET); - __ bind(&next_map); - } - } - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); -} - - #undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // The return address is in ra. - Label slow, miss; - - Register key = LoadIC::NameRegister(); - Register receiver = LoadIC::ReceiverRegister(); - DCHECK(receiver.is(a1)); - DCHECK(key.is(a2)); - - __ UntagAndJumpIfNotSmi(t2, key, &miss); - __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); - __ LoadFromNumberDictionary(&slow, t0, key, v0, t2, a3, t1); - __ Ret(); - - // Slow case, key and receiver still unmodified. - __ bind(&slow); - __ IncrementCounter( - masm->isolate()->counters()->keyed_load_external_array_slow(), - 1, a2, a3); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - // Miss case, call the runtime. - __ bind(&miss); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); } - - -#undef __ - -} } // namespace v8::internal +} // namespace v8::internal #endif // V8_TARGET_ARCH_MIPS
diff --git a/src/ic/mips/ic-compiler-mips.cc b/src/ic/mips/ic-compiler-mips.cc new file mode 100644 index 0000000..a563061 --- /dev/null +++ b/src/ic/mips/ic-compiler-mips.cc
@@ -0,0 +1,126 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS + +#include "src/ic/ic-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm()) + + +Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, + CodeHandleList* handlers, + Handle<Name> name, + Code::StubType type, + IcCheckType check) { + Label miss; + + if (check == PROPERTY && + (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { + // In case we are compiling an IC for dictionary loads and stores, just + // check whether the name is unique. + if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { + __ JumpIfNotUniqueName(this->name(), &miss); + } else { + __ Branch(&miss, ne, this->name(), Operand(name)); + } + } + + Label number_case; + Register match = scratch2(); + Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; + __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. + + // Polymorphic keyed stores may use the map register + Register map_reg = scratch1(); + DCHECK(kind() != Code::KEYED_STORE_IC || + map_reg.is(KeyedStoreIC::MapRegister())); + + int receiver_count = types->length(); + int number_of_handled_maps = 0; + __ lw(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); + for (int current = 0; current < receiver_count; ++current) { + Handle<HeapType> type = types->at(current); + Handle<Map> map = IC::TypeToMap(*type, isolate()); + if (!map->is_deprecated()) { + number_of_handled_maps++; + // Check map and tail call if there's a match. + // Separate compare from branch, to provide path for above JumpIfSmi(). + __ Subu(match, map_reg, Operand(map)); + if (type->Is(HeapType::Number())) { + DCHECK(!number_case.is_unused()); + __ bind(&number_case); + } + __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq, match, + Operand(zero_reg)); + } + } + DCHECK(number_of_handled_maps != 0); + + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + // Return the generated code. + InlineCacheState state = + number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; + return GetCode(kind(), type, name, state); +} + + +Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( + MapHandleList* receiver_maps, CodeHandleList* handler_stubs, + MapHandleList* transitioned_maps) { + Label miss; + __ JumpIfSmi(receiver(), &miss); + + int receiver_count = receiver_maps->length(); + __ lw(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); + for (int i = 0; i < receiver_count; ++i) { + if (transitioned_maps->at(i).is_null()) { + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(), + Operand(receiver_maps->at(i))); + } else { + Label next_map; + __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i))); + __ li(transition_map(), Operand(transitioned_maps->at(i))); + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET); + __ bind(&next_map); + } + } + + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + // Return the generated code. + return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); +} + + +#undef __ +#define __ ACCESS_MASM(masm) + + +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + __ li(a0, Operand(Smi::FromInt(strict_mode))); + __ Push(a0); + + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/mips/ic-mips.cc b/src/ic/mips/ic-mips.cc similarity index 78% rename from src/mips/ic-mips.cc rename to src/ic/mips/ic-mips.cc index 1f4a7be..5e72e89 100644 --- a/src/mips/ic-mips.cc +++ b/src/ic/mips/ic-mips.cc
@@ -3,16 +3,14 @@ // found in the LICENSE file. - #include "src/v8.h" #if V8_TARGET_ARCH_MIPS -#include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/runtime.h" -#include "src/stub-cache.h" +#include "src/ic/ic.h" +#include "src/ic/ic-compiler.h" +#include "src/ic/stub-cache.h" namespace v8 { namespace internal { @@ -25,8 +23,7 @@ #define __ ACCESS_MASM(masm) -static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, - Register type, +static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type, Label* global_object) { // Register usage: // type: holds the receiver instance type on entry. @@ -51,12 +48,9 @@ // is not a global object and does not have interceptors. // The address returned from GenerateStringDictionaryProbes() in scratch2 // is used. -static void GenerateDictionaryLoad(MacroAssembler* masm, - Label* miss, - Register elements, - Register name, - Register result, - Register scratch1, +static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss, + Register elements, Register name, + Register result, Register scratch1, Register scratch2) { // Main use of the scratch registers. // scratch1: Used as temporary and to hold the capacity of the property @@ -65,23 +59,18 @@ Label done; // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss, - &done, - elements, - name, - scratch1, - scratch2); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, + name, scratch1, scratch2); // If probing finds an entry check that the value is a normal // property. __ bind(&done); // scratch2 == elements + 4 * index. - const int kElementsStartOffset = NameDictionary::kHeaderSize + + const int kElementsStartOffset = + NameDictionary::kHeaderSize + NameDictionary::kElementsStartIndex * kPointerSize; const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); - __ And(at, - scratch1, + __ And(at, scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize)); __ Branch(miss, ne, at, Operand(zero_reg)); @@ -104,12 +93,9 @@ // is not a global object and does not have interceptors. // The address returned from GenerateStringDictionaryProbes() in scratch2 // is used. -static void GenerateDictionaryStore(MacroAssembler* masm, - Label* miss, - Register elements, - Register name, - Register value, - Register scratch1, +static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss, + Register elements, Register name, + Register value, Register scratch1, Register scratch2) { // Main use of the scratch registers. // scratch1: Used as temporary and to hold the capacity of the property @@ -118,23 +104,20 @@ Label done; // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss, - &done, - elements, - name, - scratch1, - scratch2); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, + name, scratch1, scratch2); // If probing finds an entry in the dictionary check that the value // is a normal property that is not read only. __ bind(&done); // scratch2 == elements + 4 * index. - const int kElementsStartOffset = NameDictionary::kHeaderSize + + const int kElementsStartOffset = + NameDictionary::kHeaderSize + NameDictionary::kElementsStartIndex * kPointerSize; const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; const int kTypeAndReadOnlyMask = (PropertyDetails::TypeField::kMask | - PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; + PropertyDetails::AttributesField::encode(READ_ONLY)) + << kSmiTagSize; __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); __ And(at, scratch1, Operand(kTypeAndReadOnlyMask)); __ Branch(miss, ne, at, Operand(zero_reg)); @@ -146,19 +129,17 @@ // Update the write barrier. Make sure not to clobber the value. __ mov(scratch1, value); - __ RecordWrite( - elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved, + kDontSaveFPRegs); } // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, - Register receiver, - Register map, + Register receiver, Register map, Register scratch, - int interceptor_bit, - Label* slow) { + int interceptor_bit, Label* slow) { // Check that the object isn't a smi. __ JumpIfSmi(receiver, slow); // Get the map of the receiver. @@ -180,14 +161,10 @@ // Loads an indexed element from a fast case array. // If not_fast_array is NULL, doesn't perform the elements map check. -static void GenerateFastArrayLoad(MacroAssembler* masm, - Register receiver, - Register key, - Register elements, - Register scratch1, - Register scratch2, - Register result, - Label* not_fast_array, +static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, + Register key, Register elements, + Register scratch1, Register scratch2, + Register result, Label* not_fast_array, Label* out_of_range) { // Register use: // @@ -244,12 +221,9 @@ // Checks whether a key is an array index string or a unique name. // Falls through if a key is a unique name. -static void GenerateKeyNameCheck(MacroAssembler* masm, - Register key, - Register map, - Register hash, - Label* index_string, - Label* not_unique) { +static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, + Register map, Register hash, + Label* index_string, Label* not_unique) { // The key is not a smi. Label unique; // Is it a name? @@ -285,8 +259,8 @@ // Probe the stub cache. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::LOAD_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, receiver, name, a3, t0, t1, t2); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3, + t0, t1, t2); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -340,14 +314,10 @@ } -static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, - Register object, - Register key, - Register scratch1, - Register scratch2, - Register scratch3, - Label* unmapped_case, - Label* slow_case) { +static MemOperand GenerateMappedArgumentsLookup( + MacroAssembler* masm, Register object, Register key, Register scratch1, + Register scratch2, Register scratch3, Label* unmapped_case, + Label* slow_case) { Heap* heap = masm->isolate()->heap(); // Check that the receiver is a JSObject. Because of the map check @@ -365,11 +335,7 @@ // Load the elements into scratch1 and check its map. Handle<Map> arguments_map(heap->sloppy_arguments_elements_map()); __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); - __ CheckMap(scratch1, - scratch2, - arguments_map, - slow_case, - DONT_DO_SMI_CHECK); + __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK); // Check if element is in the range of mapped arguments. If not, jump // to the unmapped lookup with the parameter map in scratch1. __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); @@ -413,18 +379,13 @@ const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; Register backing_store = parameter_map; __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); - __ CheckMap(backing_store, - scratch, - Heap::kFixedArrayMapRootIndex, - slow_case, + __ CheckMap(backing_store, scratch, Heap::kFixedArrayMapRootIndex, slow_case, DONT_DO_SMI_CHECK); __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); __ Branch(slow_case, Ugreater_equal, key, Operand(scratch)); __ li(scratch, Operand(kPointerSize >> 1)); __ Mul(scratch, key, scratch); - __ Addu(scratch, - scratch, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ Addu(scratch, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ Addu(scratch, backing_store, scratch); return MemOperand(scratch); } @@ -438,9 +399,8 @@ DCHECK(key.is(a2)); Label slow, notin; - MemOperand mapped_location = - GenerateMappedArgumentsLookup( - masm, receiver, key, a0, a3, t0, ¬in, &slow); + MemOperand mapped_location = GenerateMappedArgumentsLookup( + masm, receiver, key, a0, a3, t0, ¬in, &slow); __ Ret(USE_DELAY_SLOT); __ lw(v0, mapped_location); __ bind(¬in); @@ -470,8 +430,8 @@ __ sw(value, mapped_location); __ mov(t5, value); DCHECK_EQ(mapped_location.offset(), 0); - __ RecordWrite(a3, mapped_location.rm(), t5, - kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(a3, mapped_location.rm(), t5, kRAHasNotBeenSaved, + kDontSaveFPRegs); __ Ret(USE_DELAY_SLOT); __ mov(v0, value); // (In delay slot) return the value stored in v0. __ bind(¬in); @@ -482,8 +442,8 @@ __ sw(value, unmapped_location); __ mov(t5, value); DCHECK_EQ(unmapped_location.offset(), 0); - __ RecordWrite(a3, unmapped_location.rm(), t5, - kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(a3, unmapped_location.rm(), t5, kRAHasNotBeenSaved, + kDontSaveFPRegs); __ Ret(USE_DELAY_SLOT); __ mov(v0, a0); // (In delay slot) return the value stored in v0. __ bind(&slow); @@ -529,9 +489,7 @@ const Register StoreIC::ValueRegister() { return a0; } -const Register KeyedStoreIC::MapRegister() { - return a3; -} +const Register KeyedStoreIC::MapRegister() { return a3; } void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { @@ -561,14 +519,13 @@ // Now the key is known to be a smi. This place is also jumped to from below // where a numeric string is converted to a smi. - GenerateKeyedLoadReceiverCheck( - masm, receiver, a0, a3, Map::kHasIndexedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, + Map::kHasIndexedInterceptor, &slow); // Check the receiver's map to see if it has fast elements. __ CheckFastElements(a0, a3, &check_number_dictionary); - GenerateFastArrayLoad( - masm, receiver, key, a0, a3, t0, v0, NULL, &slow); + GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, NULL, &slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, t0, a3); __ Ret(); @@ -587,17 +544,15 @@ // Slow case, key and receiver still in a2 and a1. __ bind(&slow); - __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), - 1, - t0, + __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, t0, a3); GenerateRuntimeGetProperty(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow); - GenerateKeyedLoadReceiverCheck( - masm, receiver, a0, a3, Map::kHasNamedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, + Map::kHasNamedInterceptor, &slow); // If the receiver is a fast-case object, check the keyed lookup @@ -671,10 +626,8 @@ __ sll(at, t2, kPointerSizeLog2); __ addu(at, receiver, at); __ lw(v0, MemOperand(at)); - __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), - 1, - t0, - a3); + __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, + t0, a3); __ Ret(); // Load property array property. @@ -684,10 +637,8 @@ __ sll(v0, t1, kPointerSizeLog2); __ Addu(v0, v0, receiver); __ lw(v0, MemOperand(v0)); - __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), - 1, - t0, - a3); + __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, + t0, a3); __ Ret(); @@ -700,9 +651,7 @@ GenerateGlobalInstanceTypeCheck(masm, a0, &slow); // Load the property to v0. GenerateDictionaryLoad(masm, &slow, a3, key, v0, t1, t0); - __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), - 1, - t0, + __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1, t0, a3); __ Ret(); @@ -723,10 +672,7 @@ Register result = v0; DCHECK(!scratch.is(receiver) && !scratch.is(index)); - StringCharAtGenerator char_at_generator(receiver, - index, - scratch, - result, + StringCharAtGenerator char_at_generator(receiver, index, scratch, result, &miss, // When not a string. &miss, // When not a number. &miss, // When index out of range. @@ -742,30 +688,11 @@ } -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode. - __ Push(a0); - - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - static void KeyedStoreGenerateGenericHelper( - MacroAssembler* masm, - Label* fast_object, - Label* fast_double, - Label* slow, - KeyedStoreCheckMap check_map, - KeyedStoreIncrementLength increment_length, - Register value, - Register key, - Register receiver, - Register receiver_map, - Register elements_map, - Register elements) { + MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, + KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, + Register value, Register key, Register receiver, Register receiver_map, + Register elements_map, Register elements) { Label transition_smi_elements; Label finish_object_store, non_double_value, transition_double_elements; Label fast_double_without_map_check; @@ -829,13 +756,8 @@ __ sw(value, MemOperand(address)); // Update write barrier for the elements array address. __ mov(scratch_value, value); // Preserve the value which is returned. - __ RecordWrite(elements, - address, - scratch_value, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); + __ RecordWrite(elements, address, scratch_value, kRAHasNotBeenSaved, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); __ Ret(); __ bind(fast_double); @@ -849,9 +771,8 @@ // HOLECHECK: guards "A[i] double hole?" // We have to see if the double version of the hole is present. If so // go to the runtime. - __ Addu(address, elements, - Operand(FixedDoubleArray::kHeaderSize + kHoleNanUpper32Offset - - kHeapObjectTag)); + __ Addu(address, elements, Operand(FixedDoubleArray::kHeaderSize + + kHoleNanUpper32Offset - kHeapObjectTag)); __ sll(at, key, kPointerSizeLog2); __ addu(address, address, at); __ lw(scratch_value, MemOperand(address)); @@ -861,13 +782,10 @@ slow); __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, - key, + __ StoreNumberToDoubleElements(value, key, elements, // Overwritten. a3, // Scratch regs... - t0, - t1, - &transition_double_elements); + t0, t1, &transition_double_elements); if (increment_length == kIncrementLength) { // Add 1 to receiver->length. __ Addu(scratch_value, key, Operand(Smi::FromInt(1))); @@ -883,25 +801,19 @@ // Value is a double. Transition FAST_SMI_ELEMENTS -> // FAST_DOUBLE_ELEMENTS and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - receiver_map, - t0, - slow); - AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS); - ElementsTransitionGenerator::GenerateSmiToDouble( - masm, receiver, key, value, receiver_map, mode, slow); + __ LoadTransitionedArrayMapConditional( + FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, t0, slow); + AllocationSiteMode mode = + AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, + receiver_map, mode, slow); __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ jmp(&fast_double_without_map_check); __ bind(&non_double_value); // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - slow); + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, + receiver_map, t0, slow); mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); ElementsTransitionGenerator::GenerateMapChangeElementsTransition( masm, receiver, key, value, receiver_map, mode, slow); @@ -912,11 +824,8 @@ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - t0, - slow); + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, + receiver_map, t0, slow); mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); ElementsTransitionGenerator::GenerateDoubleToObject( masm, receiver, key, value, receiver_map, mode, slow); @@ -956,8 +865,8 @@ // Check that the receiver does not require access checks and is not observed. // The generic stub does not perform map checks or handle observed objects. __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset)); - __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded | - 1 << Map::kIsObserved)); + __ And(t0, t0, + Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved)); __ Branch(&slow, ne, t0, Operand(zero_reg)); // Check if the object is a JS array or not. __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset)); @@ -977,7 +886,7 @@ // a0: value. // a1: key. // a2: receiver. - GenerateRuntimeSetProperty(masm, strict_mode); + PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode); // Extra capacity case: Check if there is extra capacity to // perform the store and update the length. Used for adding one @@ -991,8 +900,8 @@ __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); __ Branch(&slow, hs, key, Operand(t0)); __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ Branch( - &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex); + __ Branch(&check_if_double_array, ne, elements_map, + Heap::kFixedArrayMapRootIndex); __ jmp(&fast_object_grow); @@ -1010,14 +919,13 @@ __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ Branch(&extra, hs, key, Operand(t0)); - KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, - &slow, kCheckMap, kDontIncrementLength, - value, key, receiver, receiver_map, - elements_map, elements); + KeyedStoreGenerateGenericHelper( + masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength, + value, key, receiver, receiver_map, elements_map, elements); KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, - &slow, kDontCheckMap, kIncrementLength, - value, key, receiver, receiver_map, - elements_map, elements); + &slow, kDontCheckMap, kIncrementLength, value, + key, receiver, receiver_map, elements_map, + elements); } @@ -1051,8 +959,10 @@ __ Push(receiver, key); // Receiver, key. // Perform tail call to the entry. - __ TailCallExternalReference(ExternalReference( - IC_Utility(kLoadElementWithInterceptor), masm->isolate()), 2, 1); + __ TailCallExternalReference( + ExternalReference(IC_Utility(kLoadElementWithInterceptor), + masm->isolate()), + 2, 1); __ bind(&slow); GenerateMiss(masm); @@ -1069,32 +979,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - // We can't use MultiPush as the order of the registers is important. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - - __ TailCallExternalReference(ref, 3, 1); -} - - void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { Register receiver = ReceiverRegister(); Register name = NameRegister(); @@ -1105,8 +989,8 @@ // Get the receiver from the stack and probe the stub cache. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::STORE_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, receiver, name, a3, t0, t1, t2); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3, + t0, t1, t2); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -1116,8 +1000,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) { __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); // Perform tail call to the entry. - ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss), - masm->isolate()); + ExternalReference ref = + ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); __ TailCallExternalReference(ref, 3, 1); } @@ -1145,18 +1029,6 @@ } -void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - __ li(a0, Operand(Smi::FromInt(strict_mode))); - __ Push(a0); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - #undef __ @@ -1189,7 +1061,7 @@ // was inlined. Instr instr = Assembler::instr_at(andi_instruction_address); return Assembler::IsAndImmediate(instr) && - Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()); + Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()); } @@ -1216,8 +1088,8 @@ } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, andi=%p, delta=%d\n", - address, andi_instruction_address, delta); + PrintF("[ patching ic at %p, andi=%p, delta=%d\n", address, + andi_instruction_address, delta); } Address patch_address = @@ -1252,8 +1124,7 @@ patcher.ChangeBranchCondition(eq); } } - - -} } // namespace v8::internal +} +} // namespace v8::internal #endif // V8_TARGET_ARCH_MIPS
diff --git a/src/ic/mips/stub-cache-mips.cc b/src/ic/mips/stub-cache-mips.cc new file mode 100644 index 0000000..6196f26 --- /dev/null +++ b/src/ic/mips/stub-cache-mips.cc
@@ -0,0 +1,167 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS + +#include "src/codegen.h" +#include "src/ic/stub-cache.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +static void ProbeTable(Isolate* isolate, MacroAssembler* masm, + Code::Flags flags, StubCache::Table table, + Register receiver, Register name, + // Number of the cache entry, not scaled. + Register offset, Register scratch, Register scratch2, + Register offset_scratch) { + ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); + ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); + ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); + + uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); + uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address()); + uint32_t map_off_addr = reinterpret_cast<uint32_t>(map_offset.address()); + + // Check the relative positions of the address fields. + DCHECK(value_off_addr > key_off_addr); + DCHECK((value_off_addr - key_off_addr) % 4 == 0); + DCHECK((value_off_addr - key_off_addr) < (256 * 4)); + DCHECK(map_off_addr > key_off_addr); + DCHECK((map_off_addr - key_off_addr) % 4 == 0); + DCHECK((map_off_addr - key_off_addr) < (256 * 4)); + + Label miss; + Register base_addr = scratch; + scratch = no_reg; + + // Multiply by 3 because there are 3 fields per entry (name, code, map). + __ sll(offset_scratch, offset, 1); + __ Addu(offset_scratch, offset_scratch, offset); + + // Calculate the base address of the entry. + __ li(base_addr, Operand(key_offset)); + __ sll(at, offset_scratch, kPointerSizeLog2); + __ Addu(base_addr, base_addr, at); + + // Check that the key in the entry matches the name. + __ lw(at, MemOperand(base_addr, 0)); + __ Branch(&miss, ne, name, Operand(at)); + + // Check the map matches. + __ lw(at, MemOperand(base_addr, map_off_addr - key_off_addr)); + __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ Branch(&miss, ne, at, Operand(scratch2)); + + // Get the code entry from the cache. + Register code = scratch2; + scratch2 = no_reg; + __ lw(code, MemOperand(base_addr, value_off_addr - key_off_addr)); + + // Check that the flags match what we're looking for. + Register flags_reg = base_addr; + base_addr = no_reg; + __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); + __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup)); + __ Branch(&miss, ne, flags_reg, Operand(flags)); + +#ifdef DEBUG + if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { + __ jmp(&miss); + } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { + __ jmp(&miss); + } +#endif + + // Jump to the first instruction in the code stub. + __ Addu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ Jump(at); + + // Miss: fall through. + __ bind(&miss); +} + + +void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags, + Register receiver, Register name, + Register scratch, Register extra, Register extra2, + Register extra3) { + Isolate* isolate = masm->isolate(); + Label miss; + + // Make sure that code is valid. The multiplying code relies on the + // entry size being 12. + DCHECK(sizeof(Entry) == 12); + + // Make sure the flags does not name a specific type. + DCHECK(Code::ExtractTypeFromFlags(flags) == 0); + + // Make sure that there are no register conflicts. + DCHECK(!scratch.is(receiver)); + DCHECK(!scratch.is(name)); + DCHECK(!extra.is(receiver)); + DCHECK(!extra.is(name)); + DCHECK(!extra.is(scratch)); + DCHECK(!extra2.is(receiver)); + DCHECK(!extra2.is(name)); + DCHECK(!extra2.is(scratch)); + DCHECK(!extra2.is(extra)); + + // Check register validity. + DCHECK(!scratch.is(no_reg)); + DCHECK(!extra.is(no_reg)); + DCHECK(!extra2.is(no_reg)); + DCHECK(!extra3.is(no_reg)); + + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2, + extra3); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(receiver, &miss); + + // Get the map of the receiver and compute the hash. + __ lw(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); + __ lw(at, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ Addu(scratch, scratch, at); + uint32_t mask = kPrimaryTableSize - 1; + // We shift out the last two bits because they are not part of the hash and + // they are always 01 for maps. + __ srl(scratch, scratch, kCacheIndexShift); + __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask)); + __ And(scratch, scratch, Operand(mask)); + + // Probe the primary table. + ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra, + extra2, extra3); + + // Primary miss: Compute hash for secondary probe. + __ srl(at, name, kCacheIndexShift); + __ Subu(scratch, scratch, at); + uint32_t mask2 = kSecondaryTableSize - 1; + __ Addu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2)); + __ And(scratch, scratch, Operand(mask2)); + + // Probe the secondary table. + ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra, + extra2, extra3); + + // Cache miss: Fall-through and let caller handle the miss by + // entering the runtime system. + __ bind(&miss); + __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2, + extra3); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS
diff --git a/src/ic/mips64/OWNERS b/src/ic/mips64/OWNERS new file mode 100644 index 0000000..5508ba6 --- /dev/null +++ b/src/ic/mips64/OWNERS
@@ -0,0 +1,5 @@ +paul.lind@imgtec.com +gergely.kis@imgtec.com +akos.palfi@imgtec.com +balazs.kilvady@imgtec.com +dusan.milosavljevic@imgtec.com
diff --git a/src/ic/mips64/access-compiler-mips64.cc b/src/ic/mips64/access-compiler-mips64.cc new file mode 100644 index 0000000..1249467 --- /dev/null +++ b/src/ic/mips64/access-compiler-mips64.cc
@@ -0,0 +1,46 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS64 + +#include "src/ic/access-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, + Handle<Code> code) { + __ Jump(code, RelocInfo::CODE_TARGET); +} + + +Register* PropertyAccessCompiler::load_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3, scratch4. + Register receiver = LoadIC::ReceiverRegister(); + Register name = LoadIC::NameRegister(); + static Register registers[] = {receiver, name, a3, a0, a4, a5}; + return registers; +} + + +Register* PropertyAccessCompiler::store_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3. + Register receiver = StoreIC::ReceiverRegister(); + Register name = StoreIC::NameRegister(); + DCHECK(a3.is(KeyedStoreIC::MapRegister())); + static Register registers[] = {receiver, name, a3, a4, a5}; + return registers; +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS64
diff --git a/src/mips64/stub-cache-mips64.cc b/src/ic/mips64/handler-compiler-mips64.cc similarity index 66% rename from src/mips64/stub-cache-mips64.cc rename to src/ic/mips64/handler-compiler-mips64.cc index 3e73fd5..d26a1fd 100644 --- a/src/mips64/stub-cache-mips64.cc +++ b/src/ic/mips64/handler-compiler-mips64.cc
@@ -1,4 +1,4 @@ -// Copyright 2012 the V8 project authors. All rights reserved. +// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,8 @@ #if V8_TARGET_ARCH_MIPS64 -#include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/stub-cache.h" +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" namespace v8 { namespace internal { @@ -16,81 +15,79 @@ #define __ ACCESS_MASM(masm) -static void ProbeTable(Isolate* isolate, - MacroAssembler* masm, - Code::Flags flags, - StubCache::Table table, - Register receiver, - Register name, - // Number of the cache entry, not scaled. - Register offset, - Register scratch, - Register scratch2, - Register offset_scratch) { - ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); - ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); - ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + // ----------- S t a t e ------------- + // -- a0 : receiver + // -- a2 : name + // -- ra : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); - uint64_t key_off_addr = reinterpret_cast<uint64_t>(key_offset.address()); - uint64_t value_off_addr = reinterpret_cast<uint64_t>(value_offset.address()); - uint64_t map_off_addr = reinterpret_cast<uint64_t>(map_offset.address()); - - // Check the relative positions of the address fields. - DCHECK(value_off_addr > key_off_addr); - DCHECK((value_off_addr - key_off_addr) % 4 == 0); - DCHECK((value_off_addr - key_off_addr) < (256 * 4)); - DCHECK(map_off_addr > key_off_addr); - DCHECK((map_off_addr - key_off_addr) % 4 == 0); - DCHECK((map_off_addr - key_off_addr) < (256 * 4)); - - Label miss; - Register base_addr = scratch; - scratch = no_reg; - - // Multiply by 3 because there are 3 fields per entry (name, code, map). - __ dsll(offset_scratch, offset, 1); - __ Daddu(offset_scratch, offset_scratch, offset); - - // Calculate the base address of the entry. - __ li(base_addr, Operand(key_offset)); - __ dsll(at, offset_scratch, kPointerSizeLog2); - __ Daddu(base_addr, base_addr, at); - - // Check that the key in the entry matches the name. - __ ld(at, MemOperand(base_addr, 0)); - __ Branch(&miss, ne, name, Operand(at)); - - // Check the map matches. - __ ld(at, MemOperand(base_addr, map_off_addr - key_off_addr)); - __ ld(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ Branch(&miss, ne, at, Operand(scratch2)); - - // Get the code entry from the cache. - Register code = scratch2; - scratch2 = no_reg; - __ ld(code, MemOperand(base_addr, value_off_addr - key_off_addr)); - - // Check that the flags match what we're looking for. - Register flags_reg = base_addr; - base_addr = no_reg; - __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); - __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup)); - __ Branch(&miss, ne, flags_reg, Operand(flags)); - -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ ld(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); } -#endif - // Jump to the first instruction in the code stub. - __ Daddu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ Jump(at); + // Restore context register. + __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); +} - // Miss: fall through. - __ bind(&miss); + +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- ra : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ ld(receiver, + FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver, value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ pop(v0); + + // Restore context register. + __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + } + __ Ret(); } @@ -132,111 +129,13 @@ __ ld(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); - NameDictionaryLookupStub::GenerateNegativeLookup(masm, - miss_label, - &done, - receiver, - properties, - name, - scratch1); + NameDictionaryLookupStub::GenerateNegativeLookup( + masm, miss_label, &done, receiver, properties, name, scratch1); __ bind(&done); __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); } -void StubCache::GenerateProbe(MacroAssembler* masm, - Code::Flags flags, - Register receiver, - Register name, - Register scratch, - Register extra, - Register extra2, - Register extra3) { - Isolate* isolate = masm->isolate(); - Label miss; - - // Make sure that code is valid. The multiplying code relies on the - // entry size being 12. - // DCHECK(sizeof(Entry) == 12); - // DCHECK(sizeof(Entry) == 3 * kPointerSize); - - // Make sure the flags does not name a specific type. - DCHECK(Code::ExtractTypeFromFlags(flags) == 0); - - // Make sure that there are no register conflicts. - DCHECK(!scratch.is(receiver)); - DCHECK(!scratch.is(name)); - DCHECK(!extra.is(receiver)); - DCHECK(!extra.is(name)); - DCHECK(!extra.is(scratch)); - DCHECK(!extra2.is(receiver)); - DCHECK(!extra2.is(name)); - DCHECK(!extra2.is(scratch)); - DCHECK(!extra2.is(extra)); - - // Check register validity. - DCHECK(!scratch.is(no_reg)); - DCHECK(!extra.is(no_reg)); - DCHECK(!extra2.is(no_reg)); - DCHECK(!extra3.is(no_reg)); - - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, - extra2, extra3); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(receiver, &miss); - - // Get the map of the receiver and compute the hash. - __ ld(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); - __ ld(at, FieldMemOperand(receiver, HeapObject::kMapOffset)); - __ Daddu(scratch, scratch, at); - uint64_t mask = kPrimaryTableSize - 1; - // We shift out the last two bits because they are not part of the hash and - // they are always 01 for maps. - __ dsrl(scratch, scratch, kCacheIndexShift); - __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask)); - __ And(scratch, scratch, Operand(mask)); - - // Probe the primary table. - ProbeTable(isolate, - masm, - flags, - kPrimary, - receiver, - name, - scratch, - extra, - extra2, - extra3); - - // Primary miss: Compute hash for secondary probe. - __ dsrl(at, name, kCacheIndexShift); - __ Dsubu(scratch, scratch, at); - uint64_t mask2 = kSecondaryTableSize - 1; - __ Daddu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2)); - __ And(scratch, scratch, Operand(mask2)); - - // Probe the secondary table. - ProbeTable(isolate, - masm, - flags, - kSecondary, - receiver, - name, - scratch, - extra, - extra2, - extra3); - - // Cache miss: Fall-through and let caller handle the miss by - // entering the runtime system. - __ bind(&miss); - __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, - extra2, extra3); -} - - void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( MacroAssembler* masm, int index, Register prototype, Label* miss) { Isolate* isolate = masm->isolate(); @@ -269,6 +168,9 @@ } +// Generate code to check that a global property cell is empty. Create +// the property cell at compilation time if no cell exists for the +// property. void PropertyHandlerCompiler::GenerateCheckPropertyCell( MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, Register scratch, Label* miss) { @@ -281,10 +183,8 @@ } -static void PushInterceptorArguments(MacroAssembler* masm, - Register receiver, - Register holder, - Register name, +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); @@ -301,12 +201,8 @@ static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - Handle<JSObject> holder_obj, - IC::UtilityId id) { + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), NamedLoadHandlerCompiler::kInterceptorArgsLength); @@ -324,10 +220,10 @@ __ sd(receiver, MemOperand(sp, argc * kPointerSize)); // Push receiver. // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - Register arg = values[argc-1-i]; + Register arg = values[argc - 1 - i]; DCHECK(!receiver.is(arg)); DCHECK(!scratch_in.is(arg)); - __ sd(arg, MemOperand(sp, (argc-1-i) * kPointerSize)); // Push arg. + __ sd(arg, MemOperand(sp, (argc - 1 - i) * kPointerSize)); // Push arg. } DCHECK(optimization.is_simple_api_call()); @@ -339,16 +235,15 @@ // Put holder in place. CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( - receiver_map, - &holder_lookup); + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); switch (holder_lookup) { case CallOptimization::kHolderIsReceiver: __ Move(holder, receiver); break; case CallOptimization::kHolderFound: __ li(holder, api_holder); - break; + break; case CallOptimization::kHolderNotFound: UNREACHABLE(); break; @@ -377,10 +272,7 @@ Address function_address = v8::ToCData<Address>(api_call_info->callback()); ApiFunction fun(function_address); ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; - ExternalReference ref = - ExternalReference(&fun, - type, - masm->isolate()); + ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); __ li(api_function_address, Operand(ref)); // Jump to stub. @@ -389,9 +281,59 @@ } -void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, - Handle<Code> code) { - __ Jump(code, RelocInfo::CODE_TARGET); +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // The return address is in ra + Label slow, miss; + + Register key = LoadIC::NameRegister(); + Register receiver = LoadIC::ReceiverRegister(); + DCHECK(receiver.is(a1)); + DCHECK(key.is(a2)); + + __ UntagAndJumpIfNotSmi(a6, key, &miss); + __ ld(a4, FieldMemOperand(receiver, JSObject::kElementsOffset)); + DCHECK(kSmiTagSize + kSmiShiftSize == 32); + __ LoadFromNumberDictionary(&slow, a4, key, v0, a6, a3, a5); + __ Ret(); + + // Slow case, key and receiver still unmodified. + __ bind(&slow); + __ IncrementCounter( + masm->isolate()->counters()->keyed_load_external_array_slow(), 1, a2, a3); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); + + // Miss case, call the runtime. + __ bind(&miss); + + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + // Push receiver, key and value for runtime call. + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); } @@ -463,8 +405,8 @@ __ jmp(&do_store); __ bind(&heap_number); - __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, - miss_label, DONT_DO_SMI_CHECK); + __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex, miss_label, + DONT_DO_SMI_CHECK); __ ldc1(f4, FieldMemOperand(value_reg, HeapNumber::kValueOffset)); __ bind(&do_store); @@ -483,9 +425,9 @@ __ li(a2, Operand(transition)); __ Push(a2, a0); __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); + ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), + isolate()), + 3, 1); return; } @@ -494,13 +436,8 @@ __ sd(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, - scratch2, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - OMIT_REMEMBERED_SET, + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kRAHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); if (details.type() == CONSTANT) { @@ -519,8 +456,8 @@ index -= transition->inobject_properties(); // TODO(verwaest): Share this code as a code stub. - SmiCheck smi_check = representation.IsTagged() - ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; if (index < 0) { // Set the property straight into the object. int offset = transition->instance_size() + (index * kPointerSize); @@ -535,21 +472,15 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(receiver_reg, - offset, - storage_reg, - scratch1, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kRAHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); } } else { // Write to the properties array. int offset = index * kPointerSize + FixedArray::kHeaderSize; // Get the properties array - __ ld(scratch1, - FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); + __ ld(scratch1, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); if (representation.IsDouble()) { __ sd(storage_reg, FieldMemOperand(scratch1, offset)); } else { @@ -561,14 +492,9 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(scratch1, - offset, - storage_reg, - receiver_reg, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kRAHasNotBeenSaved, kDontSaveFPRegs, + EMIT_REMEMBERED_SET, smi_check); } } @@ -615,8 +541,8 @@ // Make sure there's no overlap between holder and object registers. DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) - && !scratch2.is(scratch1)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); // Keep track of the current object in register reg. Register reg = object_reg; @@ -649,10 +575,10 @@ } DCHECK(current.is_null() || current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); + NameDictionary::kNotFound); - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, - scratch1, scratch2); + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); __ ld(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset)); reg = holder_reg; // From now on the object will be in holder_reg. @@ -681,9 +607,8 @@ if (current_map->IsJSGlobalProxyMap()) { __ CheckAccessGlobalProxy(reg, scratch2, miss); } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell( - masm(), Handle<JSGlobalObject>::cast(current), name, - scratch2, miss); + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); } reg = holder_reg; // From now on the object will be in holder_reg. @@ -766,8 +691,8 @@ __ push(receiver()); if (heap()->InNewSpace(callback->data())) { __ li(scratch3(), callback); - __ ld(scratch3(), FieldMemOperand(scratch3(), - ExecutableAccessorInfo::kDataOffset)); + __ ld(scratch3(), + FieldMemOperand(scratch3(), ExecutableAccessorInfo::kDataOffset)); } else { __ li(scratch3(), Handle<Object>(callback->data(), isolate())); } @@ -776,8 +701,7 @@ __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); __ sd(scratch3(), MemOperand(sp, 4 * kPointerSize)); __ sd(scratch3(), MemOperand(sp, 3 * kPointerSize)); - __ li(scratch4(), - Operand(ExternalReference::isolate_address(isolate()))); + __ li(scratch4(), Operand(ExternalReference::isolate_address(isolate()))); __ sd(scratch4(), MemOperand(sp, 2 * kPointerSize)); __ sd(reg, MemOperand(sp, 1 * kPointerSize)); __ sd(name(), MemOperand(sp, 0 * kPointerSize)); @@ -876,7 +800,7 @@ Register holder_reg = Frontend(receiver(), name); __ Push(receiver(), holder_reg); // Receiver. - __ li(at, Operand(callback)); // Callback info. + __ li(at, Operand(callback)); // Callback info. __ push(at); __ li(at, Operand(name)); __ Push(at, value()); @@ -891,54 +815,6 @@ } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- ra : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ld(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver, value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ pop(v0); - - // Restore context register. - __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( Handle<Name> name) { __ Push(receiver(), this->name(), value()); @@ -953,72 +829,9 @@ } -Register* PropertyAccessCompiler::load_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3, scratch4. - Register receiver = LoadIC::ReceiverRegister(); - Register name = LoadIC::NameRegister(); - static Register registers[] = { receiver, name, a3, a0, a4, a5 }; - return registers; -} - - -Register* PropertyAccessCompiler::store_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3. - Register receiver = StoreIC::ReceiverRegister(); - Register name = StoreIC::NameRegister(); - DCHECK(a3.is(KeyedStoreIC::MapRegister())); - static Register registers[] = { receiver, name, a3, a4, a5 }; - return registers; -} - - Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - // ----------- S t a t e ------------- - // -- a0 : receiver - // -- a2 : name - // -- ra : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ ld(receiver, - FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - } - __ Ret(); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { Label miss; @@ -1048,131 +861,8 @@ } -Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, - CodeHandleList* handlers, - Handle<Name> name, - Code::StubType type, - IcCheckType check) { - Label miss; - - if (check == PROPERTY && - (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { - // In case we are compiling an IC for dictionary loads and stores, just - // check whether the name is unique. - if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { - __ JumpIfNotUniqueName(this->name(), &miss); - } else { - __ Branch(&miss, ne, this->name(), Operand(name)); - } - } - - Label number_case; - Register match = scratch2(); - Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; - __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. - - // Polymorphic keyed stores may use the map register - Register map_reg = scratch1(); - DCHECK(kind() != Code::KEYED_STORE_IC || - map_reg.is(KeyedStoreIC::MapRegister())); - - int receiver_count = types->length(); - int number_of_handled_maps = 0; - __ ld(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); - for (int current = 0; current < receiver_count; ++current) { - Handle<HeapType> type = types->at(current); - Handle<Map> map = IC::TypeToMap(*type, isolate()); - if (!map->is_deprecated()) { - number_of_handled_maps++; - // Check map and tail call if there's a match. - // Separate compare from branch, to provide path for above JumpIfSmi(). - __ Dsubu(match, map_reg, Operand(map)); - if (type->Is(HeapType::Number())) { - DCHECK(!number_case.is_unused()); - __ bind(&number_case); - } - __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, - eq, match, Operand(zero_reg)); - } - } - DCHECK(number_of_handled_maps != 0); - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - InlineCacheState state = - number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; - return GetCode(kind(), type, name, state); -} - - -Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( - MapHandleList* receiver_maps, CodeHandleList* handler_stubs, - MapHandleList* transitioned_maps) { - Label miss; - __ JumpIfSmi(receiver(), &miss); - - int receiver_count = receiver_maps->length(); - __ ld(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); - for (int i = 0; i < receiver_count; ++i) { - if (transitioned_maps->at(i).is_null()) { - __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, - scratch1(), Operand(receiver_maps->at(i))); - } else { - Label next_map; - __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i))); - __ li(transition_map(), Operand(transitioned_maps->at(i))); - __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET); - __ bind(&next_map); - } - } - - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); -} - - #undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // The return address is in ra - Label slow, miss; - - Register key = LoadIC::NameRegister(); - Register receiver = LoadIC::ReceiverRegister(); - DCHECK(receiver.is(a1)); - DCHECK(key.is(a2)); - - __ UntagAndJumpIfNotSmi(a6, key, &miss); - __ ld(a4, FieldMemOperand(receiver, JSObject::kElementsOffset)); - DCHECK(kSmiTagSize + kSmiShiftSize == 32); - __ LoadFromNumberDictionary(&slow, a4, key, v0, a6, a3, a5); - __ Ret(); - - // Slow case, key and receiver still unmodified. - __ bind(&slow); - __ IncrementCounter( - masm->isolate()->counters()->keyed_load_external_array_slow(), - 1, a2, a3); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - // Miss case, call the runtime. - __ bind(&miss); - - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); } - - -#undef __ - -} } // namespace v8::internal +} // namespace v8::internal #endif // V8_TARGET_ARCH_MIPS64
diff --git a/src/ic/mips64/ic-compiler-mips64.cc b/src/ic/mips64/ic-compiler-mips64.cc new file mode 100644 index 0000000..a503f72 --- /dev/null +++ b/src/ic/mips64/ic-compiler-mips64.cc
@@ -0,0 +1,126 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS64 + +#include "src/ic/ic-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm()) + + +Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, + CodeHandleList* handlers, + Handle<Name> name, + Code::StubType type, + IcCheckType check) { + Label miss; + + if (check == PROPERTY && + (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { + // In case we are compiling an IC for dictionary loads and stores, just + // check whether the name is unique. + if (name.is_identical_to(isolate()->factory()->normal_ic_symbol())) { + __ JumpIfNotUniqueName(this->name(), &miss); + } else { + __ Branch(&miss, ne, this->name(), Operand(name)); + } + } + + Label number_case; + Register match = scratch2(); + Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; + __ JumpIfSmi(receiver(), smi_target, match); // Reg match is 0 if Smi. + + // Polymorphic keyed stores may use the map register + Register map_reg = scratch1(); + DCHECK(kind() != Code::KEYED_STORE_IC || + map_reg.is(KeyedStoreIC::MapRegister())); + + int receiver_count = types->length(); + int number_of_handled_maps = 0; + __ ld(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); + for (int current = 0; current < receiver_count; ++current) { + Handle<HeapType> type = types->at(current); + Handle<Map> map = IC::TypeToMap(*type, isolate()); + if (!map->is_deprecated()) { + number_of_handled_maps++; + // Check map and tail call if there's a match. + // Separate compare from branch, to provide path for above JumpIfSmi(). + __ Dsubu(match, map_reg, Operand(map)); + if (type->Is(HeapType::Number())) { + DCHECK(!number_case.is_unused()); + __ bind(&number_case); + } + __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq, match, + Operand(zero_reg)); + } + } + DCHECK(number_of_handled_maps != 0); + + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + // Return the generated code. + InlineCacheState state = + number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC; + return GetCode(kind(), type, name, state); +} + + +Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( + MapHandleList* receiver_maps, CodeHandleList* handler_stubs, + MapHandleList* transitioned_maps) { + Label miss; + __ JumpIfSmi(receiver(), &miss); + + int receiver_count = receiver_maps->length(); + __ ld(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); + for (int i = 0; i < receiver_count; ++i) { + if (transitioned_maps->at(i).is_null()) { + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET, eq, scratch1(), + Operand(receiver_maps->at(i))); + } else { + Label next_map; + __ Branch(&next_map, ne, scratch1(), Operand(receiver_maps->at(i))); + __ li(transition_map(), Operand(transitioned_maps->at(i))); + __ Jump(handler_stubs->at(i), RelocInfo::CODE_TARGET); + __ bind(&next_map); + } + } + + __ bind(&miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + + // Return the generated code. + return GetCode(kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC); +} + + +#undef __ +#define __ ACCESS_MASM(masm) + + +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + __ Push(StoreIC::ReceiverRegister(), StoreIC::NameRegister(), + StoreIC::ValueRegister()); + + __ li(a0, Operand(Smi::FromInt(strict_mode))); + __ Push(a0); + + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS64
diff --git a/src/mips64/ic-mips64.cc b/src/ic/mips64/ic-mips64.cc similarity index 78% rename from src/mips64/ic-mips64.cc rename to src/ic/mips64/ic-mips64.cc index 5187342..897880c 100644 --- a/src/mips64/ic-mips64.cc +++ b/src/ic/mips64/ic-mips64.cc
@@ -3,16 +3,14 @@ // found in the LICENSE file. - #include "src/v8.h" #if V8_TARGET_ARCH_MIPS64 -#include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/runtime.h" -#include "src/stub-cache.h" +#include "src/ic/ic.h" +#include "src/ic/ic-compiler.h" +#include "src/ic/stub-cache.h" namespace v8 { namespace internal { @@ -25,8 +23,7 @@ #define __ ACCESS_MASM(masm) -static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, - Register type, +static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type, Label* global_object) { // Register usage: // type: holds the receiver instance type on entry. @@ -51,12 +48,9 @@ // is not a global object and does not have interceptors. // The address returned from GenerateStringDictionaryProbes() in scratch2 // is used. -static void GenerateDictionaryLoad(MacroAssembler* masm, - Label* miss, - Register elements, - Register name, - Register result, - Register scratch1, +static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss, + Register elements, Register name, + Register result, Register scratch1, Register scratch2) { // Main use of the scratch registers. // scratch1: Used as temporary and to hold the capacity of the property @@ -65,23 +59,18 @@ Label done; // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss, - &done, - elements, - name, - scratch1, - scratch2); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, + name, scratch1, scratch2); // If probing finds an entry check that the value is a normal // property. __ bind(&done); // scratch2 == elements + 4 * index. - const int kElementsStartOffset = NameDictionary::kHeaderSize + + const int kElementsStartOffset = + NameDictionary::kHeaderSize + NameDictionary::kElementsStartIndex * kPointerSize; const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; __ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset)); - __ And(at, - scratch1, + __ And(at, scratch1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask))); __ Branch(miss, ne, at, Operand(zero_reg)); @@ -104,12 +93,9 @@ // is not a global object and does not have interceptors. // The address returned from GenerateStringDictionaryProbes() in scratch2 // is used. -static void GenerateDictionaryStore(MacroAssembler* masm, - Label* miss, - Register elements, - Register name, - Register value, - Register scratch1, +static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss, + Register elements, Register name, + Register value, Register scratch1, Register scratch2) { // Main use of the scratch registers. // scratch1: Used as temporary and to hold the capacity of the property @@ -118,18 +104,14 @@ Label done; // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss, - &done, - elements, - name, - scratch1, - scratch2); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements, + name, scratch1, scratch2); // If probing finds an entry in the dictionary check that the value // is a normal property that is not read only. __ bind(&done); // scratch2 == elements + 4 * index. - const int kElementsStartOffset = NameDictionary::kHeaderSize + + const int kElementsStartOffset = + NameDictionary::kHeaderSize + NameDictionary::kElementsStartIndex * kPointerSize; const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; const int kTypeAndReadOnlyMask = @@ -146,19 +128,17 @@ // Update the write barrier. Make sure not to clobber the value. __ mov(scratch1, value); - __ RecordWrite( - elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved, + kDontSaveFPRegs); } // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, - Register receiver, - Register map, + Register receiver, Register map, Register scratch, - int interceptor_bit, - Label* slow) { + int interceptor_bit, Label* slow) { // Check that the object isn't a smi. __ JumpIfSmi(receiver, slow); // Get the map of the receiver. @@ -180,14 +160,10 @@ // Loads an indexed element from a fast case array. // If not_fast_array is NULL, doesn't perform the elements map check. -static void GenerateFastArrayLoad(MacroAssembler* masm, - Register receiver, - Register key, - Register elements, - Register scratch1, - Register scratch2, - Register result, - Label* not_fast_array, +static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, + Register key, Register elements, + Register scratch1, Register scratch2, + Register result, Label* not_fast_array, Label* out_of_range) { // Register use: // @@ -227,7 +203,7 @@ // Fast case: Do the load. __ Daddu(scratch1, elements, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + Operand(FixedArray::kHeaderSize - kHeapObjectTag)); // The key is a smi. STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); __ SmiScale(at, key, kPointerSizeLog2); @@ -244,12 +220,9 @@ // Checks whether a key is an array index string or a unique name. // Falls through if a key is a unique name. -static void GenerateKeyNameCheck(MacroAssembler* masm, - Register key, - Register map, - Register hash, - Label* index_string, - Label* not_unique) { +static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, + Register map, Register hash, + Label* index_string, Label* not_unique) { // The key is not a smi. Label unique; // Is it a name? @@ -285,8 +258,8 @@ // Probe the stub cache. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::LOAD_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, receiver, name, a3, a4, a5, a6); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3, + a4, a5, a6); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -339,14 +312,10 @@ } -static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, - Register object, - Register key, - Register scratch1, - Register scratch2, - Register scratch3, - Label* unmapped_case, - Label* slow_case) { +static MemOperand GenerateMappedArgumentsLookup( + MacroAssembler* masm, Register object, Register key, Register scratch1, + Register scratch2, Register scratch3, Label* unmapped_case, + Label* slow_case) { Heap* heap = masm->isolate()->heap(); // Check that the receiver is a JSObject. Because of the map check @@ -364,11 +333,7 @@ // Load the elements into scratch1 and check its map. Handle<Map> arguments_map(heap->sloppy_arguments_elements_map()); __ ld(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); - __ CheckMap(scratch1, - scratch2, - arguments_map, - slow_case, - DONT_DO_SMI_CHECK); + __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK); // Check if element is in the range of mapped arguments. If not, jump // to the unmapped lookup with the parameter map in scratch1. __ ld(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); @@ -412,18 +377,13 @@ const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; Register backing_store = parameter_map; __ ld(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); - __ CheckMap(backing_store, - scratch, - Heap::kFixedArrayMapRootIndex, - slow_case, + __ CheckMap(backing_store, scratch, Heap::kFixedArrayMapRootIndex, slow_case, DONT_DO_SMI_CHECK); __ ld(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); __ Branch(slow_case, Ugreater_equal, key, Operand(scratch)); __ SmiUntag(scratch, key); __ dsll(scratch, scratch, kPointerSizeLog2); - __ Daddu(scratch, - scratch, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ Daddu(scratch, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ Daddu(scratch, backing_store, scratch); return MemOperand(scratch); } @@ -437,9 +397,8 @@ DCHECK(key.is(a2)); Label slow, notin; - MemOperand mapped_location = - GenerateMappedArgumentsLookup( - masm, receiver, key, a0, a3, a4, ¬in, &slow); + MemOperand mapped_location = GenerateMappedArgumentsLookup( + masm, receiver, key, a0, a3, a4, ¬in, &slow); __ Ret(USE_DELAY_SLOT); __ ld(v0, mapped_location); __ bind(¬in); @@ -469,8 +428,8 @@ __ sd(value, mapped_location); __ mov(t1, value); DCHECK_EQ(mapped_location.offset(), 0); - __ RecordWrite(a3, mapped_location.rm(), t1, - kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(a3, mapped_location.rm(), t1, kRAHasNotBeenSaved, + kDontSaveFPRegs); __ Ret(USE_DELAY_SLOT); __ mov(v0, value); // (In delay slot) return the value stored in v0. __ bind(¬in); @@ -481,8 +440,8 @@ __ sd(value, unmapped_location); __ mov(t1, value); DCHECK_EQ(unmapped_location.offset(), 0); - __ RecordWrite(a3, unmapped_location.rm(), t1, - kRAHasNotBeenSaved, kDontSaveFPRegs); + __ RecordWrite(a3, unmapped_location.rm(), t1, kRAHasNotBeenSaved, + kDontSaveFPRegs); __ Ret(USE_DELAY_SLOT); __ mov(v0, a0); // (In delay slot) return the value stored in v0. __ bind(&slow); @@ -528,9 +487,7 @@ const Register StoreIC::ValueRegister() { return a0; } -const Register KeyedStoreIC::MapRegister() { - return a3; -} +const Register KeyedStoreIC::MapRegister() { return a3; } void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { @@ -560,14 +517,13 @@ // Now the key is known to be a smi. This place is also jumped to from below // where a numeric string is converted to a smi. - GenerateKeyedLoadReceiverCheck( - masm, receiver, a0, a3, Map::kHasIndexedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, + Map::kHasIndexedInterceptor, &slow); // Check the receiver's map to see if it has fast elements. __ CheckFastElements(a0, a3, &check_number_dictionary); - GenerateFastArrayLoad( - masm, receiver, key, a0, a3, a4, v0, NULL, &slow); + GenerateFastArrayLoad(masm, receiver, key, a0, a3, a4, v0, NULL, &slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a4, a3); __ Ret(); @@ -586,17 +542,15 @@ // Slow case, key and receiver still in a2 and a1. __ bind(&slow); - __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), - 1, - a4, + __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, a4, a3); GenerateRuntimeGetProperty(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow); - GenerateKeyedLoadReceiverCheck( - masm, receiver, a0, a3, Map::kHasNamedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, + Map::kHasNamedInterceptor, &slow); // If the receiver is a fast-case object, check the keyed lookup @@ -677,10 +631,8 @@ __ dsll(at, a6, kPointerSizeLog2); __ daddu(at, receiver, at); __ ld(v0, MemOperand(at)); - __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), - 1, - a4, - a3); + __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, + a4, a3); __ Ret(); // Load property array property. @@ -690,10 +642,8 @@ __ dsll(v0, a5, kPointerSizeLog2); __ Daddu(v0, v0, a1); __ ld(v0, MemOperand(v0)); - __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), - 1, - a4, - a3); + __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, + a4, a3); __ Ret(); @@ -706,9 +656,7 @@ GenerateGlobalInstanceTypeCheck(masm, a0, &slow); // Load the property to v0. GenerateDictionaryLoad(masm, &slow, a3, key, v0, a5, a4); - __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), - 1, - a4, + __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1, a4, a3); __ Ret(); @@ -729,10 +677,7 @@ Register result = v0; DCHECK(!scratch.is(receiver) && !scratch.is(index)); - StringCharAtGenerator char_at_generator(receiver, - index, - scratch, - result, + StringCharAtGenerator char_at_generator(receiver, index, scratch, result, &miss, // When not a string. &miss, // When not a number. &miss, // When index out of range. @@ -748,31 +693,11 @@ } -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode. - __ Push(a0); - - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - static void KeyedStoreGenerateGenericHelper( - MacroAssembler* masm, - Label* fast_object, - Label* fast_double, - Label* slow, - KeyedStoreCheckMap check_map, - KeyedStoreIncrementLength increment_length, - Register value, - Register key, - Register receiver, - Register receiver_map, - Register elements_map, - Register elements) { + MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, + KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length, + Register value, Register key, Register receiver, Register receiver_map, + Register elements_map, Register elements) { Label transition_smi_elements; Label finish_object_store, non_double_value, transition_double_elements; Label fast_double_without_map_check; @@ -814,7 +739,7 @@ } // It's irrelevant whether array is smi-only or not when writing a smi. __ Daddu(address, elements, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ SmiScale(scratch_value, key, kPointerSizeLog2); __ Daddu(address, address, scratch_value); __ sd(value, MemOperand(address)); @@ -833,19 +758,14 @@ __ sd(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset)); } __ Daddu(address, elements, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ SmiScale(scratch_value, key, kPointerSizeLog2); __ Daddu(address, address, scratch_value); __ sd(value, MemOperand(address)); // Update write barrier for the elements array address. __ mov(scratch_value, value); // Preserve the value which is returned. - __ RecordWrite(elements, - address, - scratch_value, - kRAHasNotBeenSaved, - kDontSaveFPRegs, - EMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); + __ RecordWrite(elements, address, scratch_value, kRAHasNotBeenSaved, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); __ Ret(); __ bind(fast_double); @@ -860,8 +780,8 @@ // We have to see if the double version of the hole is present. If so // go to the runtime. __ Daddu(address, elements, - Operand(FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32) - - kHeapObjectTag)); + Operand(FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32) - + kHeapObjectTag)); __ SmiScale(at, key, kPointerSizeLog2); __ daddu(address, address, at); __ lw(scratch_value, MemOperand(address)); @@ -871,13 +791,10 @@ slow); __ bind(&fast_double_without_map_check); - __ StoreNumberToDoubleElements(value, - key, + __ StoreNumberToDoubleElements(value, key, elements, // Overwritten. a3, // Scratch regs... - a4, - a5, - &transition_double_elements); + a4, a5, &transition_double_elements); if (increment_length == kIncrementLength) { // Add 1 to receiver->length. __ Daddu(scratch_value, key, Operand(Smi::FromInt(1))); @@ -893,25 +810,19 @@ // Value is a double. Transition FAST_SMI_ELEMENTS -> // FAST_DOUBLE_ELEMENTS and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - receiver_map, - a4, - slow); - AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS); - ElementsTransitionGenerator::GenerateSmiToDouble( - masm, receiver, key, value, receiver_map, mode, slow); + __ LoadTransitionedArrayMapConditional( + FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, a4, slow); + AllocationSiteMode mode = + AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, + receiver_map, mode, slow); __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ jmp(&fast_double_without_map_check); __ bind(&non_double_value); // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - a4, - slow); + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, + receiver_map, a4, slow); mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); ElementsTransitionGenerator::GenerateMapChangeElementsTransition( masm, receiver, key, value, receiver_map, mode, slow); @@ -922,11 +833,8 @@ // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - receiver_map, - a4, - slow); + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, + receiver_map, a4, slow); mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); ElementsTransitionGenerator::GenerateDoubleToObject( masm, receiver, key, value, receiver_map, mode, slow); @@ -966,8 +874,8 @@ // Check that the receiver does not require access checks and is not observed. // The generic stub does not perform map checks or handle observed objects. __ lbu(a4, FieldMemOperand(receiver_map, Map::kBitFieldOffset)); - __ And(a4, a4, Operand(1 << Map::kIsAccessCheckNeeded | - 1 << Map::kIsObserved)); + __ And(a4, a4, + Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved)); __ Branch(&slow, ne, a4, Operand(zero_reg)); // Check if the object is a JS array or not. __ lbu(a4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset)); @@ -987,7 +895,7 @@ // a0: value. // a1: key. // a2: receiver. - GenerateRuntimeSetProperty(masm, strict_mode); + PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode); // Extra capacity case: Check if there is extra capacity to // perform the store and update the length. Used for adding one @@ -1001,8 +909,8 @@ __ ld(a4, FieldMemOperand(elements, FixedArray::kLengthOffset)); __ Branch(&slow, hs, key, Operand(a4)); __ ld(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ Branch( - &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex); + __ Branch(&check_if_double_array, ne, elements_map, + Heap::kFixedArrayMapRootIndex); __ jmp(&fast_object_grow); @@ -1020,14 +928,13 @@ __ ld(a4, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ Branch(&extra, hs, key, Operand(a4)); - KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, - &slow, kCheckMap, kDontIncrementLength, - value, key, receiver, receiver_map, - elements_map, elements); + KeyedStoreGenerateGenericHelper( + masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength, + value, key, receiver, receiver_map, elements_map, elements); KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, - &slow, kDontCheckMap, kIncrementLength, - value, key, receiver, receiver_map, - elements_map, elements); + &slow, kDontCheckMap, kIncrementLength, value, + key, receiver, receiver_map, elements_map, + elements); } @@ -1061,8 +968,10 @@ __ Push(receiver, key); // Receiver, key. // Perform tail call to the entry. - __ TailCallExternalReference(ExternalReference( - IC_Utility(kLoadElementWithInterceptor), masm->isolate()), 2, 1); + __ TailCallExternalReference( + ExternalReference(IC_Utility(kLoadElementWithInterceptor), + masm->isolate()), + 2, 1); __ bind(&slow); GenerateMiss(masm); @@ -1079,31 +988,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Push receiver, key and value for runtime call. - // We can't use MultiPush as the order of the registers is important. - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - // The slow case calls into the runtime to complete the store without causing - // an IC miss that would otherwise cause a transition to the generic stub. - ExternalReference ref = - ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - - __ TailCallExternalReference(ref, 3, 1); -} - - void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { Register receiver = ReceiverRegister(); Register name = NameRegister(); @@ -1114,8 +998,8 @@ // Get the receiver from the stack and probe the stub cache. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::STORE_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, receiver, name, a3, a4, a5, a6); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, a3, + a4, a5, a6); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -1125,8 +1009,8 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) { __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); // Perform tail call to the entry. - ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss), - masm->isolate()); + ExternalReference ref = + ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate()); __ TailCallExternalReference(ref, 3, 1); } @@ -1152,18 +1036,6 @@ } -void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - __ Push(ReceiverRegister(), NameRegister(), ValueRegister()); - - __ li(a0, Operand(Smi::FromInt(strict_mode))); - __ Push(a0); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - #undef __ @@ -1196,7 +1068,7 @@ // was inlined. Instr instr = Assembler::instr_at(andi_instruction_address); return Assembler::IsAndImmediate(instr) && - Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()); + Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()); } @@ -1223,8 +1095,8 @@ } if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, andi=%p, delta=%d\n", - address, andi_instruction_address, delta); + PrintF("[ patching ic at %p, andi=%p, delta=%d\n", address, + andi_instruction_address, delta); } Address patch_address = @@ -1259,8 +1131,7 @@ patcher.ChangeBranchCondition(eq); } } - - -} } // namespace v8::internal +} +} // namespace v8::internal #endif // V8_TARGET_ARCH_MIPS64
diff --git a/src/ic/mips64/stub-cache-mips64.cc b/src/ic/mips64/stub-cache-mips64.cc new file mode 100644 index 0000000..6d3fcb3 --- /dev/null +++ b/src/ic/mips64/stub-cache-mips64.cc
@@ -0,0 +1,168 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_MIPS64 + +#include "src/codegen.h" +#include "src/ic/stub-cache.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +static void ProbeTable(Isolate* isolate, MacroAssembler* masm, + Code::Flags flags, StubCache::Table table, + Register receiver, Register name, + // Number of the cache entry, not scaled. + Register offset, Register scratch, Register scratch2, + Register offset_scratch) { + ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); + ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); + ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); + + uint64_t key_off_addr = reinterpret_cast<uint64_t>(key_offset.address()); + uint64_t value_off_addr = reinterpret_cast<uint64_t>(value_offset.address()); + uint64_t map_off_addr = reinterpret_cast<uint64_t>(map_offset.address()); + + // Check the relative positions of the address fields. + DCHECK(value_off_addr > key_off_addr); + DCHECK((value_off_addr - key_off_addr) % 4 == 0); + DCHECK((value_off_addr - key_off_addr) < (256 * 4)); + DCHECK(map_off_addr > key_off_addr); + DCHECK((map_off_addr - key_off_addr) % 4 == 0); + DCHECK((map_off_addr - key_off_addr) < (256 * 4)); + + Label miss; + Register base_addr = scratch; + scratch = no_reg; + + // Multiply by 3 because there are 3 fields per entry (name, code, map). + __ dsll(offset_scratch, offset, 1); + __ Daddu(offset_scratch, offset_scratch, offset); + + // Calculate the base address of the entry. + __ li(base_addr, Operand(key_offset)); + __ dsll(at, offset_scratch, kPointerSizeLog2); + __ Daddu(base_addr, base_addr, at); + + // Check that the key in the entry matches the name. + __ ld(at, MemOperand(base_addr, 0)); + __ Branch(&miss, ne, name, Operand(at)); + + // Check the map matches. + __ ld(at, MemOperand(base_addr, map_off_addr - key_off_addr)); + __ ld(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ Branch(&miss, ne, at, Operand(scratch2)); + + // Get the code entry from the cache. + Register code = scratch2; + scratch2 = no_reg; + __ ld(code, MemOperand(base_addr, value_off_addr - key_off_addr)); + + // Check that the flags match what we're looking for. + Register flags_reg = base_addr; + base_addr = no_reg; + __ lw(flags_reg, FieldMemOperand(code, Code::kFlagsOffset)); + __ And(flags_reg, flags_reg, Operand(~Code::kFlagsNotUsedInLookup)); + __ Branch(&miss, ne, flags_reg, Operand(flags)); + +#ifdef DEBUG + if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { + __ jmp(&miss); + } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { + __ jmp(&miss); + } +#endif + + // Jump to the first instruction in the code stub. + __ Daddu(at, code, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ Jump(at); + + // Miss: fall through. + __ bind(&miss); +} + + +void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags, + Register receiver, Register name, + Register scratch, Register extra, Register extra2, + Register extra3) { + Isolate* isolate = masm->isolate(); + Label miss; + + // Make sure that code is valid. The multiplying code relies on the + // entry size being 12. + // DCHECK(sizeof(Entry) == 12); + // DCHECK(sizeof(Entry) == 3 * kPointerSize); + + // Make sure the flags does not name a specific type. + DCHECK(Code::ExtractTypeFromFlags(flags) == 0); + + // Make sure that there are no register conflicts. + DCHECK(!scratch.is(receiver)); + DCHECK(!scratch.is(name)); + DCHECK(!extra.is(receiver)); + DCHECK(!extra.is(name)); + DCHECK(!extra.is(scratch)); + DCHECK(!extra2.is(receiver)); + DCHECK(!extra2.is(name)); + DCHECK(!extra2.is(scratch)); + DCHECK(!extra2.is(extra)); + + // Check register validity. + DCHECK(!scratch.is(no_reg)); + DCHECK(!extra.is(no_reg)); + DCHECK(!extra2.is(no_reg)); + DCHECK(!extra3.is(no_reg)); + + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1, extra2, + extra3); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(receiver, &miss); + + // Get the map of the receiver and compute the hash. + __ ld(scratch, FieldMemOperand(name, Name::kHashFieldOffset)); + __ ld(at, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ Daddu(scratch, scratch, at); + uint64_t mask = kPrimaryTableSize - 1; + // We shift out the last two bits because they are not part of the hash and + // they are always 01 for maps. + __ dsrl(scratch, scratch, kCacheIndexShift); + __ Xor(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask)); + __ And(scratch, scratch, Operand(mask)); + + // Probe the primary table. + ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch, extra, + extra2, extra3); + + // Primary miss: Compute hash for secondary probe. + __ dsrl(at, name, kCacheIndexShift); + __ Dsubu(scratch, scratch, at); + uint64_t mask2 = kSecondaryTableSize - 1; + __ Daddu(scratch, scratch, Operand((flags >> kCacheIndexShift) & mask2)); + __ And(scratch, scratch, Operand(mask2)); + + // Probe the secondary table. + ProbeTable(isolate, masm, flags, kSecondary, receiver, name, scratch, extra, + extra2, extra3); + + // Cache miss: Fall-through and let caller handle the miss by + // entering the runtime system. + __ bind(&miss); + __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1, extra2, + extra3); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_MIPS64
diff --git a/src/ic/x64/handler-compiler-x64.cc b/src/ic/x64/handler-compiler-x64.cc new file mode 100644 index 0000000..d332bb4 --- /dev/null +++ b/src/ic/x64/handler-compiler-x64.cc
@@ -0,0 +1,878 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_X64 + +#include "src/ic/call-optimization.h" +#include "src/ic/handler-compiler.h" +#include "src/ic/ic.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + +void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( + MacroAssembler* masm, Label* miss_label, Register receiver, + Handle<Name> name, Register scratch0, Register scratch1) { + DCHECK(name->IsUniqueName()); + DCHECK(!receiver.is(scratch0)); + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->negative_lookups(), 1); + __ IncrementCounter(counters->negative_lookups_miss(), 1); + + __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); + + const int kInterceptorOrAccessCheckNeededMask = + (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); + + // Bail out if the receiver has a named interceptor or requires access checks. + __ testb(FieldOperand(scratch0, Map::kBitFieldOffset), + Immediate(kInterceptorOrAccessCheckNeededMask)); + __ j(not_zero, miss_label); + + // Check that receiver is a JSObject. + __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE); + __ j(below, miss_label); + + // Load properties array. + Register properties = scratch0; + __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); + + // Check that the properties array is a dictionary. + __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset), + Heap::kHashTableMapRootIndex); + __ j(not_equal, miss_label); + + Label done; + NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, + properties, name, scratch1); + __ bind(&done); + __ DecrementCounter(counters->negative_lookups_miss(), 1); +} + + +void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( + MacroAssembler* masm, int index, Register prototype, Label* miss) { + Isolate* isolate = masm->isolate(); + // Get the global function with the given index. + Handle<JSFunction> function( + JSFunction::cast(isolate->native_context()->get(index))); + + // Check we're still in the same context. + Register scratch = prototype; + const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); + __ movp(scratch, Operand(rsi, offset)); + __ movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset)); + __ Cmp(Operand(scratch, Context::SlotOffset(index)), function); + __ j(not_equal, miss); + + // Load its initial map. The global functions all have initial maps. + __ Move(prototype, Handle<Map>(function->initial_map())); + // Load the prototype from the initial map. + __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); +} + + +void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( + MacroAssembler* masm, Register receiver, Register result, Register scratch, + Label* miss_label) { + __ TryGetFunctionPrototype(receiver, result, miss_label); + if (!result.is(rax)) __ movp(rax, result); + __ ret(0); +} + + +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, + Handle<JSObject> holder_obj) { + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); + STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); + __ Push(name); + Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); + DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); + __ Move(kScratchRegister, interceptor); + __ Push(kScratchRegister); + __ Push(receiver); + __ Push(holder); +} + + +static void CompileCallLoadPropertyWithInterceptor( + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), + NamedLoadHandlerCompiler::kInterceptorArgsLength); +} + + +// Generate call to api function. +void PropertyHandlerCompiler::GenerateFastApiCall( + MacroAssembler* masm, const CallOptimization& optimization, + Handle<Map> receiver_map, Register receiver, Register scratch_in, + bool is_store, int argc, Register* values) { + DCHECK(optimization.is_simple_api_call()); + + __ PopReturnAddressTo(scratch_in); + // receiver + __ Push(receiver); + // Write the arguments to stack frame. + for (int i = 0; i < argc; i++) { + Register arg = values[argc - 1 - i]; + DCHECK(!receiver.is(arg)); + DCHECK(!scratch_in.is(arg)); + __ Push(arg); + } + __ PushReturnAddressFrom(scratch_in); + // Stack now matches JSFunction abi. + + // Abi for CallApiFunctionStub. + Register callee = rax; + Register call_data = rbx; + Register holder = rcx; + Register api_function_address = rdx; + Register scratch = rdi; // scratch_in is no longer valid. + + // Put holder in place. + CallOptimization::HolderLookup holder_lookup; + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + __ Move(holder, receiver); + break; + case CallOptimization::kHolderFound: + __ Move(holder, api_holder); + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); + break; + } + + Isolate* isolate = masm->isolate(); + Handle<JSFunction> function = optimization.constant_function(); + Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); + Handle<Object> call_data_obj(api_call_info->data(), isolate); + + // Put callee in place. + __ Move(callee, function); + + bool call_data_undefined = false; + // Put call_data in place. + if (isolate->heap()->InNewSpace(*call_data_obj)) { + __ Move(scratch, api_call_info); + __ movp(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset)); + } else if (call_data_obj->IsUndefined()) { + call_data_undefined = true; + __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); + } else { + __ Move(call_data, call_data_obj); + } + + // Put api_function_address in place. + Address function_address = v8::ToCData<Address>(api_call_info->callback()); + __ Move(api_function_address, function_address, + RelocInfo::EXTERNAL_REFERENCE); + + // Jump to stub. + CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); + __ TailCallStub(&stub); +} + + +void PropertyHandlerCompiler::GenerateCheckPropertyCell( + MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, + Register scratch, Label* miss) { + Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); + DCHECK(cell->value()->IsTheHole()); + __ Move(scratch, cell); + __ Cmp(FieldOperand(scratch, Cell::kValueOffset), + masm->isolate()->factory()->the_hole_value()); + __ j(not_equal, miss); +} + + +void NamedStoreHandlerCompiler::GenerateStoreViaSetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> setter) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); + + // Save value register, so we can restore it later. + __ Push(value()); + + if (!setter.is_null()) { + // Call the JavaScript setter with receiver and value on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ movp(receiver, + FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver); + __ Push(value()); + ParameterCount actual(1); + ParameterCount expected(setter); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); + } + + // We have to return the passed value, not the return value of the setter. + __ Pop(rax); + + // Restore context register. + __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + } + __ ret(0); +} + + +void NamedLoadHandlerCompiler::GenerateLoadViaGetter( + MacroAssembler* masm, Handle<HeapType> type, Register receiver, + Handle<JSFunction> getter) { + // ----------- S t a t e ------------- + // -- rax : receiver + // -- rcx : name + // -- rsp[0] : return address + // ----------------------------------- + { + FrameScope scope(masm, StackFrame::INTERNAL); + + if (!getter.is_null()) { + // Call the JavaScript getter with the receiver on the stack. + if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { + // Swap in the global receiver. + __ movp(receiver, + FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); + } + __ Push(receiver); + ParameterCount actual(0); + ParameterCount expected(getter); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); + } else { + // If we generate a global code snippet for deoptimization only, remember + // the place to continue after deoptimization. + masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); + } + + // Restore context register. + __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + } + __ ret(0); +} + + +void ElementHandlerCompiler::GenerateLoadDictionaryElement( + MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- rcx : key + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + DCHECK(rdx.is(LoadIC::ReceiverRegister())); + DCHECK(rcx.is(LoadIC::NameRegister())); + Label slow, miss; + + // This stub is meant to be tail-jumped to, the receiver must already + // have been verified by the caller to not be a smi. + + __ JumpIfNotSmi(rcx, &miss); + __ SmiToInteger32(rbx, rcx); + __ movp(rax, FieldOperand(rdx, JSObject::kElementsOffset)); + + // Check whether the elements is a number dictionary. + // rdx: receiver + // rcx: key + // rbx: key as untagged int32 + // rax: elements + __ LoadFromNumberDictionary(&slow, rax, rcx, rbx, r9, rdi, rax); + __ ret(0); + + __ bind(&slow); + // ----------- S t a t e ------------- + // -- rcx : key + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); + + __ bind(&miss); + // ----------- S t a t e ------------- + // -- rcx : key + // -- rdx : receiver + // -- rsp[0] : return address + // ----------------------------------- + TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); +} + + +static void StoreIC_PushArgs(MacroAssembler* masm) { + Register receiver = StoreIC::ReceiverRegister(); + Register name = StoreIC::NameRegister(); + Register value = StoreIC::ValueRegister(); + + DCHECK(!rbx.is(receiver) && !rbx.is(name) && !rbx.is(value)); + + __ PopReturnAddressTo(rbx); + __ Push(receiver); + __ Push(name); + __ Push(value); + __ PushReturnAddressFrom(rbx); +} + + +void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Return address is on the stack. + StoreIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) { + // Return address is on the stack. + StoreIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 3, 1); +} + + +#undef __ +#define __ ACCESS_MASM((masm())) + + +void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, + Handle<Name> name) { + if (!label->is_unused()) { + __ bind(label); + __ Move(this->name(), name); + } +} + + +// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if +// store is successful. +void NamedStoreHandlerCompiler::GenerateStoreTransition( + Handle<Map> transition, Handle<Name> name, Register receiver_reg, + Register storage_reg, Register value_reg, Register scratch1, + Register scratch2, Register unused, Label* miss_label, Label* slow) { + int descriptor = transition->LastAdded(); + DescriptorArray* descriptors = transition->instance_descriptors(); + PropertyDetails details = descriptors->GetDetails(descriptor); + Representation representation = details.representation(); + DCHECK(!representation.IsNone()); + + if (details.type() == CONSTANT) { + Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); + __ Cmp(value_reg, constant); + __ j(not_equal, miss_label); + } else if (representation.IsSmi()) { + __ JumpIfNotSmi(value_reg, miss_label); + } else if (representation.IsHeapObject()) { + __ JumpIfSmi(value_reg, miss_label); + HeapType* field_type = descriptors->GetFieldType(descriptor); + HeapType::Iterator<Map> it = field_type->Classes(); + if (!it.Done()) { + Label do_store; + while (true) { + __ CompareMap(value_reg, it.Current()); + it.Advance(); + if (it.Done()) { + __ j(not_equal, miss_label); + break; + } + __ j(equal, &do_store, Label::kNear); + } + __ bind(&do_store); + } + } else if (representation.IsDouble()) { + Label do_store, heap_number; + __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE); + + __ JumpIfNotSmi(value_reg, &heap_number); + __ SmiToInteger32(scratch1, value_reg); + __ Cvtlsi2sd(xmm0, scratch1); + __ jmp(&do_store); + + __ bind(&heap_number); + __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, + DONT_DO_SMI_CHECK); + __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); + + __ bind(&do_store); + __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); + } + + // Stub never generated for objects that require access checks. + DCHECK(!transition->is_access_check_needed()); + + // Perform map transition for the receiver if necessary. + if (details.type() == FIELD && + Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { + // The properties must be extended before we can store the value. + // We jump to a runtime call that extends the properties array. + __ PopReturnAddressTo(scratch1); + __ Push(receiver_reg); + __ Push(transition); + __ Push(value_reg); + __ PushReturnAddressFrom(scratch1); + __ TailCallExternalReference( + ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), + isolate()), + 3, 1); + return; + } + + // Update the map of the object. + __ Move(scratch1, transition); + __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); + + // Update the write barrier for the map field. + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + + if (details.type() == CONSTANT) { + DCHECK(value_reg.is(rax)); + __ ret(0); + return; + } + + int index = transition->instance_descriptors()->GetFieldIndex( + transition->LastAdded()); + + // Adjust for the number of properties stored in the object. Even in the + // face of a transition we can use the old map here because the size of the + // object and the number of in-object properties is not going to change. + index -= transition->inobject_properties(); + + // TODO(verwaest): Share this code as a code stub. + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + if (index < 0) { + // Set the property straight into the object. + int offset = transition->instance_size() + (index * kPointerSize); + if (representation.IsDouble()) { + __ movp(FieldOperand(receiver_reg, offset), storage_reg); + } else { + __ movp(FieldOperand(receiver_reg, offset), value_reg); + } + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ movp(storage_reg, value_reg); + } + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); + } + } else { + // Write to the properties array. + int offset = index * kPointerSize + FixedArray::kHeaderSize; + // Get the properties array (optimistically). + __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); + if (representation.IsDouble()) { + __ movp(FieldOperand(scratch1, offset), storage_reg); + } else { + __ movp(FieldOperand(scratch1, offset), value_reg); + } + + if (!representation.IsSmi()) { + // Update the write barrier for the array address. + if (!representation.IsDouble()) { + __ movp(storage_reg, value_reg); + } + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); + } + } + + // Return the value (register rax). + DCHECK(value_reg.is(rax)); + __ ret(0); +} + + +void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, + Register value_reg, + Label* miss_label) { + DCHECK(lookup->representation().IsHeapObject()); + __ JumpIfSmi(value_reg, miss_label); + HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); + Label do_store; + while (true) { + __ CompareMap(value_reg, it.Current()); + it.Advance(); + if (it.Done()) { + __ j(not_equal, miss_label); + break; + } + __ j(equal, &do_store, Label::kNear); + } + __ bind(&do_store); + + StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), + lookup->representation()); + GenerateTailCall(masm(), stub.GetCode()); +} + + +Register PropertyHandlerCompiler::CheckPrototypes( + Register object_reg, Register holder_reg, Register scratch1, + Register scratch2, Handle<Name> name, Label* miss, + PrototypeCheckType check) { + Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); + + // Make sure there's no overlap between holder and object registers. + DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); + + // Keep track of the current object in register reg. On the first + // iteration, reg is an alias for object_reg, on later iterations, + // it is an alias for holder_reg. + Register reg = object_reg; + int depth = 0; + + Handle<JSObject> current = Handle<JSObject>::null(); + if (type()->IsConstant()) { + current = Handle<JSObject>::cast(type()->AsConstant()->Value()); + } + Handle<JSObject> prototype = Handle<JSObject>::null(); + Handle<Map> current_map = receiver_map; + Handle<Map> holder_map(holder()->map()); + // Traverse the prototype chain and check the maps in the prototype chain for + // fast and global objects or do negative lookup for normal objects. + while (!current_map.is_identical_to(holder_map)) { + ++depth; + + // Only global objects and objects that do not require access + // checks are allowed in stubs. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + + prototype = handle(JSObject::cast(current_map->prototype())); + if (current_map->is_dictionary_map() && + !current_map->IsJSGlobalObjectMap()) { + DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. + if (!name->IsUniqueName()) { + DCHECK(name->IsString()); + name = factory()->InternalizeString(Handle<String>::cast(name)); + } + DCHECK(current.is_null() || + current->property_dictionary()->FindEntry(name) == + NameDictionary::kNotFound); + + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); + + __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + reg = holder_reg; // From now on the object will be in holder_reg. + __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } else { + bool in_new_space = heap()->InNewSpace(*prototype); + // Two possible reasons for loading the prototype from the map: + // (1) Can't store references to new space in code. + // (2) Handler is shared for all receivers with the same prototype + // map (but not necessarily the same prototype instance). + bool load_prototype_from_map = in_new_space || depth == 1; + if (load_prototype_from_map) { + // Save the map in scratch1 for later. + __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); + } + if (depth != 1 || check == CHECK_ALL_MAPS) { + __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); + } + + // Check access rights to the global object. This has to happen after + // the map check so that we know that the object is actually a global + // object. + // This allows us to install generated handlers for accesses to the + // global proxy (as opposed to using slow ICs). See corresponding code + // in LookupForRead(). + if (current_map->IsJSGlobalProxyMap()) { + __ CheckAccessGlobalProxy(reg, scratch2, miss); + } else if (current_map->IsJSGlobalObjectMap()) { + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); + } + reg = holder_reg; // From now on the object will be in holder_reg. + + if (load_prototype_from_map) { + __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); + } else { + __ Move(reg, prototype); + } + } + + // Go to the next object in the prototype chain. + current = prototype; + current_map = handle(current->map()); + } + + // Log the check depth. + LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); + + if (depth != 0 || check == CHECK_ALL_MAPS) { + // Check the holder map. + __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); + } + + // Perform security check for access to the global object. + DCHECK(current_map->IsJSGlobalProxyMap() || + !current_map->is_access_check_needed()); + if (current_map->IsJSGlobalProxyMap()) { + __ CheckAccessGlobalProxy(reg, scratch1, miss); + } + + // Return the register containing the holder. + return reg; +} + + +void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ jmp(&success); + __ bind(miss); + TailCallBuiltin(masm(), MissBuiltin(kind())); + __ bind(&success); + } +} + + +void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { + if (!miss->is_unused()) { + Label success; + __ jmp(&success); + GenerateRestoreName(miss, name); + TailCallBuiltin(masm(), MissBuiltin(kind())); + __ bind(&success); + } +} + + +void NamedLoadHandlerCompiler::GenerateLoadCallback( + Register reg, Handle<ExecutableAccessorInfo> callback) { + // Insert additional parameters into the stack frame above return address. + DCHECK(!scratch4().is(reg)); + __ PopReturnAddressTo(scratch4()); + + STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); + STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); + STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); + STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); + STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); + __ Push(receiver()); // receiver + if (heap()->InNewSpace(callback->data())) { + DCHECK(!scratch2().is(reg)); + __ Move(scratch2(), callback); + __ Push(FieldOperand(scratch2(), + ExecutableAccessorInfo::kDataOffset)); // data + } else { + __ Push(Handle<Object>(callback->data(), isolate())); + } + DCHECK(!kScratchRegister.is(reg)); + __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); + __ Push(kScratchRegister); // return value + __ Push(kScratchRegister); // return value default + __ PushAddress(ExternalReference::isolate_address(isolate())); + __ Push(reg); // holder + __ Push(name()); // name + // Save a pointer to where we pushed the arguments pointer. This will be + // passed as the const PropertyAccessorInfo& to the C++ callback. + + __ PushReturnAddressFrom(scratch4()); + + // Abi for CallApiGetter + Register api_function_address = r8; + Address getter_address = v8::ToCData<Address>(callback->getter()); + __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE); + + CallApiGetterStub stub(isolate()); + __ TailCallStub(&stub); +} + + +void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { + // Return the constant value. + __ Move(rax, value); + __ ret(0); +} + + +void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( + LookupIterator* it, Register holder_reg) { + DCHECK(holder()->HasNamedInterceptor()); + DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); + + // 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->property_kind() == 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()); + + // 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(), + IC::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); + __ 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()); + __ PopReturnAddressTo(scratch2()); + PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), + holder()); + __ PushReturnAddressFrom(scratch2()); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); + __ TailCallExternalReference( + ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( + Handle<JSObject> object, Handle<Name> name, + Handle<ExecutableAccessorInfo> callback) { + Register holder_reg = Frontend(receiver(), name); + + __ PopReturnAddressTo(scratch1()); + __ Push(receiver()); + __ Push(holder_reg); + __ Push(callback); // callback info + __ Push(name); + __ Push(value()); + __ PushReturnAddressFrom(scratch1()); + + // Do tail-call to the runtime system. + ExternalReference store_callback_property = + ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); + __ TailCallExternalReference(store_callback_property, 5, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( + Handle<Name> name) { + __ PopReturnAddressTo(scratch1()); + __ Push(receiver()); + __ Push(this->name()); + __ Push(value()); + __ PushReturnAddressFrom(scratch1()); + + // Do tail-call to the runtime system. + ExternalReference store_ic_property = ExternalReference( + IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); + __ TailCallExternalReference(store_ic_property, 3, 1); + + // Return the generated code. + return GetCode(kind(), Code::FAST, name); +} + + +Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } + + +Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( + Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { + Label miss; + FrontendHeader(receiver(), name, &miss); + + // Get the value from the cell. + Register result = StoreIC::ValueRegister(); + __ Move(result, cell); + __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); + + // Check for deleted property if property can actually be deleted. + if (is_configurable) { + __ CompareRoot(result, Heap::kTheHoleValueRootIndex); + __ j(equal, &miss); + } else if (FLAG_debug_code) { + __ CompareRoot(result, Heap::kTheHoleValueRootIndex); + __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); + } + + Counters* counters = isolate()->counters(); + __ IncrementCounter(counters->named_load_global_stub(), 1); + __ ret(0); + + FrontendFooter(name, &miss); + + // Return the generated code. + return GetCode(kind(), Code::NORMAL, name); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_X64
diff --git a/src/ic/x64/ic-compiler-x64.cc b/src/ic/x64/ic-compiler-x64.cc index 793bd0e..b2b02fb 100644 --- a/src/ic/x64/ic-compiler-x64.cc +++ b/src/ic/x64/ic-compiler-x64.cc
@@ -6,7 +6,6 @@ #if V8_TARGET_ARCH_X64 -#include "src/ic/call-optimization.h" #include "src/ic/ic-compiler.h" namespace v8 { @@ -15,697 +14,21 @@ #define __ ACCESS_MASM(masm) -void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( - MacroAssembler* masm, Label* miss_label, Register receiver, - Handle<Name> name, Register scratch0, Register scratch1) { - DCHECK(name->IsUniqueName()); - DCHECK(!receiver.is(scratch0)); - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->negative_lookups(), 1); - __ IncrementCounter(counters->negative_lookups_miss(), 1); +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + // Return address is on the stack. + DCHECK(!rbx.is(StoreIC::ReceiverRegister()) && + !rbx.is(StoreIC::NameRegister()) && !rbx.is(StoreIC::ValueRegister())); - __ movp(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); + __ PopReturnAddressTo(rbx); + __ Push(StoreIC::ReceiverRegister()); + __ Push(StoreIC::NameRegister()); + __ Push(StoreIC::ValueRegister()); + __ Push(Smi::FromInt(strict_mode)); + __ PushReturnAddressFrom(rbx); - const int kInterceptorOrAccessCheckNeededMask = - (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); - - // Bail out if the receiver has a named interceptor or requires access checks. - __ testb(FieldOperand(scratch0, Map::kBitFieldOffset), - Immediate(kInterceptorOrAccessCheckNeededMask)); - __ j(not_zero, miss_label); - - // Check that receiver is a JSObject. - __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE); - __ j(below, miss_label); - - // Load properties array. - Register properties = scratch0; - __ movp(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); - - // Check that the properties array is a dictionary. - __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset), - Heap::kHashTableMapRootIndex); - __ j(not_equal, miss_label); - - Label done; - NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, - properties, name, scratch1); - __ bind(&done); - __ DecrementCounter(counters->negative_lookups_miss(), 1); -} - - -void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype, Label* miss) { - Isolate* isolate = masm->isolate(); - // Get the global function with the given index. - Handle<JSFunction> function( - JSFunction::cast(isolate->native_context()->get(index))); - - // Check we're still in the same context. - Register scratch = prototype; - const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); - __ movp(scratch, Operand(rsi, offset)); - __ movp(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset)); - __ Cmp(Operand(scratch, Context::SlotOffset(index)), function); - __ j(not_equal, miss); - - // Load its initial map. The global functions all have initial maps. - __ Move(prototype, Handle<Map>(function->initial_map())); - // Load the prototype from the initial map. - __ movp(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); -} - - -void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype( - MacroAssembler* masm, Register receiver, Register result, Register scratch, - Label* miss_label) { - __ TryGetFunctionPrototype(receiver, result, miss_label); - if (!result.is(rax)) __ movp(rax, result); - __ ret(0); -} - - -static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, - Register holder, Register name, - Handle<JSObject> holder_obj) { - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3); - STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4); - __ Push(name); - Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); - DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor)); - __ Move(kScratchRegister, interceptor); - __ Push(kScratchRegister); - __ Push(receiver); - __ Push(holder); -} - - -static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, Register receiver, Register holder, Register name, - Handle<JSObject> holder_obj, IC::UtilityId id) { - PushInterceptorArguments(masm, receiver, holder, name, holder_obj); - __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), - NamedLoadHandlerCompiler::kInterceptorArgsLength); -} - - -// Generate call to api function. -void PropertyHandlerCompiler::GenerateFastApiCall( - MacroAssembler* masm, const CallOptimization& optimization, - Handle<Map> receiver_map, Register receiver, Register scratch_in, - bool is_store, int argc, Register* values) { - DCHECK(optimization.is_simple_api_call()); - - __ PopReturnAddressTo(scratch_in); - // receiver - __ Push(receiver); - // Write the arguments to stack frame. - for (int i = 0; i < argc; i++) { - Register arg = values[argc - 1 - i]; - DCHECK(!receiver.is(arg)); - DCHECK(!scratch_in.is(arg)); - __ Push(arg); - } - __ PushReturnAddressFrom(scratch_in); - // Stack now matches JSFunction abi. - - // Abi for CallApiFunctionStub. - Register callee = rax; - Register call_data = rbx; - Register holder = rcx; - Register api_function_address = rdx; - Register scratch = rdi; // scratch_in is no longer valid. - - // Put holder in place. - CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = - optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); - switch (holder_lookup) { - case CallOptimization::kHolderIsReceiver: - __ Move(holder, receiver); - break; - case CallOptimization::kHolderFound: - __ Move(holder, api_holder); - break; - case CallOptimization::kHolderNotFound: - UNREACHABLE(); - break; - } - - Isolate* isolate = masm->isolate(); - Handle<JSFunction> function = optimization.constant_function(); - Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); - Handle<Object> call_data_obj(api_call_info->data(), isolate); - - // Put callee in place. - __ Move(callee, function); - - bool call_data_undefined = false; - // Put call_data in place. - if (isolate->heap()->InNewSpace(*call_data_obj)) { - __ Move(scratch, api_call_info); - __ movp(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset)); - } else if (call_data_obj->IsUndefined()) { - call_data_undefined = true; - __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); - } else { - __ Move(call_data, call_data_obj); - } - - // Put api_function_address in place. - Address function_address = v8::ToCData<Address>(api_call_info->callback()); - __ Move(api_function_address, function_address, - RelocInfo::EXTERNAL_REFERENCE); - - // Jump to stub. - CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc); - __ TailCallStub(&stub); -} - - -void PropertyHandlerCompiler::GenerateCheckPropertyCell( - MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, - Register scratch, Label* miss) { - Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); - DCHECK(cell->value()->IsTheHole()); - __ Move(scratch, cell); - __ Cmp(FieldOperand(scratch, Cell::kValueOffset), - masm->isolate()->factory()->the_hole_value()); - __ j(not_equal, miss); -} - - -#undef __ -#define __ ACCESS_MASM((masm())) - - -void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label, - Handle<Name> name) { - if (!label->is_unused()) { - __ bind(label); - __ Move(this->name(), name); - } -} - - -// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if -// store is successful. -void NamedStoreHandlerCompiler::GenerateStoreTransition( - Handle<Map> transition, Handle<Name> name, Register receiver_reg, - Register storage_reg, Register value_reg, Register scratch1, - Register scratch2, Register unused, Label* miss_label, Label* slow) { - int descriptor = transition->LastAdded(); - DescriptorArray* descriptors = transition->instance_descriptors(); - PropertyDetails details = descriptors->GetDetails(descriptor); - Representation representation = details.representation(); - DCHECK(!representation.IsNone()); - - if (details.type() == CONSTANT) { - Handle<Object> constant(descriptors->GetValue(descriptor), isolate()); - __ Cmp(value_reg, constant); - __ j(not_equal, miss_label); - } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); - } else if (representation.IsHeapObject()) { - __ JumpIfSmi(value_reg, miss_label); - HeapType* field_type = descriptors->GetFieldType(descriptor); - HeapType::Iterator<Map> it = field_type->Classes(); - if (!it.Done()) { - Label do_store; - while (true) { - __ CompareMap(value_reg, it.Current()); - it.Advance(); - if (it.Done()) { - __ j(not_equal, miss_label); - break; - } - __ j(equal, &do_store, Label::kNear); - } - __ bind(&do_store); - } - } else if (representation.IsDouble()) { - Label do_store, heap_number; - __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE); - - __ JumpIfNotSmi(value_reg, &heap_number); - __ SmiToInteger32(scratch1, value_reg); - __ Cvtlsi2sd(xmm0, scratch1); - __ jmp(&do_store); - - __ bind(&heap_number); - __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label, - DONT_DO_SMI_CHECK); - __ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset)); - - __ bind(&do_store); - __ movsd(FieldOperand(storage_reg, HeapNumber::kValueOffset), xmm0); - } - - // Stub never generated for objects that require access checks. - DCHECK(!transition->is_access_check_needed()); - - // Perform map transition for the receiver if necessary. - if (details.type() == FIELD && - Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) { - // The properties must be extended before we can store the value. - // We jump to a runtime call that extends the properties array. - __ PopReturnAddressTo(scratch1); - __ Push(receiver_reg); - __ Push(transition); - __ Push(value_reg); - __ PushReturnAddressFrom(scratch1); - __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), - isolate()), - 3, 1); - return; - } - - // Update the map of the object. - __ Move(scratch1, transition); - __ movp(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); - - // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, - kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - - if (details.type() == CONSTANT) { - DCHECK(value_reg.is(rax)); - __ ret(0); - return; - } - - int index = transition->instance_descriptors()->GetFieldIndex( - transition->LastAdded()); - - // Adjust for the number of properties stored in the object. Even in the - // face of a transition we can use the old map here because the size of the - // object and the number of in-object properties is not going to change. - index -= transition->inobject_properties(); - - // TODO(verwaest): Share this code as a code stub. - SmiCheck smi_check = - representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; - if (index < 0) { - // Set the property straight into the object. - int offset = transition->instance_size() + (index * kPointerSize); - if (representation.IsDouble()) { - __ movp(FieldOperand(receiver_reg, offset), storage_reg); - } else { - __ movp(FieldOperand(receiver_reg, offset), value_reg); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ movp(storage_reg, value_reg); - } - __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, - kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); - } - } else { - // Write to the properties array. - int offset = index * kPointerSize + FixedArray::kHeaderSize; - // Get the properties array (optimistically). - __ movp(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); - if (representation.IsDouble()) { - __ movp(FieldOperand(scratch1, offset), storage_reg); - } else { - __ movp(FieldOperand(scratch1, offset), value_reg); - } - - if (!representation.IsSmi()) { - // Update the write barrier for the array address. - if (!representation.IsDouble()) { - __ movp(storage_reg, value_reg); - } - __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, - kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check); - } - } - - // Return the value (register rax). - DCHECK(value_reg.is(rax)); - __ ret(0); -} - - -void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup, - Register value_reg, - Label* miss_label) { - DCHECK(lookup->representation().IsHeapObject()); - __ JumpIfSmi(value_reg, miss_label); - HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes(); - Label do_store; - while (true) { - __ CompareMap(value_reg, it.Current()); - it.Advance(); - if (it.Done()) { - __ j(not_equal, miss_label); - break; - } - __ j(equal, &do_store, Label::kNear); - } - __ bind(&do_store); - - StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), - lookup->representation()); - GenerateTailCall(masm(), stub.GetCode()); -} - - -Register PropertyHandlerCompiler::CheckPrototypes( - Register object_reg, Register holder_reg, Register scratch1, - Register scratch2, Handle<Name> name, Label* miss, - PrototypeCheckType check) { - Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate())); - - // Make sure there's no overlap between holder and object registers. - DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && - !scratch2.is(scratch1)); - - // Keep track of the current object in register reg. On the first - // iteration, reg is an alias for object_reg, on later iterations, - // it is an alias for holder_reg. - Register reg = object_reg; - int depth = 0; - - Handle<JSObject> current = Handle<JSObject>::null(); - if (type()->IsConstant()) { - current = Handle<JSObject>::cast(type()->AsConstant()->Value()); - } - Handle<JSObject> prototype = Handle<JSObject>::null(); - Handle<Map> current_map = receiver_map; - Handle<Map> holder_map(holder()->map()); - // Traverse the prototype chain and check the maps in the prototype chain for - // fast and global objects or do negative lookup for normal objects. - while (!current_map.is_identical_to(holder_map)) { - ++depth; - - // Only global objects and objects that do not require access - // checks are allowed in stubs. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - - prototype = handle(JSObject::cast(current_map->prototype())); - if (current_map->is_dictionary_map() && - !current_map->IsJSGlobalObjectMap()) { - DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. - if (!name->IsUniqueName()) { - DCHECK(name->IsString()); - name = factory()->InternalizeString(Handle<String>::cast(name)); - } - DCHECK(current.is_null() || - current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); - - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, - scratch2); - - __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - reg = holder_reg; // From now on the object will be in holder_reg. - __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - } else { - bool in_new_space = heap()->InNewSpace(*prototype); - // Two possible reasons for loading the prototype from the map: - // (1) Can't store references to new space in code. - // (2) Handler is shared for all receivers with the same prototype - // map (but not necessarily the same prototype instance). - bool load_prototype_from_map = in_new_space || depth == 1; - if (load_prototype_from_map) { - // Save the map in scratch1 for later. - __ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); - } - if (depth != 1 || check == CHECK_ALL_MAPS) { - __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Check access rights to the global object. This has to happen after - // the map check so that we know that the object is actually a global - // object. - // This allows us to install generated handlers for accesses to the - // global proxy (as opposed to using slow ICs). See corresponding code - // in LookupForRead(). - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch2, miss); - } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), - name, scratch2, miss); - } - reg = holder_reg; // From now on the object will be in holder_reg. - - if (load_prototype_from_map) { - __ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); - } else { - __ Move(reg, prototype); - } - } - - // Go to the next object in the prototype chain. - current = prototype; - current_map = handle(current->map()); - } - - // Log the check depth. - LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); - - if (depth != 0 || check == CHECK_ALL_MAPS) { - // Check the holder map. - __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK); - } - - // Perform security check for access to the global object. - DCHECK(current_map->IsJSGlobalProxyMap() || - !current_map->is_access_check_needed()); - if (current_map->IsJSGlobalProxyMap()) { - __ CheckAccessGlobalProxy(reg, scratch1, miss); - } - - // Return the register containing the holder. - return reg; -} - - -void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ jmp(&success); - __ bind(miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) { - if (!miss->is_unused()) { - Label success; - __ jmp(&success); - GenerateRestoreName(miss, name); - TailCallBuiltin(masm(), MissBuiltin(kind())); - __ bind(&success); - } -} - - -void NamedLoadHandlerCompiler::GenerateLoadCallback( - Register reg, Handle<ExecutableAccessorInfo> callback) { - // Insert additional parameters into the stack frame above return address. - DCHECK(!scratch4().is(reg)); - __ PopReturnAddressTo(scratch4()); - - STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); - STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); - STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); - STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); - STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); - STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6); - __ Push(receiver()); // receiver - if (heap()->InNewSpace(callback->data())) { - DCHECK(!scratch2().is(reg)); - __ Move(scratch2(), callback); - __ Push(FieldOperand(scratch2(), - ExecutableAccessorInfo::kDataOffset)); // data - } else { - __ Push(Handle<Object>(callback->data(), isolate())); - } - DCHECK(!kScratchRegister.is(reg)); - __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); - __ Push(kScratchRegister); // return value - __ Push(kScratchRegister); // return value default - __ PushAddress(ExternalReference::isolate_address(isolate())); - __ Push(reg); // holder - __ Push(name()); // name - // Save a pointer to where we pushed the arguments pointer. This will be - // passed as the const PropertyAccessorInfo& to the C++ callback. - - __ PushReturnAddressFrom(scratch4()); - - // Abi for CallApiGetter - Register api_function_address = r8; - Address getter_address = v8::ToCData<Address>(callback->getter()); - __ Move(api_function_address, getter_address, RelocInfo::EXTERNAL_REFERENCE); - - CallApiGetterStub stub(isolate()); - __ TailCallStub(&stub); -} - - -void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) { - // Return the constant value. - __ Move(rax, value); - __ ret(0); -} - - -void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup( - LookupIterator* it, Register holder_reg) { - DCHECK(holder()->HasNamedInterceptor()); - DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined()); - - // 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->property_kind() == 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()); - - // 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(), - IC::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); - __ 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()); - __ PopReturnAddressTo(scratch2()); - PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(), - holder()); - __ PushReturnAddressFrom(scratch2()); - - ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptor), isolate()); - __ TailCallExternalReference( - ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1); -} - - -Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( - Handle<JSObject> object, Handle<Name> name, - Handle<ExecutableAccessorInfo> callback) { - Register holder_reg = Frontend(receiver(), name); - - __ PopReturnAddressTo(scratch1()); - __ Push(receiver()); - __ Push(holder_reg); - __ Push(callback); // callback info - __ Push(name); - __ Push(value()); - __ PushReturnAddressFrom(scratch1()); - - // Do tail-call to the runtime system. - ExternalReference store_callback_property = - ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); - __ TailCallExternalReference(store_callback_property, 5, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedStoreHandlerCompiler::GenerateStoreViaSetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> setter) { - // ----------- S t a t e ------------- - // -- rsp[0] : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Save value register, so we can restore it later. - __ Push(value()); - - if (!setter.is_null()) { - // Call the JavaScript setter with receiver and value on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ movp(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver); - __ Push(value()); - ParameterCount actual(1); - ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); - } - - // We have to return the passed value, not the return value of the setter. - __ Pop(rax); - - // Restore context register. - __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); } @@ -713,24 +36,6 @@ #define __ ACCESS_MASM(masm()) -Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor( - Handle<Name> name) { - __ PopReturnAddressTo(scratch1()); - __ Push(receiver()); - __ Push(this->name()); - __ Push(value()); - __ PushReturnAddressFrom(scratch1()); - - // Do tail-call to the runtime system. - ExternalReference store_ic_property = ExternalReference( - IC_Utility(IC::kStorePropertyWithInterceptor), isolate()); - __ TailCallExternalReference(store_ic_property, 3, 1); - - // Return the generated code. - return GetCode(kind(), Code::FAST, name); -} - - Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic( MapHandleList* receiver_maps, CodeHandleList* handler_stubs, MapHandleList* transitioned_maps) { @@ -763,83 +68,6 @@ } -Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } - - -#undef __ -#define __ ACCESS_MASM(masm) - - -void NamedLoadHandlerCompiler::GenerateLoadViaGetter( - MacroAssembler* masm, Handle<HeapType> type, Register receiver, - Handle<JSFunction> getter) { - // ----------- S t a t e ------------- - // -- rax : receiver - // -- rcx : name - // -- rsp[0] : return address - // ----------------------------------- - { - FrameScope scope(masm, StackFrame::INTERNAL); - - if (!getter.is_null()) { - // Call the JavaScript getter with the receiver on the stack. - if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { - // Swap in the global receiver. - __ movp(receiver, - FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); - } - __ Push(receiver); - ParameterCount actual(0); - ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, - NullCallWrapper()); - } else { - // If we generate a global code snippet for deoptimization only, remember - // the place to continue after deoptimization. - masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); - } - - // Restore context register. - __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); - } - __ ret(0); -} - - -#undef __ -#define __ ACCESS_MASM(masm()) - - -Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal( - Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) { - Label miss; - FrontendHeader(receiver(), name, &miss); - - // Get the value from the cell. - Register result = StoreIC::ValueRegister(); - __ Move(result, cell); - __ movp(result, FieldOperand(result, PropertyCell::kValueOffset)); - - // Check for deleted property if property can actually be deleted. - if (is_configurable) { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - __ j(equal, &miss); - } else if (FLAG_debug_code) { - __ CompareRoot(result, Heap::kTheHoleValueRootIndex); - __ Check(not_equal, kDontDeleteCellsCannotContainTheHole); - } - - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->named_load_global_stub(), 1); - __ ret(0); - - FrontendFooter(name, &miss); - - // Return the generated code. - return GetCode(kind(), Code::NORMAL, name); -} - - Handle<Code> PropertyICCompiler::CompilePolymorphic(TypeHandleList* types, CodeHandleList* handlers, Handle<Name> name, @@ -897,72 +125,6 @@ #undef __ -#define __ ACCESS_MASM(masm) - - -void ElementHandlerCompiler::GenerateLoadDictionaryElement( - MacroAssembler* masm) { - // ----------- S t a t e ------------- - // -- rcx : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - DCHECK(rdx.is(LoadIC::ReceiverRegister())); - DCHECK(rcx.is(LoadIC::NameRegister())); - Label slow, miss; - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - - __ JumpIfNotSmi(rcx, &miss); - __ SmiToInteger32(rbx, rcx); - __ movp(rax, FieldOperand(rdx, JSObject::kElementsOffset)); - - // Check whether the elements is a number dictionary. - // rdx: receiver - // rcx: key - // rbx: key as untagged int32 - // rax: elements - __ LoadFromNumberDictionary(&slow, rax, rcx, rbx, r9, rdi, rax); - __ ret(0); - - __ bind(&slow); - // ----------- S t a t e ------------- - // -- rcx : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow); - - __ bind(&miss); - // ----------- S t a t e ------------- - // -- rcx : key - // -- rdx : receiver - // -- rsp[0] : return address - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); -} - - -void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Return address is on the stack. - DCHECK(!rbx.is(StoreIC::ReceiverRegister()) && - !rbx.is(StoreIC::NameRegister()) && !rbx.is(StoreIC::ValueRegister())); - - __ PopReturnAddressTo(rbx); - __ Push(StoreIC::ReceiverRegister()); - __ Push(StoreIC::NameRegister()); - __ Push(StoreIC::ValueRegister()); - __ Push(Smi::FromInt(strict_mode)); - __ PushReturnAddressFrom(rbx); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - -#undef __ } } // namespace v8::internal
diff --git a/src/ic/x64/ic-x64.cc b/src/ic/x64/ic-x64.cc index 1abb931..7516882 100644 --- a/src/ic/x64/ic-x64.cc +++ b/src/ic/x64/ic-x64.cc
@@ -1012,26 +1012,6 @@ } -void StoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - -void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { - // Return address is on the stack. - StoreIC_PushArgs(masm); - - // Do tail-call to runtime routine. - ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); - __ TailCallExternalReference(ref, 3, 1); -} - - void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { // Return address is on the stack. StoreIC_PushArgs(masm);
diff --git a/src/ic/x87/OWNERS b/src/ic/x87/OWNERS new file mode 100644 index 0000000..dd9998b --- /dev/null +++ b/src/ic/x87/OWNERS
@@ -0,0 +1 @@ +weiliang.lin@intel.com
diff --git a/src/ic/x87/access-compiler-x87.cc b/src/ic/x87/access-compiler-x87.cc new file mode 100644 index 0000000..d30c257 --- /dev/null +++ b/src/ic/x87/access-compiler-x87.cc
@@ -0,0 +1,44 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_X87 + +#include "src/ic/access-compiler.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + +void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, + Handle<Code> code) { + __ jmp(code, RelocInfo::CODE_TARGET); +} + + +Register* PropertyAccessCompiler::load_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3, scratch4. + Register receiver = LoadIC::ReceiverRegister(); + Register name = LoadIC::NameRegister(); + static Register registers[] = {receiver, name, ebx, eax, edi, no_reg}; + return registers; +} + + +Register* PropertyAccessCompiler::store_calling_convention() { + // receiver, name, scratch1, scratch2, scratch3. + Register receiver = StoreIC::ReceiverRegister(); + Register name = StoreIC::NameRegister(); + DCHECK(ebx.is(KeyedStoreIC::MapRegister())); + static Register registers[] = {receiver, name, ebx, edi, no_reg}; + return registers; +} + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_X87
diff --git a/src/x87/stub-cache-x87.cc b/src/ic/x87/ic-compiler-x87.cc similarity index 76% rename from src/x87/stub-cache-x87.cc rename to src/ic/x87/ic-compiler-x87.cc index dedbaa6..5c68d54 100644 --- a/src/x87/stub-cache-x87.cc +++ b/src/ic/x87/ic-compiler-x87.cc
@@ -6,114 +6,14 @@ #if V8_TARGET_ARCH_X87 -#include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/stub-cache.h" +#include "src/ic/call-optimization.h" +#include "src/ic/ic-compiler.h" namespace v8 { namespace internal { #define __ ACCESS_MASM(masm) - -static void ProbeTable(Isolate* isolate, - MacroAssembler* masm, - Code::Flags flags, - StubCache::Table table, - Register name, - Register receiver, - // Number of the cache entry pointer-size scaled. - Register offset, - Register extra) { - ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); - ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); - ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); - - Label miss; - - // Multiply by 3 because there are 3 fields per entry (name, code, map). - __ lea(offset, Operand(offset, offset, times_2, 0)); - - if (extra.is_valid()) { - // Get the code entry from the cache. - __ mov(extra, Operand::StaticArray(offset, times_1, value_offset)); - - // Check that the key in the entry matches the name. - __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); - __ j(not_equal, &miss); - - // Check the map matches. - __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); - __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ j(not_equal, &miss); - - // Check that the flags match what we're looking for. - __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); - __ and_(offset, ~Code::kFlagsNotUsedInLookup); - __ cmp(offset, flags); - __ j(not_equal, &miss); - -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); - } -#endif - - // Jump to the first instruction in the code stub. - __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag)); - __ jmp(extra); - - __ bind(&miss); - } else { - // Save the offset on the stack. - __ push(offset); - - // Check that the key in the entry matches the name. - __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); - __ j(not_equal, &miss); - - // Check the map matches. - __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); - __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ j(not_equal, &miss); - - // Restore offset register. - __ mov(offset, Operand(esp, 0)); - - // Get the code entry from the cache. - __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); - - // Check that the flags match what we're looking for. - __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); - __ and_(offset, ~Code::kFlagsNotUsedInLookup); - __ cmp(offset, flags); - __ j(not_equal, &miss); - -#ifdef DEBUG - if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { - __ jmp(&miss); - } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { - __ jmp(&miss); - } -#endif - - // Restore offset and re-load code entry from cache. - __ pop(offset); - __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); - - // Jump to the first instruction in the code stub. - __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag)); - __ jmp(offset); - - // Pop at miss. - __ bind(&miss); - __ pop(offset); - } -} - - void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup( MacroAssembler* masm, Label* miss_label, Register receiver, Handle<Name> name, Register scratch0, Register scratch1) { @@ -147,89 +47,13 @@ __ j(not_equal, miss_label); Label done; - NameDictionaryLookupStub::GenerateNegativeLookup(masm, - miss_label, - &done, - properties, - name, - scratch1); + NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done, + properties, name, scratch1); __ bind(&done); __ DecrementCounter(counters->negative_lookups_miss(), 1); } -void StubCache::GenerateProbe(MacroAssembler* masm, - Code::Flags flags, - Register receiver, - Register name, - Register scratch, - Register extra, - Register extra2, - Register extra3) { - Label miss; - - // Assert that code is valid. The multiplying code relies on the entry size - // being 12. - DCHECK(sizeof(Entry) == 12); - - // Assert the flags do not name a specific type. - DCHECK(Code::ExtractTypeFromFlags(flags) == 0); - - // Assert that there are no register conflicts. - DCHECK(!scratch.is(receiver)); - DCHECK(!scratch.is(name)); - DCHECK(!extra.is(receiver)); - DCHECK(!extra.is(name)); - DCHECK(!extra.is(scratch)); - - // Assert scratch and extra registers are valid, and extra2/3 are unused. - DCHECK(!scratch.is(no_reg)); - DCHECK(extra2.is(no_reg)); - DCHECK(extra3.is(no_reg)); - - Register offset = scratch; - scratch = no_reg; - - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); - - // Check that the receiver isn't a smi. - __ JumpIfSmi(receiver, &miss); - - // Get the map of the receiver and compute the hash. - __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); - __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ xor_(offset, flags); - // We mask out the last two bits because they are not part of the hash and - // they are always 01 for maps. Also in the two 'and' instructions below. - __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); - // ProbeTable expects the offset to be pointer scaled, which it is, because - // the heap object tag size is 2 and the pointer size log 2 is also 2. - DCHECK(kCacheIndexShift == kPointerSizeLog2); - - // Probe the primary table. - ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra); - - // Primary miss: Compute hash for secondary probe. - __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); - __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); - __ xor_(offset, flags); - __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); - __ sub(offset, name); - __ add(offset, Immediate(flags)); - __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift); - - // Probe the secondary table. - ProbeTable( - isolate(), masm, flags, kSecondary, name, receiver, offset, extra); - - // Cache miss: Fall-through and let caller handle the miss by - // entering the runtime system. - __ bind(&miss); - __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); -} - - void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype( MacroAssembler* masm, int index, Register prototype, Label* miss) { // Get the global function with the given index. @@ -259,10 +83,8 @@ } -static void PushInterceptorArguments(MacroAssembler* masm, - Register receiver, - Register holder, - Register name, +static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, + Register holder, Register name, Handle<JSObject> holder_obj) { STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0); STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1); @@ -281,12 +103,8 @@ static void CompileCallLoadPropertyWithInterceptor( - MacroAssembler* masm, - Register receiver, - Register holder, - Register name, - Handle<JSObject> holder_obj, - IC::UtilityId id) { + MacroAssembler* masm, Register receiver, Register holder, Register name, + Handle<JSObject> holder_obj, IC::UtilityId id) { PushInterceptorArguments(masm, receiver, holder, name, holder_obj); __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()), NamedLoadHandlerCompiler::kInterceptorArgsLength); @@ -307,7 +125,7 @@ __ push(receiver); // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - Register arg = values[argc-1-i]; + Register arg = values[argc - 1 - i]; DCHECK(!receiver.is(arg)); DCHECK(!scratch_in.is(arg)); __ push(arg); @@ -325,16 +143,15 @@ // Put holder in place. CallOptimization::HolderLookup holder_lookup; - Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( - receiver_map, - &holder_lookup); + Handle<JSObject> api_holder = + optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup); switch (holder_lookup) { case CallOptimization::kHolderIsReceiver: __ Move(holder, receiver); break; case CallOptimization::kHolderFound: __ LoadHeapObject(holder, api_holder); - break; + break; case CallOptimization::kHolderNotFound: UNREACHABLE(); break; @@ -376,8 +193,7 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell( MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, Register scratch, Label* miss) { - Handle<PropertyCell> cell = - JSGlobalObject::EnsurePropertyCell(global, name); + Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name); DCHECK(cell->value()->IsTheHole()); Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value(); if (masm->serializer_enabled()) { @@ -391,12 +207,6 @@ } -void PropertyAccessCompiler::GenerateTailCall(MacroAssembler* masm, - Handle<Code> code) { - __ jmp(code, RelocInfo::CODE_TARGET); -} - - #undef __ #define __ ACCESS_MASM(masm()) @@ -427,7 +237,7 @@ __ CmpObject(value_reg, constant); __ j(not_equal, miss_label); } else if (representation.IsSmi()) { - __ JumpIfNotSmi(value_reg, miss_label); + __ JumpIfNotSmi(value_reg, miss_label); } else if (representation.IsHeapObject()) { __ JumpIfSmi(value_reg, miss_label); HeapType* field_type = descriptors->GetFieldType(descriptor); @@ -491,12 +301,8 @@ __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1); // Update the write barrier for the map field. - __ RecordWriteField(receiver_reg, - HeapObject::kMapOffset, - scratch1, - scratch2, - OMIT_REMEMBERED_SET, - OMIT_SMI_CHECK); + __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2, + OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); if (details.type() == CONSTANT) { DCHECK(value_reg.is(eax)); @@ -512,8 +318,8 @@ // object and the number of in-object properties is not going to change. index -= transition->inobject_properties(); - SmiCheck smi_check = representation.IsTagged() - ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; + SmiCheck smi_check = + representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK; // TODO(verwaest): Share this code as a code stub. if (index < 0) { // Set the property straight into the object. @@ -529,12 +335,8 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(receiver_reg, - offset, - storage_reg, - scratch1, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1, + EMIT_REMEMBERED_SET, smi_check); } } else { // Write to the properties array. @@ -552,12 +354,8 @@ if (!representation.IsDouble()) { __ mov(storage_reg, value_reg); } - __ RecordWriteField(scratch1, - offset, - storage_reg, - receiver_reg, - EMIT_REMEMBERED_SET, - smi_check); + __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg, + EMIT_REMEMBERED_SET, smi_check); } } @@ -599,8 +397,8 @@ // Make sure there's no overlap between holder and object registers. DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); - DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) - && !scratch2.is(scratch1)); + DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && + !scratch2.is(scratch1)); // Keep track of the current object in register reg. Register reg = object_reg; @@ -632,10 +430,10 @@ } DCHECK(current.is_null() || current->property_dictionary()->FindEntry(name) == - NameDictionary::kNotFound); + NameDictionary::kNotFound); - GenerateDictionaryNegativeLookup(masm(), miss, reg, name, - scratch1, scratch2); + GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1, + scratch2); __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); reg = holder_reg; // From now on the object will be in holder_reg. @@ -660,9 +458,8 @@ if (current_map->IsJSGlobalProxyMap()) { __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss); } else if (current_map->IsJSGlobalObjectMap()) { - GenerateCheckPropertyCell( - masm(), Handle<JSGlobalObject>::cast(current), name, - scratch2, miss); + GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current), + name, scratch2, miss); } if (load_prototype_from_map) { @@ -912,8 +709,8 @@ __ push(value()); ParameterCount actual(1); ParameterCount expected(setter); - __ InvokeFunction(setter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); + __ InvokeFunction(setter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); } else { // If we generate a global code snippet for deoptimization only, remember // the place to continue after deoptimization. @@ -978,25 +775,6 @@ } -Register* PropertyAccessCompiler::load_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3, scratch4. - Register receiver = LoadIC::ReceiverRegister(); - Register name = LoadIC::NameRegister(); - static Register registers[] = { receiver, name, ebx, eax, edi, no_reg }; - return registers; -} - - -Register* PropertyAccessCompiler::store_calling_convention() { - // receiver, name, scratch1, scratch2, scratch3. - Register receiver = StoreIC::ReceiverRegister(); - Register name = StoreIC::NameRegister(); - DCHECK(ebx.is(KeyedStoreIC::MapRegister())); - static Register registers[] = { receiver, name, ebx, edi, no_reg }; - return registers; -} - - Register NamedStoreHandlerCompiler::value() { return StoreIC::ValueRegister(); } @@ -1020,8 +798,8 @@ __ push(receiver); ParameterCount actual(0); ParameterCount expected(getter); - __ InvokeFunction(getter, expected, actual, - CALL_FUNCTION, NullCallWrapper()); + __ InvokeFunction(getter, expected, actual, CALL_FUNCTION, + NullCallWrapper()); } else { // If we generate a global code snippet for deoptimization only, remember // the place to continue after deoptimization. @@ -1179,8 +957,25 @@ } -#undef __ +void PropertyICCompiler::GenerateRuntimeSetProperty(MacroAssembler* masm, + StrictMode strict_mode) { + // Return address is on the stack. + DCHECK(!ebx.is(StoreIC::ReceiverRegister()) && + !ebx.is(StoreIC::NameRegister()) && !ebx.is(StoreIC::ValueRegister())); + __ pop(ebx); + __ push(StoreIC::ReceiverRegister()); + __ push(StoreIC::NameRegister()); + __ push(StoreIC::ValueRegister()); + __ push(Immediate(Smi::FromInt(strict_mode))); + __ push(ebx); // return address -} } // namespace v8::internal + // Do tail-call to runtime routine. + __ TailCallRuntime(Runtime::kSetProperty, 4, 1); +} + + +#undef __ +} +} // namespace v8::internal #endif // V8_TARGET_ARCH_X87
diff --git a/src/x87/ic-x87.cc b/src/ic/x87/ic-x87.cc similarity index 81% rename from src/x87/ic-x87.cc rename to src/ic/x87/ic-x87.cc index 4f7d810..8301588 100644 --- a/src/x87/ic-x87.cc +++ b/src/ic/x87/ic-x87.cc
@@ -7,9 +7,9 @@ #if V8_TARGET_ARCH_X87 #include "src/codegen.h" -#include "src/ic-inl.h" -#include "src/runtime.h" -#include "src/stub-cache.h" +#include "src/ic/ic.h" +#include "src/ic/ic-compiler.h" +#include "src/ic/stub-cache.h" namespace v8 { namespace internal { @@ -21,8 +21,7 @@ #define __ ACCESS_MASM(masm) -static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, - Register type, +static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type, Label* global_object) { // Register usage: // type: holds the receiver instance type on entry. @@ -42,13 +41,9 @@ // name is not internalized, and will jump to the miss_label in that // case. The generated code assumes that the receiver has slow // properties, is not a global object and does not have interceptors. -static void GenerateDictionaryLoad(MacroAssembler* masm, - Label* miss_label, - Register elements, - Register name, - Register r0, - Register r1, - Register result) { +static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, + Register elements, Register name, + Register r0, Register r1, Register result) { // Register use: // // elements - holds the property dictionary on entry and is unchanged. @@ -66,13 +61,8 @@ Label done; // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss_label, - &done, - elements, - name, - r0, - r1); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, + elements, name, r0, r1); // If probing finds an entry in the dictionary, r0 contains the // index into the dictionary. Check that the value is a normal @@ -99,13 +89,9 @@ // call if name is not internalized, and will jump to the miss_label in // that case. The generated code assumes that the receiver has slow // properties, is not a global object and does not have interceptors. -static void GenerateDictionaryStore(MacroAssembler* masm, - Label* miss_label, - Register elements, - Register name, - Register value, - Register r0, - Register r1) { +static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label, + Register elements, Register name, + Register value, Register r0, Register r1) { // Register use: // // elements - holds the property dictionary on entry and is clobbered. @@ -121,13 +107,8 @@ // Probe the dictionary. - NameDictionaryLookupStub::GeneratePositiveLookup(masm, - miss_label, - &done, - elements, - name, - r0, - r1); + NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, + elements, name, r0, r1); // If probing finds an entry in the dictionary, r0 contains the // index into the dictionary. Check that the value is a normal @@ -139,7 +120,8 @@ const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; const int kTypeAndReadOnlyMask = (PropertyDetails::TypeField::kMask | - PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; + PropertyDetails::AttributesField::encode(READ_ONLY)) + << kSmiTagSize; __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), Immediate(kTypeAndReadOnlyMask)); __ j(not_zero, miss_label); @@ -158,10 +140,8 @@ // Checks the receiver for special cases (value type, slow case bits). // Falls through for regular JS object. static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, - Register receiver, - Register map, - int interceptor_bit, - Label* slow) { + Register receiver, Register map, + int interceptor_bit, Label* slow) { // Register use: // receiver - holds the receiver and is unchanged. // Scratch registers: @@ -190,12 +170,9 @@ // Loads an indexed element from a fast case array. // If not_fast_array is NULL, doesn't perform the elements map check. -static void GenerateFastArrayLoad(MacroAssembler* masm, - Register receiver, - Register key, - Register scratch, - Register result, - Label* not_fast_array, +static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, + Register key, Register scratch, + Register result, Label* not_fast_array, Label* out_of_range) { // Register use: // receiver - holds the receiver and is unchanged. @@ -233,12 +210,9 @@ // Checks whether a key is an array index string or a unique name. // Falls through if the key is a unique name. -static void GenerateKeyNameCheck(MacroAssembler* masm, - Register key, - Register map, - Register hash, - Label* index_string, - Label* not_unique) { +static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, + Register map, Register hash, + Label* index_string, Label* not_unique) { // Register use: // key - holds the key and is unchanged. Assumed to be non-smi. // Scratch registers: @@ -266,13 +240,9 @@ } -static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, - Register object, - Register key, - Register scratch1, - Register scratch2, - Label* unmapped_case, - Label* slow_case) { +static Operand GenerateMappedArgumentsLookup( + MacroAssembler* masm, Register object, Register key, Register scratch1, + Register scratch2, Label* unmapped_case, Label* slow_case) { Heap* heap = masm->isolate()->heap(); Factory* factory = masm->isolate()->factory(); @@ -302,10 +272,8 @@ // Load element index and check whether it is the hole. const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize; - __ mov(scratch2, FieldOperand(scratch1, - key, - times_half_pointer_size, - kHeaderSize)); + __ mov(scratch2, + FieldOperand(scratch1, key, times_half_pointer_size, kHeaderSize)); __ cmp(scratch2, factory->the_hole_value()); __ j(equal, unmapped_case); @@ -314,9 +282,7 @@ // map in scratch1). const int kContextOffset = FixedArray::kHeaderSize; __ mov(scratch1, FieldOperand(scratch1, kContextOffset)); - return FieldOperand(scratch1, - scratch2, - times_half_pointer_size, + return FieldOperand(scratch1, scratch2, times_half_pointer_size, Context::kHeaderSize); } @@ -336,9 +302,7 @@ __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset)); __ cmp(key, scratch); __ j(greater_equal, slow_case); - return FieldOperand(backing_store, - key, - times_half_pointer_size, + return FieldOperand(backing_store, key, times_half_pointer_size, FixedArray::kHeaderSize); } @@ -359,8 +323,8 @@ // Now the key is known to be a smi. This place is also jumped to from // where a numeric string is converted to a smi. - GenerateKeyedLoadReceiverCheck( - masm, receiver, eax, Map::kHasIndexedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, eax, + Map::kHasIndexedInterceptor, &slow); // Check the receiver's map to see if it has fast elements. __ CheckFastElements(eax, &check_number_dictionary); @@ -379,9 +343,7 @@ // Check whether the elements is a number dictionary. // ebx: untagged index // eax: elements - __ CheckMap(eax, - isolate->factory()->hash_table_map(), - &slow, + __ CheckMap(eax, isolate->factory()->hash_table_map(), &slow, DONT_DO_SMI_CHECK); Label slow_pop_receiver; // Push receiver on the stack to free up a register for the dictionary @@ -404,8 +366,8 @@ __ bind(&check_name); GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); - GenerateKeyedLoadReceiverCheck( - masm, receiver, eax, Map::kHasNamedInterceptor, &slow); + GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor, + &slow); // If the receiver is a fast-case object, check the keyed lookup // cache. Otherwise probe the dictionary. @@ -492,8 +454,8 @@ // Load property array property. __ bind(&property_array_property); __ mov(eax, FieldOperand(receiver, JSObject::kPropertiesOffset)); - __ mov(eax, FieldOperand(eax, edi, times_pointer_size, - FixedArray::kHeaderSize)); + __ mov(eax, + FieldOperand(eax, edi, times_pointer_size, FixedArray::kHeaderSize)); __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1); __ ret(0); @@ -527,10 +489,7 @@ Register result = eax; DCHECK(!result.is(scratch)); - StringCharAtGenerator char_at_generator(receiver, - index, - scratch, - result, + StringCharAtGenerator char_at_generator(receiver, index, scratch, result, &miss, // When not a string. &miss, // When not a number. &miss, // When index out of range. @@ -597,9 +556,8 @@ Label slow, notin; Factory* factory = masm->isolate()->factory(); - Operand mapped_location = - GenerateMappedArgumentsLookup( - masm, receiver, key, ebx, eax, ¬in, &slow); + Operand mapped_location = GenerateMappedArgumentsLookup( + masm, receiver, key, ebx, eax, ¬in, &slow); __ mov(eax, mapped_location); __ Ret(); __ bind(¬in); @@ -625,9 +583,8 @@ DCHECK(name.is(ecx)); DCHECK(value.is(eax)); - Operand mapped_location = - GenerateMappedArgumentsLookup(masm, receiver, name, ebx, edi, ¬in, - &slow); + Operand mapped_location = GenerateMappedArgumentsLookup( + masm, receiver, name, ebx, edi, ¬in, &slow); __ mov(mapped_location, value); __ lea(ecx, mapped_location); __ mov(edx, value); @@ -648,12 +605,8 @@ static void KeyedStoreGenerateGenericHelper( - MacroAssembler* masm, - Label* fast_object, - Label* fast_double, - Label* slow, - KeyedStoreCheckMap check_map, - KeyedStoreIncrementLength increment_length) { + MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow, + KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length) { Label transition_smi_elements; Label finish_object_store, non_double_value, transition_double_elements; Label fast_double_without_map_check; @@ -713,8 +666,7 @@ __ mov(FixedArrayElementOperand(ebx, key), value); // Update write barrier for the elements array address. __ mov(edx, value); // Preserve the value which is returned. - __ RecordWriteArray( - ebx, edx, key, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); + __ RecordWriteArray(ebx, edx, key, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); __ ret(0); __ bind(fast_double); @@ -750,32 +702,24 @@ __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset)); // Transition the array appropriately depending on the value type. - __ CheckMap(value, - masm->isolate()->factory()->heap_number_map(), - &non_double_value, - DONT_DO_SMI_CHECK); + __ CheckMap(value, masm->isolate()->factory()->heap_number_map(), + &non_double_value, DONT_DO_SMI_CHECK); // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS // and complete the store. __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS, - ebx, - edi, - slow); - AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, - FAST_DOUBLE_ELEMENTS); - ElementsTransitionGenerator::GenerateSmiToDouble( - masm, receiver, key, value, ebx, mode, slow); + FAST_DOUBLE_ELEMENTS, ebx, edi, slow); + AllocationSiteMode mode = + AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value, + ebx, mode, slow); __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset)); __ jmp(&fast_double_without_map_check); __ bind(&non_double_value); // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, - FAST_ELEMENTS, - ebx, - edi, - slow); + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, ebx, + edi, slow); mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS); ElementsTransitionGenerator::GenerateMapChangeElementsTransition( masm, receiver, key, value, ebx, mode, slow); @@ -787,14 +731,11 @@ // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS __ mov(ebx, FieldOperand(receiver, HeapObject::kMapOffset)); - __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, - FAST_ELEMENTS, - ebx, - edi, - slow); + __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS, + ebx, edi, slow); mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); - ElementsTransitionGenerator::GenerateDoubleToObject( - masm, receiver, key, value, ebx, mode, slow); + ElementsTransitionGenerator::GenerateDoubleToObject(masm, receiver, key, + value, ebx, mode, slow); __ mov(ebx, FieldOperand(receiver, JSObject::kElementsOffset)); __ jmp(&finish_object_store); } @@ -838,7 +779,7 @@ // Slow case: call runtime. __ bind(&slow); - GenerateRuntimeSetProperty(masm, strict_mode); + PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode); // Extra capacity case: Check if there is extra capacity to // perform the store and update the length. Used for adding one @@ -877,8 +818,8 @@ __ cmp(key, FieldOperand(receiver, JSArray::kLengthOffset)); // Compare smis. __ j(above_equal, &extra); - KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, - &slow, kCheckMap, kDontIncrementLength); + KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, &slow, + kCheckMap, kDontIncrementLength); KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, &slow, kDontCheckMap, kIncrementLength); } @@ -894,8 +835,8 @@ // Probe the stub cache. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::LOAD_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, receiver, name, ebx, eax); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, receiver, name, ebx, + eax); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -990,9 +931,7 @@ const Register StoreIC::ValueRegister() { return eax; } -const Register KeyedStoreIC::MapRegister() { - return ebx; -} +const Register KeyedStoreIC::MapRegister() { return ebx; } void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { @@ -1008,9 +947,8 @@ // Return address is on the stack. Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::STORE_IC)); - masm->isolate()->stub_cache()->GenerateProbe( - masm, flags, ReceiverRegister(), NameRegister(), - ebx, no_reg); + masm->isolate()->stub_cache()->GenerateProbe(masm, flags, ReceiverRegister(), + NameRegister(), ebx, no_reg); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -1070,40 +1008,6 @@ } -void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Return address is on the stack. - DCHECK(!ebx.is(ReceiverRegister()) && !ebx.is(NameRegister()) && - !ebx.is(ValueRegister())); - __ pop(ebx); - __ push(ReceiverRegister()); - __ push(NameRegister()); - __ push(ValueRegister()); - __ push(Immediate(Smi::FromInt(strict_mode))); - __ push(ebx); // return address - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - -void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm, - StrictMode strict_mode) { - // Return address is on the stack. - DCHECK(!ebx.is(ReceiverRegister()) && !ebx.is(NameRegister()) && - !ebx.is(ValueRegister())); - __ pop(ebx); - __ push(ReceiverRegister()); - __ push(NameRegister()); - __ push(ValueRegister()); - __ push(Immediate(Smi::FromInt(strict_mode))); - __ push(ebx); // return address - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kSetProperty, 4, 1); -} - - void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { // Return address is on the stack. StoreIC_PushArgs(masm); @@ -1186,8 +1090,8 @@ // condition code uses at the patched jump. uint8_t delta = *reinterpret_cast<uint8_t*>(delta_address); if (FLAG_trace_ic) { - PrintF("[ patching ic at %p, test=%p, delta=%d\n", - address, test_instruction_address, delta); + PrintF("[ patching ic at %p, test=%p, delta=%d\n", address, + test_instruction_address, delta); } // Patch with a short conditional jump. Enabling means switching from a short @@ -1195,17 +1099,17 @@ // reverse operation of that. Address jmp_address = test_instruction_address - delta; DCHECK((check == ENABLE_INLINED_SMI_CHECK) - ? (*jmp_address == Assembler::kJncShortOpcode || - *jmp_address == Assembler::kJcShortOpcode) - : (*jmp_address == Assembler::kJnzShortOpcode || - *jmp_address == Assembler::kJzShortOpcode)); - Condition cc = (check == ENABLE_INLINED_SMI_CHECK) - ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) - : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); + ? (*jmp_address == Assembler::kJncShortOpcode || + *jmp_address == Assembler::kJcShortOpcode) + : (*jmp_address == Assembler::kJnzShortOpcode || + *jmp_address == Assembler::kJzShortOpcode)); + Condition cc = + (check == ENABLE_INLINED_SMI_CHECK) + ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) + : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); } - - -} } // namespace v8::internal +} +} // namespace v8::internal #endif // V8_TARGET_ARCH_X87
diff --git a/src/ic/x87/stub-cache-x87.cc b/src/ic/x87/stub-cache-x87.cc new file mode 100644 index 0000000..8b4f0fd --- /dev/null +++ b/src/ic/x87/stub-cache-x87.cc
@@ -0,0 +1,183 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#if V8_TARGET_ARCH_X87 + +#include "src/codegen.h" +#include "src/ic/stub-cache.h" + +namespace v8 { +namespace internal { + +#define __ ACCESS_MASM(masm) + + +static void ProbeTable(Isolate* isolate, MacroAssembler* masm, + Code::Flags flags, StubCache::Table table, Register name, + Register receiver, + // Number of the cache entry pointer-size scaled. + Register offset, Register extra) { + ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); + ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); + ExternalReference map_offset(isolate->stub_cache()->map_reference(table)); + + Label miss; + + // Multiply by 3 because there are 3 fields per entry (name, code, map). + __ lea(offset, Operand(offset, offset, times_2, 0)); + + if (extra.is_valid()) { + // Get the code entry from the cache. + __ mov(extra, Operand::StaticArray(offset, times_1, value_offset)); + + // Check that the key in the entry matches the name. + __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); + __ j(not_equal, &miss); + + // Check the map matches. + __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); + __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); + __ j(not_equal, &miss); + + // Check that the flags match what we're looking for. + __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); + __ and_(offset, ~Code::kFlagsNotUsedInLookup); + __ cmp(offset, flags); + __ j(not_equal, &miss); + +#ifdef DEBUG + if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { + __ jmp(&miss); + } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { + __ jmp(&miss); + } +#endif + + // Jump to the first instruction in the code stub. + __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag)); + __ jmp(extra); + + __ bind(&miss); + } else { + // Save the offset on the stack. + __ push(offset); + + // Check that the key in the entry matches the name. + __ cmp(name, Operand::StaticArray(offset, times_1, key_offset)); + __ j(not_equal, &miss); + + // Check the map matches. + __ mov(offset, Operand::StaticArray(offset, times_1, map_offset)); + __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset)); + __ j(not_equal, &miss); + + // Restore offset register. + __ mov(offset, Operand(esp, 0)); + + // Get the code entry from the cache. + __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); + + // Check that the flags match what we're looking for. + __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); + __ and_(offset, ~Code::kFlagsNotUsedInLookup); + __ cmp(offset, flags); + __ j(not_equal, &miss); + +#ifdef DEBUG + if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { + __ jmp(&miss); + } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { + __ jmp(&miss); + } +#endif + + // Restore offset and re-load code entry from cache. + __ pop(offset); + __ mov(offset, Operand::StaticArray(offset, times_1, value_offset)); + + // Jump to the first instruction in the code stub. + __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag)); + __ jmp(offset); + + // Pop at miss. + __ bind(&miss); + __ pop(offset); + } +} + + +void StubCache::GenerateProbe(MacroAssembler* masm, Code::Flags flags, + Register receiver, Register name, + Register scratch, Register extra, Register extra2, + Register extra3) { + Label miss; + + // Assert that code is valid. The multiplying code relies on the entry size + // being 12. + DCHECK(sizeof(Entry) == 12); + + // Assert the flags do not name a specific type. + DCHECK(Code::ExtractTypeFromFlags(flags) == 0); + + // Assert that there are no register conflicts. + DCHECK(!scratch.is(receiver)); + DCHECK(!scratch.is(name)); + DCHECK(!extra.is(receiver)); + DCHECK(!extra.is(name)); + DCHECK(!extra.is(scratch)); + + // Assert scratch and extra registers are valid, and extra2/3 are unused. + DCHECK(!scratch.is(no_reg)); + DCHECK(extra2.is(no_reg)); + DCHECK(extra3.is(no_reg)); + + Register offset = scratch; + scratch = no_reg; + + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); + + // Check that the receiver isn't a smi. + __ JumpIfSmi(receiver, &miss); + + // Get the map of the receiver and compute the hash. + __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); + __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); + __ xor_(offset, flags); + // We mask out the last two bits because they are not part of the hash and + // they are always 01 for maps. Also in the two 'and' instructions below. + __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); + // ProbeTable expects the offset to be pointer scaled, which it is, because + // the heap object tag size is 2 and the pointer size log 2 is also 2. + DCHECK(kCacheIndexShift == kPointerSizeLog2); + + // Probe the primary table. + ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra); + + // Primary miss: Compute hash for secondary probe. + __ mov(offset, FieldOperand(name, Name::kHashFieldOffset)); + __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset)); + __ xor_(offset, flags); + __ and_(offset, (kPrimaryTableSize - 1) << kCacheIndexShift); + __ sub(offset, name); + __ add(offset, Immediate(flags)); + __ and_(offset, (kSecondaryTableSize - 1) << kCacheIndexShift); + + // Probe the secondary table. + ProbeTable(isolate(), masm, flags, kSecondary, name, receiver, offset, extra); + + // Cache miss: Fall-through and let caller handle the miss by + // entering the runtime system. + __ bind(&miss); + __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); +} + + +#undef __ +} +} // namespace v8::internal + +#endif // V8_TARGET_ARCH_X87
diff --git a/src/isolate.cc b/src/isolate.cc index fc8d34d..0f1f702 100644 --- a/src/isolate.cc +++ b/src/isolate.cc
@@ -1057,7 +1057,7 @@ // probably not a valid Error object. In that case, we fall through // and capture the stack trace at this throw site. LookupIterator lookup(exception_handle, key, - LookupIterator::CHECK_PROPERTY); + LookupIterator::OWN_PROPERTY); Handle<Object> stack_trace_property; if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) && stack_trace_property->IsJSArray()) {
diff --git a/src/json-stringifier.h b/src/json-stringifier.h index 1970c2d..1b108ce 100644 --- a/src/json-stringifier.h +++ b/src/json-stringifier.h
@@ -340,7 +340,7 @@ MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction( Handle<Object> object, Handle<Object> key) { LookupIterator it(object, tojson_string_, - LookupIterator::CHECK_DERIVED_SKIP_INTERCEPTOR); + LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); Handle<Object> fun; ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); if (!fun->IsJSFunction()) return object;
diff --git a/src/lookup-inl.h b/src/lookup-inl.h index a32295b..d87221e 100644 --- a/src/lookup-inl.h +++ b/src/lookup-inl.h
@@ -19,11 +19,11 @@ DCHECK(!next->map()->IsGlobalObjectMap() || next->map()->is_hidden_prototype()); - if (!check_derived() && + if (!check_prototype_chain() && !(check_hidden() && next->map()->is_hidden_prototype()) && // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even // when not checking other hidden prototypes. - !(map->IsJSGlobalProxyMap() && next->IsJSGlobalObject())) { + !map->IsJSGlobalProxyMap()) { return NULL; }
diff --git a/src/lookup.cc b/src/lookup.cc index 56001c3..5bce620 100644 --- a/src/lookup.cc +++ b/src/lookup.cc
@@ -35,8 +35,8 @@ // Either was found in the receiver, or the receiver has no prototype. if (holder == NULL) return; - maybe_holder_ = handle(holder); - holder_map_ = handle(map); + maybe_holder_ = handle(holder, isolate_); + holder_map_ = handle(map, isolate_); } @@ -53,7 +53,7 @@ Handle<Map> LookupIterator::GetReceiverMap() const { Handle<Object> receiver = GetReceiver(); if (receiver->IsNumber()) return isolate_->factory()->heap_number_map(); - return handle(Handle<HeapObject>::cast(receiver)->map()); + return handle(Handle<HeapObject>::cast(receiver)->map(), isolate_); } @@ -184,7 +184,7 @@ } transition_map_ = Map::TransitionToDataProperty( - handle(receiver->map()), name_, value, attributes, store_mode); + handle(receiver->map(), isolate_), name_, value, attributes, store_mode); state_ = TRANSITION; } @@ -209,8 +209,9 @@ // observable. Handle<JSObject> receiver = GetStoreTarget(); maybe_holder_ = receiver; - holder_map_ = Map::TransitionToAccessorProperty( - handle(receiver->map()), name_, component, accessor, attributes); + holder_map_ = + Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_), + name_, component, accessor, attributes); JSObject::MigrateToMap(receiver, holder_map_); ReloadPropertyInformation(); @@ -243,7 +244,7 @@ JSObject::SetNormalizedProperty(receiver, name_, pair, details); JSObject::ReoptimizeIfPrototype(receiver); - holder_map_ = handle(receiver->map()); + holder_map_ = handle(receiver->map(), isolate_); ReloadPropertyInformation(); } @@ -251,7 +252,7 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); // Optimization that only works if configuration_ is not mutable. - if (!check_derived()) return true; + if (!check_prototype_chain()) return true; DisallowHeapAllocation no_gc; Handle<Object> receiver = GetReceiver(); if (!receiver->IsJSReceiver()) return false; @@ -272,16 +273,6 @@ } -bool LookupIterator::HolderIsNonGlobalHiddenPrototype() const { - if (!HolderIsReceiverOrHiddenPrototype()) return false; - Handle<Object> receiver = GetReceiver(); - Handle<JSReceiver> holder = GetHolder<JSReceiver>(); - if (receiver.is_identical_to(holder)) return false; - if (receiver->IsJSGlobalProxy()) return !holder->IsJSGlobalObject(); - return true; -} - - Handle<Object> LookupIterator::FetchValue() const { Object* result = NULL; Handle<JSObject> holder = GetHolder<JSObject>();
diff --git a/src/lookup.h b/src/lookup.h index d6fa35b..bf2fb1b 100644 --- a/src/lookup.h +++ b/src/lookup.h
@@ -16,19 +16,21 @@ public: enum Configuration { // Configuration bits. - CHECK_HIDDEN_PROPERTY = 1 << 0, - CHECK_DERIVED_PROPERTY = 1 << 1, - CHECK_INTERCEPTOR = 1 << 2, - CHECK_ACCESS_CHECK = 1 << 3, + kAccessCheck = 1 << 0, + kHidden = 1 << 1, + kInterceptor = 1 << 2, + kPrototypeChain = 1 << 3, // Convience combinations of bits. - CHECK_PROPERTY = 0, - CHECK_OWN = CHECK_ACCESS_CHECK | CHECK_INTERCEPTOR, - CHECK_HIDDEN_SKIP_INTERCEPTOR = CHECK_HIDDEN_PROPERTY | CHECK_ACCESS_CHECK, - CHECK_DERIVED_SKIP_INTERCEPTOR = - CHECK_HIDDEN_SKIP_INTERCEPTOR | CHECK_DERIVED_PROPERTY, - CHECK_DERIVED = CHECK_DERIVED_SKIP_INTERCEPTOR | CHECK_INTERCEPTOR, - CHECK_HIDDEN = CHECK_HIDDEN_SKIP_INTERCEPTOR | CHECK_INTERCEPTOR + OWN_PROPERTY = 0, + OWN_SKIP_INTERCEPTOR = kAccessCheck, + OWN = kAccessCheck | kInterceptor, + HIDDEN_PROPERTY = kHidden, + HIDDEN_SKIP_INTERCEPTOR = kAccessCheck | kHidden, + HIDDEN = kAccessCheck | kHidden | kInterceptor, + PROTOTYPE_CHAIN_PROPERTY = kHidden | kPrototypeChain, + PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kAccessCheck | kHidden | kPrototypeChain, + PROTOTYPE_CHAIN = kAccessCheck | kHidden | kPrototypeChain | kInterceptor }; enum State { @@ -53,20 +55,8 @@ DESCRIPTOR }; - explicit LookupIterator(const LookupIterator* other) - : configuration_(other->configuration_), - state_(other->state_), - property_kind_(other->property_kind_), - property_encoding_(other->property_encoding_), - property_details_(other->property_details_), - isolate_(other->isolate_), - name_(other->name_), - holder_map_(other->holder_map_), - maybe_receiver_(other->maybe_receiver_), - maybe_holder_(other->maybe_holder_) {} - LookupIterator(Handle<Object> receiver, Handle<Name> name, - Configuration configuration = CHECK_DERIVED) + Configuration configuration = PROTOTYPE_CHAIN) : configuration_(ComputeConfiguration(configuration, name)), state_(NOT_FOUND), property_kind_(DATA), @@ -77,14 +67,14 @@ maybe_receiver_(receiver), number_(DescriptorArray::kNotFound) { Handle<JSReceiver> root = GetRoot(); - holder_map_ = handle(root->map()); + holder_map_ = handle(root->map(), isolate_); maybe_holder_ = root; Next(); } LookupIterator(Handle<Object> receiver, Handle<Name> name, Handle<JSReceiver> holder, - Configuration configuration = CHECK_DERIVED) + Configuration configuration = PROTOTYPE_CHAIN) : configuration_(ComputeConfiguration(configuration, name)), state_(NOT_FOUND), property_kind_(DATA), @@ -92,7 +82,7 @@ property_details_(NONE, NORMAL, Representation::None()), isolate_(name->GetIsolate()), name_(name), - holder_map_(holder->map()), + holder_map_(holder->map(), isolate_), maybe_receiver_(receiver), maybe_holder_(holder), number_(DescriptorArray::kNotFound) { @@ -110,7 +100,6 @@ state_ = NOT_FOUND; } - Heap* heap() const { return isolate_->heap(); } Factory* factory() const { return isolate_->factory(); } Handle<Object> GetReceiver() const { return maybe_receiver_.ToHandleChecked(); @@ -128,7 +117,6 @@ } Handle<JSReceiver> GetRoot() const; bool HolderIsReceiverOrHiddenPrototype() const; - bool HolderIsNonGlobalHiddenPrototype() const; /* ACCESS_CHECK */ bool HasAccess(v8::AccessType access_type) const; @@ -203,17 +191,15 @@ bool is_guaranteed_to_have_holder() const { return !maybe_receiver_.is_null(); } - bool check_interceptor() const { - return !IsBootstrapping() && (configuration_ & CHECK_INTERCEPTOR) != 0; - } - bool check_derived() const { - return (configuration_ & CHECK_DERIVED_PROPERTY) != 0; - } - bool check_hidden() const { - return (configuration_ & CHECK_HIDDEN_PROPERTY) != 0; - } bool check_access_check() const { - return (configuration_ & CHECK_ACCESS_CHECK) != 0; + return (configuration_ & kAccessCheck) != 0; + } + bool check_hidden() const { return (configuration_ & kHidden) != 0; } + bool check_interceptor() const { + return !IsBootstrapping() && (configuration_ & kInterceptor) != 0; + } + bool check_prototype_chain() const { + return (configuration_ & kPrototypeChain) != 0; } int descriptor_number() const { DCHECK(has_property_); @@ -229,7 +215,7 @@ static Configuration ComputeConfiguration( Configuration configuration, Handle<Name> name) { if (name->IsOwn()) { - return static_cast<Configuration>(configuration & CHECK_HIDDEN); + return static_cast<Configuration>(configuration & HIDDEN); } else { return configuration; }
diff --git a/src/mips/OWNERS b/src/mips/OWNERS index 8d6807d..5508ba6 100644 --- a/src/mips/OWNERS +++ b/src/mips/OWNERS
@@ -1,10 +1,5 @@ -plind44@gmail.com paul.lind@imgtec.com -gergely@homejinni.com gergely.kis@imgtec.com -palfia@homejinni.com akos.palfi@imgtec.com -kilvadyb@homejinni.com balazs.kilvady@imgtec.com -Dusan.Milosavljevic@rt-rk.com dusan.milosavljevic@imgtec.com
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index 462ef67..f6785d2 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc
@@ -13,7 +13,7 @@ #include "src/deoptimizer.h" #include "src/full-codegen.h" #include "src/runtime.h" -#include "src/stub-cache.h" + namespace v8 { namespace internal {
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 3169b1a..0b844a5 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc
@@ -9,8 +9,11 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" +#include "src/ic/handler-compiler.h" +#include "src/isolate.h" +#include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" -#include "src/stub-cache.h" +#include "src/runtime.h" namespace v8 { namespace internal { @@ -404,7 +407,7 @@ class OpBits: public BitField<Token::Value, 2, 14> {}; Major MajorKey() const { return ConvertToDouble; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return result1_.code() + (result2_.code() << 4) + @@ -1483,7 +1486,7 @@ // Enter the exit frame that transitions from JavaScript to C++. FrameScope scope(masm, StackFrame::MANUAL); - __ EnterExitFrame(save_doubles_); + __ EnterExitFrame(save_doubles()); // s0: number of arguments including receiver (C callee-saved) // s1: pointer to first argument (C callee-saved) @@ -1571,7 +1574,7 @@ // sp: stack pointer // fp: frame pointer // s0: still holds argc (callee-saved). - __ LeaveExitFrame(save_doubles_, s0, true, EMIT_RETURN); + __ LeaveExitFrame(save_doubles(), s0, true, EMIT_RETURN); // Handling of exception. __ bind(&exception_returned);
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h index 0e3f1c3..9133304 100644 --- a/src/mips/code-stubs-mips.h +++ b/src/mips/code-stubs-mips.h
@@ -5,7 +5,7 @@ #ifndef V8_MIPS_CODE_STUBS_ARM_H_ #define V8_MIPS_CODE_STUBS_ARM_H_ -#include "src/ic-inl.h" +#include "src/code-stubs.h" namespace v8 { @@ -29,7 +29,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -70,7 +70,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -84,7 +84,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return StoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -97,7 +97,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return RestoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -126,7 +126,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, @@ -176,7 +176,7 @@ class SignRegisterBits: public BitField<int, 12, 4> {}; Major MajorKey() const { return WriteInt32ToHeapNumber; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return IntRegisterBits::encode(the_int_.code()) | HeapNumberRegisterBits::encode(the_heap_number_.code()) @@ -348,7 +348,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) | @@ -389,7 +389,7 @@ private: Major MajorKey() const { return DirectCEntry; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } bool NeedsImmovableCode() { return true; } }; @@ -436,7 +436,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { return LookupModeBits::encode(mode_); } + uint32_t MinorKey() const { return LookupModeBits::encode(mode_); } class LookupModeBits: public BitField<LookupMode, 0, 1> {};
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h index 82a410e..b02ec4f 100644 --- a/src/mips/codegen-mips.h +++ b/src/mips/codegen-mips.h
@@ -8,7 +8,7 @@ #include "src/ast.h" -#include "src/ic-inl.h" +#include "src/macro-assembler.h" namespace v8 { namespace internal {
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 1327bf6..bd3e821 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc
@@ -22,7 +22,6 @@ #include "src/isolate-inl.h" #include "src/parser.h" #include "src/scopes.h" -#include "src/stub-cache.h" #include "src/mips/code-stubs-mips.h" #include "src/mips/macro-assembler-mips.h"
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 193db1e..91e2911 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc
@@ -31,7 +31,7 @@ #include "src/hydrogen-osr.h" #include "src/mips/lithium-codegen-mips.h" #include "src/mips/lithium-gap-resolver-mips.h" -#include "src/stub-cache.h" + namespace v8 { namespace internal { @@ -897,7 +897,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -2887,6 +2887,19 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ li(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(a0)); + __ li(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); @@ -2894,13 +2907,7 @@ __ li(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -3028,13 +3035,7 @@ // Name is always in a2. __ li(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3341,13 +3342,7 @@ DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h index 5c19e0d..d379eb9 100644 --- a/src/mips/lithium-codegen-mips.h +++ b/src/mips/lithium-codegen-mips.h
@@ -364,6 +364,9 @@ void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); + template <class T> + void EmitVectorLoadICRegisters(T* instr); + ZoneList<LEnvironment*> deoptimizations_; ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_; ZoneList<Handle<Object> > deoptimization_literals_;
diff --git a/src/mips64/OWNERS b/src/mips64/OWNERS index 8d6807d..5508ba6 100644 --- a/src/mips64/OWNERS +++ b/src/mips64/OWNERS
@@ -1,10 +1,5 @@ -plind44@gmail.com paul.lind@imgtec.com -gergely@homejinni.com gergely.kis@imgtec.com -palfia@homejinni.com akos.palfi@imgtec.com -kilvadyb@homejinni.com balazs.kilvady@imgtec.com -Dusan.Milosavljevic@rt-rk.com dusan.milosavljevic@imgtec.com
diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc index cbbcc05..91dcfc8 100644 --- a/src/mips64/builtins-mips64.cc +++ b/src/mips64/builtins-mips64.cc
@@ -13,7 +13,6 @@ #include "src/deoptimizer.h" #include "src/full-codegen.h" #include "src/runtime.h" -#include "src/stub-cache.h" namespace v8 { namespace internal {
diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index 970792a..78a169c 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc
@@ -9,8 +9,11 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" +#include "src/ic/handler-compiler.h" +#include "src/isolate.h" +#include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" -#include "src/stub-cache.h" +#include "src/runtime.h" namespace v8 { namespace internal { @@ -403,7 +406,7 @@ class OpBits: public BitField<Token::Value, 2, 14> {}; Major MajorKey() const { return ConvertToDouble; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return result1_.code() + (result2_.code() << 4) + @@ -1477,7 +1480,7 @@ // Enter the exit frame that transitions from JavaScript to C++. FrameScope scope(masm, StackFrame::MANUAL); - __ EnterExitFrame(save_doubles_); + __ EnterExitFrame(save_doubles()); // s0: number of arguments including receiver (C callee-saved) // s1: pointer to first argument (C callee-saved) @@ -1564,7 +1567,7 @@ // sp: stack pointer // fp: frame pointer // s0: still holds argc (callee-saved). - __ LeaveExitFrame(save_doubles_, s0, true, EMIT_RETURN); + __ LeaveExitFrame(save_doubles(), s0, true, EMIT_RETURN); // Handling of exception. __ bind(&exception_returned);
diff --git a/src/mips64/code-stubs-mips64.h b/src/mips64/code-stubs-mips64.h index 73f19cd..614c3f6 100644 --- a/src/mips64/code-stubs-mips64.h +++ b/src/mips64/code-stubs-mips64.h
@@ -5,7 +5,7 @@ #ifndef V8_MIPS_CODE_STUBS_ARM_H_ #define V8_MIPS_CODE_STUBS_ARM_H_ -#include "src/ic-inl.h" +#include "src/code-stubs.h" namespace v8 { @@ -29,7 +29,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -69,7 +69,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -83,7 +83,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return StoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -96,7 +96,7 @@ static void GenerateAheadOfTime(Isolate* isolate); private: Major MajorKey() const { return RestoreRegistersState; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -125,7 +125,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop(MacroAssembler* masm, @@ -175,7 +175,7 @@ class SignRegisterBits: public BitField<int, 12, 4> {}; Major MajorKey() const { return WriteInt32ToHeapNumber; } - int MinorKey() const { + uint32_t MinorKey() const { // Encode the parameters in a unique 16 bit value. return IntRegisterBits::encode(the_int_.code()) | HeapNumberRegisterBits::encode(the_heap_number_.code()) @@ -347,7 +347,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) | @@ -388,7 +388,7 @@ private: Major MajorKey() const { return DirectCEntry; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } bool NeedsImmovableCode() { return true; } }; @@ -435,7 +435,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { return LookupModeBits::encode(mode_); } + uint32_t MinorKey() const { return LookupModeBits::encode(mode_); } class LookupModeBits: public BitField<LookupMode, 0, 1> {};
diff --git a/src/mips64/codegen-mips64.h b/src/mips64/codegen-mips64.h index 82a410e..b02ec4f 100644 --- a/src/mips64/codegen-mips64.h +++ b/src/mips64/codegen-mips64.h
@@ -8,7 +8,7 @@ #include "src/ast.h" -#include "src/ic-inl.h" +#include "src/macro-assembler.h" namespace v8 { namespace internal {
diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index b874625..dc90608 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc
@@ -22,7 +22,6 @@ #include "src/isolate-inl.h" #include "src/parser.h" #include "src/scopes.h" -#include "src/stub-cache.h" #include "src/mips64/code-stubs-mips64.h" #include "src/mips64/macro-assembler-mips64.h"
diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index ab0d8c7..42b6ea1 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc
@@ -8,7 +8,6 @@ #include "src/hydrogen-osr.h" #include "src/mips64/lithium-codegen-mips64.h" #include "src/mips64/lithium-gap-resolver-mips64.h" -#include "src/stub-cache.h" namespace v8 { namespace internal { @@ -852,7 +851,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -2866,6 +2865,19 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ li(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(a0)); + __ li(LoadIC::SlotRegister(), + Operand(Smi::FromInt(instr->hydrogen()->slot()))); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(cp)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); @@ -2873,13 +2885,7 @@ __ li(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -3021,13 +3027,7 @@ // Name is always in a2. __ li(LoadIC::NameRegister(), Operand(instr->name())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3375,13 +3375,7 @@ DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ li(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(a0)); - __ li(LoadIC::SlotRegister(), - Operand(Smi::FromInt(instr->hydrogen()->slot()))); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
diff --git a/src/mips64/lithium-codegen-mips64.h b/src/mips64/lithium-codegen-mips64.h index d42a10e..d67abdb 100644 --- a/src/mips64/lithium-codegen-mips64.h +++ b/src/mips64/lithium-codegen-mips64.h
@@ -365,6 +365,9 @@ void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); + template <class T> + void EmitVectorLoadICRegisters(T* instr); + ZoneList<LEnvironment*> deoptimizations_; ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_; ZoneList<Handle<Object> > deoptimization_literals_;
diff --git a/src/objects-inl.h b/src/objects-inl.h index e2414d2..9289900 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h
@@ -717,19 +717,9 @@ // the entry size. int length = FixedArray::cast(this)->length(); if (length == 0) return true; - if (length < DeoptimizationInputData::kFirstDeoptEntryIndex) return false; - FixedArray* self = FixedArray::cast(const_cast<Object*>(this)); - int deopt_count = - Smi::cast(self->get(DeoptimizationInputData::kDeoptEntryCountIndex)) - ->value(); - int patch_count = - Smi::cast( - self->get( - DeoptimizationInputData::kReturnAddressPatchEntryCountIndex)) - ->value(); - - return length == DeoptimizationInputData::LengthFor(deopt_count, patch_count); + length -= DeoptimizationInputData::kFirstDeoptEntryIndex; + return length >= 0 && length % DeoptimizationInputData::kDeoptEntrySize == 0; } @@ -7022,6 +7012,16 @@ } +Handle<Object> TypeFeedbackInfo::PremonomorphicSentinel(Isolate* isolate) { + return isolate->factory()->megamorphic_symbol(); +} + + +Handle<Object> TypeFeedbackInfo::GenericSentinel(Isolate* isolate) { + return isolate->factory()->generic_symbol(); +} + + Handle<Object> TypeFeedbackInfo::MonomorphicArraySentinel(Isolate* isolate, ElementsKind elements_kind) { return Handle<Object>(Smi::FromInt(static_cast<int>(elements_kind)), isolate);
diff --git a/src/objects.cc b/src/objects.cc index f223b0f..e3c45c4 100644 --- a/src/objects.cc +++ b/src/objects.cc
@@ -143,7 +143,7 @@ Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object, Handle<Name> key) { - LookupIterator it(object, key, LookupIterator::CHECK_DERIVED_PROPERTY); + LookupIterator it(object, key, LookupIterator::PROTOTYPE_CHAIN_PROPERTY); return GetDataProperty(&it); } @@ -3787,7 +3787,7 @@ void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name, Handle<Object> value, PropertyAttributes attributes) { - LookupIterator it(object, name, LookupIterator::CHECK_PROPERTY); + LookupIterator it(object, name, LookupIterator::OWN_PROPERTY); #ifdef DEBUG uint32_t index; DCHECK(!object->IsJSProxy()); @@ -3812,8 +3812,7 @@ PropertyAttributes attributes, ExecutableAccessorInfoHandling handling) { DCHECK(!value->IsTheHole()); - LookupIterator it(object, name, - LookupIterator::CHECK_HIDDEN_SKIP_INTERCEPTOR); + LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); bool is_observed = object->map()->is_observed() && *name != it.isolate()->heap()->hidden_string(); for (; it.IsFound(); it.Next()) { @@ -3832,7 +3831,6 @@ case LookupIterator::PROPERTY: { if (!it.HasProperty()) break; - if (it.HolderIsNonGlobalHiddenPrototype()) break; PropertyDetails details = it.property_details(); Handle<Object> old_value = it.isolate()->factory()->the_hole_value(); switch (it.property_kind()) { @@ -3984,7 +3982,7 @@ if (object->IsJSObject() && name->AsArrayIndex(&index)) { return GetOwnElementAttribute(object, index); } - LookupIterator it(object, name, LookupIterator::CHECK_HIDDEN); + LookupIterator it(object, name, LookupIterator::HIDDEN); return GetPropertyAttributes(&it); } @@ -4692,7 +4690,7 @@ bool JSObject::HasHiddenProperties(Handle<JSObject> object) { Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string(); - LookupIterator it(object, hidden, LookupIterator::CHECK_PROPERTY); + LookupIterator it(object, hidden, LookupIterator::OWN_PROPERTY); Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it); // Cannot get an exception since the hidden_string isn't accessible to JS. DCHECK(maybe.has_value); @@ -4727,7 +4725,7 @@ } else { Isolate* isolate = GetIsolate(); LookupIterator it(handle(this), isolate->factory()->hidden_string(), - LookupIterator::CHECK_PROPERTY); + LookupIterator::OWN_PROPERTY); if (it.IsFound() && it.HasProperty()) { DCHECK_EQ(LookupIterator::DATA, it.property_kind()); return *it.GetDataValue(); @@ -4923,9 +4921,8 @@ // Skip interceptors on FORCE_DELETION. LookupIterator::Configuration config = - delete_mode == FORCE_DELETION - ? LookupIterator::CHECK_HIDDEN_SKIP_INTERCEPTOR - : LookupIterator::CHECK_HIDDEN; + delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR + : LookupIterator::HIDDEN; LookupIterator it(object, name, config); @@ -6154,8 +6151,7 @@ Object::GetElement(isolate, object, index).ToHandleChecked(); } } else { - LookupIterator it(object, name, - LookupIterator::CHECK_HIDDEN_SKIP_INTERCEPTOR); + LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); CHECK(GetPropertyAttributes(&it).has_value); preexists = it.IsFound(); if (preexists && (it.property_kind() == LookupIterator::DATA || @@ -6174,7 +6170,7 @@ setter->IsNull()); // At least one of the accessors needs to be a new value. DCHECK(!getter->IsNull() || !setter->IsNull()); - LookupIterator it(object, name, LookupIterator::CHECK_PROPERTY); + LookupIterator it(object, name, LookupIterator::OWN_PROPERTY); if (!getter->IsNull()) { it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes); } @@ -6257,8 +6253,7 @@ SetElementCallback(object, index, info, info->property_attributes()); } else { // Lookup the name. - LookupIterator it(object, name, - LookupIterator::CHECK_HIDDEN_SKIP_INTERCEPTOR); + LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR); CHECK(GetPropertyAttributes(&it).has_value); // ES5 forbids turning a property into an accessor if it's not // configurable. See 8.6.1 (Table 5). @@ -6316,7 +6311,7 @@ } } else { LookupIterator it(object, name, - LookupIterator::CHECK_DERIVED_SKIP_INTERCEPTOR); + LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); for (; it.IsFound(); it.Next()) { switch (it.state()) { case LookupIterator::INTERCEPTOR: @@ -7933,17 +7928,11 @@ Handle<DeoptimizationInputData> DeoptimizationInputData::New( - Isolate* isolate, int deopt_entry_count, int return_patch_address_count, - PretenureFlag pretenure) { - DCHECK(deopt_entry_count + return_patch_address_count > 0); - Handle<FixedArray> deoptimization_data = - Handle<FixedArray>::cast(isolate->factory()->NewFixedArray( - LengthFor(deopt_entry_count, return_patch_address_count), pretenure)); - deoptimization_data->set(kDeoptEntryCountIndex, - Smi::FromInt(deopt_entry_count)); - deoptimization_data->set(kReturnAddressPatchEntryCountIndex, - Smi::FromInt(return_patch_address_count)); - return Handle<DeoptimizationInputData>::cast(deoptimization_data); + Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) { + DCHECK(deopt_entry_count > 0); + return Handle<DeoptimizationInputData>::cast( + isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count), + pretenure)); } @@ -10291,26 +10280,7 @@ SafepointEntry Code::GetSafepointEntry(Address pc) { SafepointTable table(this); - SafepointEntry entry = table.FindEntry(pc); - if (entry.is_valid() || !is_turbofanned()) { - return entry; - } - - // If the code is turbofanned, we might be looking for - // an address that was patched by lazy deoptimization. - // In that case look through the patch table, try to - // lookup the original address there, and then use this - // to find the safepoint entry. - DeoptimizationInputData* deopt_data = - DeoptimizationInputData::cast(deoptimization_data()); - intptr_t offset = pc - instruction_start(); - for (int i = 0; i < deopt_data->ReturnAddressPatchCount(); i++) { - if (deopt_data->PatchedAddressPc(i)->value() == offset) { - int original_offset = deopt_data->ReturnAddressPc(i)->value(); - return table.FindEntry(instruction_start() + original_offset); - } - } - return SafepointEntry(); + return table.FindEntry(pc); } @@ -10863,19 +10833,6 @@ os << "\n"; } } - - int return_address_patch_count = ReturnAddressPatchCount(); - if (return_address_patch_count != 0) { - os << "Return address patch data (count = " << return_address_patch_count - << ")\n"; - os << " index pc patched_pc\n"; - } - for (int i = 0; i < return_address_patch_count; i++) { - Vector<char> buf = Vector<char>::New(128); - SNPrintF(buf, "%6d %6d %12d\n", i, ReturnAddressPc(i)->value(), - PatchedAddressPc(i)->value()); - os << buf.start(); - } } @@ -11006,6 +10963,13 @@ } else { os << "<none>"; } + if (entry.deoptimization_pc() != Safepoint::kNoDeoptimizationPc) { + Vector<char> buf2 = Vector<char>::New(30); + SNPrintF(buf2, "%6d", entry.deoptimization_pc()); + os << buf2.start(); + } else { + os << "<none>"; + } if (entry.argument_count() > 0) { os << " argc: " << entry.argument_count(); } @@ -11708,10 +11672,9 @@ return "allocation-site-tenuring-changed"; case kAllocationSiteTransitionChangedGroup: return "allocation-site-transition-changed"; - default: - UNREACHABLE(); - return "?"; } + UNREACHABLE(); + return "?"; } @@ -12875,12 +12838,12 @@ bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { - Isolate* isolate = jsarray_map->GetIsolate(); - DCHECK(!jsarray_map->is_dictionary_map()); - LookupResult lookup(isolate); - Handle<Name> length_string = isolate->factory()->length_string(); - jsarray_map->LookupDescriptor(NULL, *length_string, &lookup); - return lookup.IsReadOnly(); + Isolate* isolate = jsarray_map->GetIsolate(); + DCHECK(!jsarray_map->is_dictionary_map()); + LookupResult lookup(isolate); + Handle<Name> length_string = isolate->factory()->length_string(); + jsarray_map->LookupDescriptor(NULL, *length_string, &lookup); + return lookup.IsReadOnly(); } @@ -12890,7 +12853,7 @@ CHECK(array->length()->ToArrayIndex(&length)); if (length <= index) { LookupIterator it(array, array->GetIsolate()->factory()->length_string(), - LookupIterator::CHECK_PROPERTY); + LookupIterator::OWN_PROPERTY); CHECK(it.IsFound()); CHECK(it.HasProperty()); return it.IsReadOnly(); @@ -13277,7 +13240,7 @@ Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object, Handle<Name> key) { - LookupIterator it(object, key, LookupIterator::CHECK_ACCESS_CHECK); + LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR); Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); if (!maybe_result.has_value) return Maybe<bool>(); return maybe(it.IsFound()); @@ -13315,7 +13278,7 @@ Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object, Handle<Name> key) { - LookupIterator it(object, key, LookupIterator::CHECK_ACCESS_CHECK); + LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR); Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it); if (!maybe_result.has_value) return Maybe<bool>(); return maybe(it.IsFound() && it.property_kind() == LookupIterator::ACCESSOR); @@ -14646,13 +14609,6 @@ } -PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) { - DCHECK(!HasFastProperties()); - Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); - return PropertyCell::cast(value); -} - - Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell( Handle<JSGlobalObject> global, Handle<Name> name) {
diff --git a/src/objects.h b/src/objects.h index 3c814f2..4ba4c95 100644 --- a/src/objects.h +++ b/src/objects.h
@@ -5151,16 +5151,14 @@ class DeoptimizationInputData: public FixedArray { public: // Layout description. Indices in the array. - static const int kDeoptEntryCountIndex = 0; - static const int kReturnAddressPatchEntryCountIndex = 1; - static const int kTranslationByteArrayIndex = 2; - static const int kInlinedFunctionCountIndex = 3; - static const int kLiteralArrayIndex = 4; - static const int kOsrAstIdIndex = 5; - static const int kOsrPcOffsetIndex = 6; - static const int kOptimizationIdIndex = 7; - static const int kSharedFunctionInfoIndex = 8; - static const int kFirstDeoptEntryIndex = 9; + static const int kTranslationByteArrayIndex = 0; + static const int kInlinedFunctionCountIndex = 1; + static const int kLiteralArrayIndex = 2; + static const int kOsrAstIdIndex = 3; + static const int kOsrPcOffsetIndex = 4; + static const int kOptimizationIdIndex = 5; + static const int kSharedFunctionInfoIndex = 6; + static const int kFirstDeoptEntryIndex = 7; // Offsets of deopt entry elements relative to the start of the entry. static const int kAstIdRawOffset = 0; @@ -5169,12 +5167,6 @@ static const int kPcOffset = 3; static const int kDeoptEntrySize = 4; - // Offsets of return address patch entry elements relative to the start of the - // entry - static const int kReturnAddressPcOffset = 0; - static const int kPatchedAddressPcOffset = 1; - static const int kReturnAddressPatchEntrySize = 2; - // Simple element accessors. #define DEFINE_ELEMENT_ACCESSORS(name, type) \ type* name() { \ @@ -5195,7 +5187,7 @@ #undef DEFINE_ELEMENT_ACCESSORS // Accessors for elements of the ith deoptimization entry. -#define DEFINE_DEOPT_ENTRY_ACCESSORS(name, type) \ +#define DEFINE_ENTRY_ACCESSORS(name, type) \ type* name(int i) { \ return type::cast(get(IndexForEntry(i) + k##name##Offset)); \ } \ @@ -5203,28 +5195,13 @@ set(IndexForEntry(i) + k##name##Offset, value); \ } - DEFINE_DEOPT_ENTRY_ACCESSORS(AstIdRaw, Smi) - DEFINE_DEOPT_ENTRY_ACCESSORS(TranslationIndex, Smi) - DEFINE_DEOPT_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi) - DEFINE_DEOPT_ENTRY_ACCESSORS(Pc, Smi) + DEFINE_ENTRY_ACCESSORS(AstIdRaw, Smi) + DEFINE_ENTRY_ACCESSORS(TranslationIndex, Smi) + DEFINE_ENTRY_ACCESSORS(ArgumentsStackHeight, Smi) + DEFINE_ENTRY_ACCESSORS(Pc, Smi) #undef DEFINE_DEOPT_ENTRY_ACCESSORS -// Accessors for elements of the ith deoptimization entry. -#define DEFINE_PATCH_ENTRY_ACCESSORS(name, type) \ - type* name(int i) { \ - return type::cast( \ - get(IndexForReturnAddressPatchEntry(i) + k##name##Offset)); \ - } \ - void Set##name(int i, type* value) { \ - set(IndexForReturnAddressPatchEntry(i) + k##name##Offset, value); \ - } - - DEFINE_PATCH_ENTRY_ACCESSORS(ReturnAddressPc, Smi) - DEFINE_PATCH_ENTRY_ACCESSORS(PatchedAddressPc, Smi) - -#undef DEFINE_PATCH_ENTRY_ACCESSORS - BailoutId AstId(int i) { return BailoutId(AstIdRaw(i)->value()); } @@ -5234,19 +5211,12 @@ } int DeoptCount() { - return length() == 0 ? 0 : Smi::cast(get(kDeoptEntryCountIndex))->value(); - } - - int ReturnAddressPatchCount() { - return length() == 0 - ? 0 - : Smi::cast(get(kReturnAddressPatchEntryCountIndex))->value(); + return (length() - kFirstDeoptEntryIndex) / kDeoptEntrySize; } // Allocates a DeoptimizationInputData. static Handle<DeoptimizationInputData> New(Isolate* isolate, int deopt_entry_count, - int return_address_patch_count, PretenureFlag pretenure); DECLARE_CAST(DeoptimizationInputData) @@ -5256,21 +5226,12 @@ #endif private: - friend class Object; // For accessing LengthFor. - static int IndexForEntry(int i) { return kFirstDeoptEntryIndex + (i * kDeoptEntrySize); } - int IndexForReturnAddressPatchEntry(int i) { - return kFirstDeoptEntryIndex + (DeoptCount() * kDeoptEntrySize) + - (i * kReturnAddressPatchEntrySize); - } - static int LengthFor(int deopt_count, int return_address_patch_count) { - return kFirstDeoptEntryIndex + (deopt_count * kDeoptEntrySize) + - (return_address_patch_count * kReturnAddressPatchEntrySize); - } + static int LengthFor(int entry_count) { return IndexForEntry(entry_count); } }; @@ -5924,10 +5885,11 @@ kAllocationSiteTenuringChangedGroup, // Group of code that depends on element transition information in // AllocationSites not being changed. - kAllocationSiteTransitionChangedGroup, - kGroupCount = kAllocationSiteTransitionChangedGroup + 1 + kAllocationSiteTransitionChangedGroup }; + static const int kGroupCount = kAllocationSiteTransitionChangedGroup + 1; + // Array for holding the index of the first code object of each group. // The last element stores the total number of code objects. class GroupStartIndexes { @@ -7836,9 +7798,6 @@ // [global proxy]: the global proxy object of the context DECL_ACCESSORS(global_proxy, JSObject) - // Retrieve the property cell used to store a property. - PropertyCell* GetPropertyCell(LookupResult* result); - DECLARE_CAST(GlobalObject) // Layout description. @@ -8449,6 +8408,12 @@ // The object that indicates a megamorphic state. static inline Handle<Object> MegamorphicSentinel(Isolate* isolate); + // The object that indicates a premonomorphic state. + static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate); + + // The object that indicates a generic state. + static inline Handle<Object> GenericSentinel(Isolate* isolate); + // The object that indicates a monomorphic state of Array with // ElementsKind static inline Handle<Object> MonomorphicArraySentinel(Isolate* isolate,
diff --git a/src/regexp.js b/src/regexp.js index 1a2a4f0..d8e3ea4 100644 --- a/src/regexp.js +++ b/src/regexp.js
@@ -394,7 +394,7 @@ // The length of compile is 1 in SpiderMonkey. %FunctionSetLength($RegExp.prototype.compile, 1); - // The properties input, $input, and $_ are aliases for each other. When this + // The properties `input` and `$_` are aliases for each other. When this // value is set the value it is set to is coerced to a string. // Getter and setter for the input. var RegExpGetInput = function() {
diff --git a/src/runtime.cc b/src/runtime.cc index 1616434..63a57e9 100644 --- a/src/runtime.cc +++ b/src/runtime.cc
@@ -1714,7 +1714,8 @@ Handle<Object> key(table->KeyAt(i), isolate); if (table->IsKey(*key)) { entries->set(number_of_non_hole_elements++, *key); - entries->set(number_of_non_hole_elements++, table->Lookup(key)); + Object* value = table->Lookup(key); + entries->set(number_of_non_hole_elements++, value); } } DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements); @@ -1980,7 +1981,7 @@ } } else { // Get attributes. - LookupIterator it(obj, name, LookupIterator::CHECK_HIDDEN); + LookupIterator it(obj, name, LookupIterator::HIDDEN); Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it); if (!maybe.has_value) return MaybeHandle<Object>(); attrs = maybe.value; @@ -2178,7 +2179,7 @@ PropertyAttributes attr, bool is_var, bool is_const, bool is_function) { // Do the lookup own properties only, see ES5 erratum. - LookupIterator it(global, name, LookupIterator::CHECK_HIDDEN_PROPERTY); + LookupIterator it(global, name, LookupIterator::HIDDEN_PROPERTY); Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); DCHECK(maybe.has_value); PropertyAttributes old_attributes = maybe.value; @@ -2308,7 +2309,7 @@ Handle<GlobalObject> global = isolate->global_object(); // Lookup the property as own on the global object. - LookupIterator it(global, name, LookupIterator::CHECK_HIDDEN_PROPERTY); + LookupIterator it(global, name, LookupIterator::HIDDEN_PROPERTY); Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); DCHECK(maybe.has_value); PropertyAttributes old_attributes = maybe.value; @@ -2458,7 +2459,7 @@ // code can run in between that modifies the declared property. DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject()); - LookupIterator it(holder, name, LookupIterator::CHECK_HIDDEN_PROPERTY); + LookupIterator it(holder, name, LookupIterator::HIDDEN_PROPERTY); Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); if (!maybe.has_value) return isolate->heap()->exception(); PropertyAttributes old_attributes = maybe.value; @@ -4889,7 +4890,7 @@ } // Lookup cache miss. Perform lookup and update the cache if // appropriate. - LookupIterator it(receiver, key, LookupIterator::CHECK_OWN); + LookupIterator it(receiver, key, LookupIterator::OWN); if (it.IsFound() && it.state() == LookupIterator::PROPERTY && it.HasProperty() && it.property_details().type() == FIELD) { FieldIndex field_index = it.GetFieldIndex(); @@ -5045,7 +5046,7 @@ return isolate->heap()->undefined_value(); } - LookupIterator it(js_object, name, LookupIterator::CHECK_PROPERTY); + LookupIterator it(js_object, name, LookupIterator::OWN_PROPERTY); // Take special care when attributes are different and there is already // a property. @@ -5293,7 +5294,7 @@ #ifdef DEBUG uint32_t index = 0; DCHECK(!key->ToArrayIndex(&index)); - LookupIterator it(object, key, LookupIterator::CHECK_PROPERTY); + LookupIterator it(object, key, LookupIterator::OWN_PROPERTY); Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); DCHECK(maybe.has_value); RUNTIME_ASSERT(!it.IsFound()); @@ -5325,7 +5326,7 @@ bool duplicate; if (key->IsName()) { LookupIterator it(object, Handle<Name>::cast(key), - LookupIterator::CHECK_PROPERTY); + LookupIterator::OWN_PROPERTY); Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); DCHECK(maybe.has_value); duplicate = it.IsFound(); @@ -6010,6 +6011,10 @@ HandleScope scope(isolate); if (raw_key->IsSymbol()) { + Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key); + if (symbol->Equals(isolate->native_context()->iterator_symbol())) { + return isolate->native_context()->array_values_iterator(); + } // Lookup in the initial Object.prototype object. Handle<Object> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( @@ -10894,8 +10899,8 @@ } -static Handle<Object> DebugLookupResultValue(LookupIterator* it, - bool* has_caught = NULL) { +static Handle<Object> DebugGetProperty(LookupIterator* it, + bool* has_caught = NULL) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: @@ -10979,9 +10984,9 @@ return *isolate->factory()->NewJSArrayWithElements(details); } - LookupIterator it(obj, name, LookupIterator::CHECK_HIDDEN); + LookupIterator it(obj, name, LookupIterator::HIDDEN); bool has_caught = false; - Handle<Object> value = DebugLookupResultValue(&it, &has_caught); + Handle<Object> value = DebugGetProperty(&it, &has_caught); if (!it.IsFound()) return isolate->heap()->undefined_value(); Handle<Object> maybe_pair; @@ -11020,8 +11025,8 @@ CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); - LookupIterator it(obj, name, LookupIterator::CHECK_DERIVED); - return *DebugLookupResultValue(&it); + LookupIterator it(obj, name); + return *DebugGetProperty(&it); }
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc index d00b751..5f91547 100644 --- a/src/safepoint-table.cc +++ b/src/safepoint-table.cc
@@ -43,8 +43,8 @@ length_ = Memory::uint32_at(header + kLengthOffset); entry_size_ = Memory::uint32_at(header + kEntrySizeOffset); pc_and_deoptimization_indexes_ = header + kHeaderSize; - entries_ = pc_and_deoptimization_indexes_ + - (length_ * kPcAndDeoptimizationIndexSize); + entries_ = + pc_and_deoptimization_indexes_ + (length_ * kPcAndDeoptimizationInfoSize); DCHECK(entry_size_ > 0); STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax == Safepoint::kNoDeoptimizationIndex); @@ -56,6 +56,7 @@ for (unsigned i = 0; i < length(); i++) { // TODO(kasperl): Replace the linear search with binary search. if (GetPcOffset(i) == pc_offset) return GetEntry(i); + if (GetDeoptimizationPcOffset(i) == pc_offset) return GetEntry(i); } return SafepointEntry(); } @@ -110,6 +111,8 @@ info.pc = assembler->pc_offset(); info.arguments = arguments; info.has_doubles = (kind & Safepoint::kWithDoubles); + info.deoptimization_pc = Safepoint::kNoDeoptimizationPc; + int safepoint_id = deoptimization_info_.length(); deoptimization_info_.Add(info, zone_); deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex, zone_); if (deopt_mode == Safepoint::kNoLazyDeopt) { @@ -120,7 +123,7 @@ ? new(zone_) ZoneList<int>(4, zone_) : NULL, zone_); - return Safepoint(indexes_.last(), registers_.last()); + return Safepoint(safepoint_id, indexes_.last(), registers_.last()); } @@ -159,6 +162,7 @@ assembler->dd(deoptimization_info_[i].pc); assembler->dd(EncodeExceptPC(deoptimization_info_[i], deopt_index_list_[i])); + assembler->dd(deoptimization_info_[i].deoptimization_pc); } // Emit table of bitmaps.
diff --git a/src/safepoint-table.h b/src/safepoint-table.h index 0bdd431..d91a195 100644 --- a/src/safepoint-table.h +++ b/src/safepoint-table.h
@@ -17,9 +17,10 @@ class SafepointEntry BASE_EMBEDDED { public: - SafepointEntry() : info_(0), bits_(NULL) {} + SafepointEntry() : info_(0), deoptimization_pc_(0), bits_(NULL) {} - SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) { + SafepointEntry(unsigned info, unsigned deoptimization_pc, uint8_t* bits) + : info_(info), deoptimization_pc_(deoptimization_pc), bits_(bits) { DCHECK(is_valid()); } @@ -39,6 +40,11 @@ return DeoptimizationIndexField::decode(info_); } + unsigned deoptimization_pc() const { + DCHECK(is_valid()); + return deoptimization_pc_; + } + static const int kArgumentsFieldBits = 3; static const int kSaveDoublesFieldBits = 1; static const int kDeoptIndexBits = @@ -74,6 +80,7 @@ private: unsigned info_; + unsigned deoptimization_pc_; uint8_t* bits_; }; @@ -84,7 +91,8 @@ int size() const { return kHeaderSize + - (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); } + (length_ * (kPcAndDeoptimizationInfoSize + entry_size_)); + } unsigned length() const { return length_; } unsigned entry_size() const { return entry_size_; } @@ -93,11 +101,17 @@ return Memory::uint32_at(GetPcOffsetLocation(index)); } + unsigned GetDeoptimizationPcOffset(unsigned index) const { + DCHECK(index < length_); + return Memory::uint32_at(GetDeoptimizationPcLocation(index)); + } + SafepointEntry GetEntry(unsigned index) const { DCHECK(index < length_); unsigned info = Memory::uint32_at(GetInfoLocation(index)); + unsigned deopt_pc = Memory::uint32_at(GetDeoptimizationPcLocation(index)); uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_)); - return SafepointEntry(info, bits); + return SafepointEntry(info, deopt_pc, bits); } // Returns the entry for the given pc. @@ -114,18 +128,23 @@ static const int kPcSize = kIntSize; static const int kDeoptimizationIndexSize = kIntSize; - static const int kPcAndDeoptimizationIndexSize = - kPcSize + kDeoptimizationIndexSize; + static const int kDeoptimizationPcSize = kIntSize; + static const int kPcAndDeoptimizationInfoSize = + kPcSize + kDeoptimizationIndexSize + kDeoptimizationPcSize; Address GetPcOffsetLocation(unsigned index) const { return pc_and_deoptimization_indexes_ + - (index * kPcAndDeoptimizationIndexSize); + (index * kPcAndDeoptimizationInfoSize); } Address GetInfoLocation(unsigned index) const { return GetPcOffsetLocation(index) + kPcSize; } + Address GetDeoptimizationPcLocation(unsigned index) const { + return GetInfoLocation(index) + kDeoptimizationIndexSize; + } + static void PrintBits(OStream& os, // NOLINT uint8_t byte, int digits); @@ -158,15 +177,30 @@ kLazyDeopt }; + class Id { + private: + explicit Id(int id) : id_(id) {} + + int id_; + + friend class SafepointTableBuilder; + friend class Safepoint; + }; + static const int kNoDeoptimizationIndex = (1 << (SafepointEntry::kDeoptIndexBits)) - 1; + static const unsigned kNoDeoptimizationPc = ~0U; + void DefinePointerSlot(int index, Zone* zone) { indexes_->Add(index, zone); } void DefinePointerRegister(Register reg, Zone* zone); + Id id() const { return Id(id_); } + private: - Safepoint(ZoneList<int>* indexes, ZoneList<int>* registers) : - indexes_(indexes), registers_(registers) { } + Safepoint(int id, ZoneList<int>* indexes, ZoneList<int>* registers) + : id_(id), indexes_(indexes), registers_(registers) {} + int id_; ZoneList<int>* indexes_; ZoneList<int>* registers_; @@ -200,6 +234,11 @@ void BumpLastLazySafepointIndex() { last_lazy_safepoint_ = deopt_index_list_.length(); } + void SetDeoptimizationPc(Safepoint::Id safepoint_id, + unsigned deoptimization_pc) { + deoptimization_info_[safepoint_id.id_].deoptimization_pc = + deoptimization_pc; + } // Emit the safepoint table after the body. The number of bits per // entry must be enough to hold all the pointer indexes. @@ -211,6 +250,7 @@ unsigned pc; unsigned arguments; bool has_doubles; + unsigned deoptimization_pc; }; uint32_t EncodeExceptPC(const DeoptimizationInfo& info, unsigned index);
diff --git a/src/version.cc b/src/version.cc index 6efbd75..e7ecf4a 100644 --- a/src/version.cc +++ b/src/version.cc
@@ -34,8 +34,8 @@ // system so their names cannot be changed without changing the scripts. #define MAJOR_VERSION 3 #define MINOR_VERSION 29 -#define BUILD_NUMBER 16 -#define PATCH_LEVEL 1 +#define BUILD_NUMBER 17 +#define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 694c77d..55eede6 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc
@@ -9,7 +9,7 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" -#include "src/ic/ic-compiler.h" +#include "src/ic/handler-compiler.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" @@ -2435,11 +2435,11 @@ // Enter the exit frame that transitions from JavaScript to C++. #ifdef _WIN64 - int arg_stack_space = (result_size_ < 2 ? 2 : 4); -#else + int arg_stack_space = (result_size() < 2 ? 2 : 4); +#else // _WIN64 int arg_stack_space = 0; -#endif - __ EnterExitFrame(arg_stack_space, save_doubles_); +#endif // _WIN64 + __ EnterExitFrame(arg_stack_space, save_doubles()); // rbx: pointer to builtin function (C callee-saved). // rbp: frame pointer of exit frame (restored after C call). @@ -2461,14 +2461,14 @@ // Windows 64-bit ABI passes arguments in rcx, rdx, r8, r9. // Pass argv and argc as two parameters. The arguments object will // be created by stubs declared by DECLARE_RUNTIME_FUNCTION(). - if (result_size_ < 2) { + if (result_size() < 2) { // Pass a pointer to the Arguments object as the first argument. // Return result in single register (rax). __ movp(rcx, r14); // argc. __ movp(rdx, r15); // argv. __ Move(r8, ExternalReference::isolate_address(isolate())); } else { - DCHECK_EQ(2, result_size_); + DCHECK_EQ(2, result_size()); // Pass a pointer to the result location as the first argument. __ leap(rcx, StackSpaceOperand(2)); // Pass a pointer to the Arguments object as the second argument. @@ -2482,21 +2482,21 @@ __ movp(rdi, r14); // argc. __ movp(rsi, r15); // argv. __ Move(rdx, ExternalReference::isolate_address(isolate())); -#endif +#endif // _WIN64 __ call(rbx); // Result is in rax - do not destroy this register! #ifdef _WIN64 // If return value is on the stack, pop it to registers. - if (result_size_ > 1) { - DCHECK_EQ(2, result_size_); + if (result_size() > 1) { + DCHECK_EQ(2, result_size()); // Read result values stored on stack. Result is stored // above the four argument mirror slots and the two // Arguments object slots. __ movq(rax, Operand(rsp, 6 * kRegisterSize)); __ movq(rdx, Operand(rsp, 7 * kRegisterSize)); } -#endif +#endif // _WIN64 // Runtime functions should not return 'the hole'. Allowing it to escape may // lead to crashes in the IC code later. @@ -2530,7 +2530,7 @@ } // Exit the JavaScript to C++ exit frame. - __ LeaveExitFrame(save_doubles_); + __ LeaveExitFrame(save_doubles()); __ ret(0); // Handling of exception.
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h index a020ce5..0732a93 100644 --- a/src/x64/code-stubs-x64.h +++ b/src/x64/code-stubs-x64.h
@@ -27,7 +27,7 @@ SaveFPRegsMode save_doubles_; Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } + uint32_t MinorKey() const { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } }; @@ -67,7 +67,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -96,7 +96,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop( @@ -158,7 +158,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { + uint32_t MinorKey() const { return DictionaryBits::encode(dictionary_.code()) | ResultBits::encode(result_.code()) | IndexBits::encode(index_.code()) | @@ -389,7 +389,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) |
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 0a6ac17..928b874 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc
@@ -810,7 +810,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory()); @@ -2846,6 +2846,18 @@ } +template <class T> +void LCodeGen::EmitVectorLoadICRegisters(T* instr) { + DCHECK(FLAG_vector_ics); + Register vector = ToRegister(instr->temp_vector()); + DCHECK(vector.is(LoadIC::VectorRegister())); + __ Move(vector, instr->hydrogen()->feedback_vector()); + // No need to allocate this register. + DCHECK(LoadIC::SlotRegister().is(rax)); + __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); +} + + void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { DCHECK(ToRegister(instr->context()).is(rsi)); DCHECK(ToRegister(instr->global_object()).is(LoadIC::ReceiverRegister())); @@ -2853,12 +2865,7 @@ __ Move(LoadIC::NameRegister(), instr->name()); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(rax)); - __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); } ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode); @@ -3001,12 +3008,7 @@ __ Move(LoadIC::NameRegister(), instr->name()); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(rax)); - __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); } Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL); CallCode(ic, RelocInfo::CODE_TARGET, instr); @@ -3289,12 +3291,7 @@ DCHECK(ToRegister(instr->key()).is(LoadIC::NameRegister())); if (FLAG_vector_ics) { - Register vector = ToRegister(instr->temp_vector()); - DCHECK(vector.is(LoadIC::VectorRegister())); - __ Move(vector, instr->hydrogen()->feedback_vector()); - // No need to allocate this register. - DCHECK(LoadIC::SlotRegister().is(rax)); - __ Move(LoadIC::SlotRegister(), Smi::FromInt(instr->hydrogen()->slot())); + EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); } Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h index b3070c0..66a1d84 100644 --- a/src/x64/lithium-codegen-x64.h +++ b/src/x64/lithium-codegen-x64.h
@@ -314,6 +314,10 @@ void DoStoreKeyedExternalArray(LStoreKeyed* instr); void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); void DoStoreKeyedFixedArray(LStoreKeyed* instr); + + template <class T> + void EmitVectorLoadICRegisters(T* instr); + #ifdef _MSC_VER // On windows, you may not access the stack more than one page below // the most recently mapped page. To make the allocated area randomly
diff --git a/src/x87/builtins-x87.cc b/src/x87/builtins-x87.cc index 59ecda3..f7feaff 100644 --- a/src/x87/builtins-x87.cc +++ b/src/x87/builtins-x87.cc
@@ -9,7 +9,6 @@ #include "src/codegen.h" #include "src/deoptimizer.h" #include "src/full-codegen.h" -#include "src/stub-cache.h" namespace v8 { namespace internal {
diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index 6191aaf..b5b6ba0 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc
@@ -9,11 +9,11 @@ #include "src/bootstrapper.h" #include "src/code-stubs.h" #include "src/codegen.h" +#include "src/ic/ic-compiler.h" #include "src/isolate.h" #include "src/jsregexp.h" #include "src/regexp-macro-assembler.h" #include "src/runtime.h" -#include "src/stub-cache.h" namespace v8 { namespace internal { @@ -2240,7 +2240,7 @@ // edi: number of arguments including receiver (C callee-saved) // esi: pointer to the first argument (C callee-saved) - // Result returned in eax, or eax+edx if result_size_ is 2. + // Result returned in eax, or eax+edx if result size is 2. // Check stack alignment. if (FLAG_debug_code) {
diff --git a/src/x87/code-stubs-x87.h b/src/x87/code-stubs-x87.h index e32902f..5f42573 100644 --- a/src/x87/code-stubs-x87.h +++ b/src/x87/code-stubs-x87.h
@@ -5,8 +5,7 @@ #ifndef V8_X87_CODE_STUBS_X87_H_ #define V8_X87_CODE_STUBS_X87_H_ -#include "src/ic-inl.h" -#include "src/macro-assembler.h" +#include "src/code-stubs.h" namespace v8 { namespace internal { @@ -29,7 +28,7 @@ private: Major MajorKey() const { return StoreBufferOverflow; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } }; @@ -69,7 +68,7 @@ private: Major MajorKey() const { return SubString; } - int MinorKey() const { return 0; } + uint32_t MinorKey() const { return 0; } void Generate(MacroAssembler* masm); }; @@ -97,7 +96,7 @@ private: virtual Major MajorKey() const { return StringCompare; } - virtual int MinorKey() const { return 0; } + virtual uint32_t MinorKey() const { return 0; } virtual void Generate(MacroAssembler* masm); static void GenerateAsciiCharsCompareLoop( @@ -156,7 +155,7 @@ Major MajorKey() const { return NameDictionaryLookup; } - int MinorKey() const { + uint32_t MinorKey() const { return DictionaryBits::encode(dictionary_.code()) | ResultBits::encode(result_.code()) | IndexBits::encode(index_.code()) | @@ -384,7 +383,7 @@ Major MajorKey() const { return RecordWrite; } - int MinorKey() const { + uint32_t MinorKey() const { return ObjectBits::encode(object_.code()) | ValueBits::encode(value_.code()) | AddressBits::encode(address_.code()) |
diff --git a/src/x87/codegen-x87.h b/src/x87/codegen-x87.h index 15b2702..c23e866 100644 --- a/src/x87/codegen-x87.h +++ b/src/x87/codegen-x87.h
@@ -6,7 +6,7 @@ #define V8_X87_CODEGEN_X87_H_ #include "src/ast.h" -#include "src/ic-inl.h" +#include "src/macro-assembler.h" namespace v8 { namespace internal {
diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index c360353..a9ea85a 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc
@@ -14,7 +14,6 @@ #include "src/isolate-inl.h" #include "src/parser.h" #include "src/scopes.h" -#include "src/stub-cache.h" namespace v8 { namespace internal {
diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index 4116b46..9654133 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc
@@ -10,8 +10,6 @@ #include "src/codegen.h" #include "src/deoptimizer.h" #include "src/hydrogen-osr.h" -#include "src/ic.h" -#include "src/stub-cache.h" #include "src/x87/lithium-codegen-x87.h" namespace v8 { @@ -1095,7 +1093,7 @@ int length = deoptimizations_.length(); if (length == 0) return; Handle<DeoptimizationInputData> data = - DeoptimizationInputData::New(isolate(), length, 0, TENURED); + DeoptimizationInputData::New(isolate(), length, TENURED); Handle<ByteArray> translations = translations_.CreateByteArray(isolate()->factory());
diff --git a/test/base-unittests/bits-unittest.cc b/test/base-unittests/bits-unittest.cc index 56d3d92..9113675 100644 --- a/test/base-unittests/bits-unittest.cc +++ b/test/base-unittests/bits-unittest.cc
@@ -10,13 +10,13 @@ namespace base { namespace bits { -TEST(BitsTest, CountSetBits32) { - EXPECT_EQ(0u, CountSetBits32(0)); - EXPECT_EQ(1u, CountSetBits32(1)); - EXPECT_EQ(8u, CountSetBits32(0x11111111)); - EXPECT_EQ(16u, CountSetBits32(0xf0f0f0f0)); - EXPECT_EQ(24u, CountSetBits32(0xfff0f0ff)); - EXPECT_EQ(32u, CountSetBits32(0xffffffff)); +TEST(BitsTest, CountPopulation32) { + EXPECT_EQ(0u, CountPopulation32(0)); + EXPECT_EQ(1u, CountPopulation32(1)); + EXPECT_EQ(8u, CountPopulation32(0x11111111)); + EXPECT_EQ(16u, CountPopulation32(0xf0f0f0f0)); + EXPECT_EQ(24u, CountPopulation32(0xfff0f0ff)); + EXPECT_EQ(32u, CountPopulation32(0xffffffff)); }
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 0278056..90617c9 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status
@@ -84,9 +84,6 @@ ############################################################################## # TurboFan compiler failures. - # TODO(mstarzinger): These need investigation and are not categorized yet. - 'test-heap/NextCodeLinkIsWeak': [PASS, NO_VARIANTS], - # TODO(mstarzinger): Sometimes the try-catch blacklist fails. 'test-debug/DebugEvaluateWithoutStack': [PASS, NO_VARIANTS], 'test-debug/MessageQueues': [PASS, NO_VARIANTS],
diff --git a/test/cctest/compiler/call-tester.h b/test/cctest/compiler/call-tester.h index 27c6044..1dbed16 100644 --- a/test/cctest/compiler/call-tester.h +++ b/test/cctest/compiler/call-tester.h
@@ -86,12 +86,24 @@ }; template <> +struct ReturnValueTraits<uint16_t> { + static uint16_t Cast(uintptr_t r) { return static_cast<uint16_t>(r); } + static MachineType Representation() { return kMachUint16; } +}; + +template <> struct ReturnValueTraits<int8_t> { static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); } static MachineType Representation() { return kMachInt8; } }; template <> +struct ReturnValueTraits<uint8_t> { + static uint8_t Cast(uintptr_t r) { return static_cast<uint8_t>(r); } + static MachineType Representation() { return kMachUint8; } +}; + +template <> struct ReturnValueTraits<double> { static double Cast(uintptr_t r) { UNREACHABLE();
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc index 1e30e93..fd2463e 100644 --- a/test/cctest/compiler/test-codegen-deopt.cc +++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -201,11 +201,12 @@ Label* cont_label = t.code->GetLabel(t.cont_block); Label* deopt_label = t.code->GetLabel(t.deopt_block); - // Check the patch table. It should patch the continuation address to the - // deoptimization block address. - CHECK_EQ(1, data->ReturnAddressPatchCount()); - CHECK_EQ(cont_label->pos(), data->ReturnAddressPc(0)->value()); - CHECK_EQ(deopt_label->pos(), data->PatchedAddressPc(0)->value()); + // Check the safepoint - it should contain an entry for the call + // with the right deoptimization address. + SafepointEntry entry = t.result_code->GetSafepointEntry( + t.result_code->instruction_start() + cont_label->pos()); + CHECK(entry.is_valid()); + CHECK_EQ(deopt_label->pos(), entry.deoptimization_pc()); // Check that we deoptimize to the right AST id. CHECK_EQ(1, data->DeoptCount());
diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc index e676fb2..5e5b604 100644 --- a/test/cctest/compiler/test-run-inlining.cc +++ b/test/cctest/compiler/test-run-inlining.cc
@@ -36,6 +36,7 @@ TEST(SimpleInlining) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function(){" @@ -49,6 +50,7 @@ TEST(SimpleInliningContext) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -63,6 +65,7 @@ TEST(CaptureContext) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "var f = (function () {" @@ -80,6 +83,7 @@ // TODO(sigurds) For now we do not inline any native functions. If we do at // some point, change this test. TEST(DontInlineEval) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "var x = 42;" @@ -94,6 +98,7 @@ TEST(InlineOmitArguments) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -108,6 +113,7 @@ TEST(InlineSurplusArguments) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -123,6 +129,7 @@ TEST(InlineTwice) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -137,6 +144,7 @@ TEST(InlineTwiceDependent) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -152,6 +160,7 @@ TEST(InlineTwiceDependentDiamond) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {" @@ -167,6 +176,7 @@ TEST(InlineTwiceDependentDiamondReal) { + FLAG_context_specialization = true; FLAG_turbo_inlining = true; FunctionTester T( "(function () {"
diff --git a/test/cctest/compiler/test-run-jsbranches.cc b/test/cctest/compiler/test-run-jsbranches.cc index 2eb4fa6..df2fcdc 100644 --- a/test/cctest/compiler/test-run-jsbranches.cc +++ b/test/cctest/compiler/test-run-jsbranches.cc
@@ -148,6 +148,26 @@ } +TEST(ForInContinueStatement) { + const char* src = + "(function(a,b) {" + " var r = '-';" + " for (var x in a) {" + " r += 'A-';" + " if (b) continue;" + " r += 'B-';" + " }" + " return r;" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val("-A-B-"), T.NewObject("({x:1})"), T.false_value()); + T.CheckCall(T.Val("-A-B-A-B-"), T.NewObject("({x:1,y:2})"), T.false_value()); + T.CheckCall(T.Val("-A-"), T.NewObject("({x:1})"), T.true_value()); + T.CheckCall(T.Val("-A-A-"), T.NewObject("({x:1,y:2})"), T.true_value()); +} + + TEST(SwitchStatement) { const char* src = "(function(a,b) {"
diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index 2c7d16f..9a80daf 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc
@@ -2672,10 +2672,10 @@ } -template <typename Type, typename CType> +template <typename Type> static void RunLoadImmIndex(MachineType rep) { const int kNumElems = 3; - CType buffer[kNumElems]; + Type buffer[kNumElems]; // initialize the buffer with raw data. byte* raw = reinterpret_cast<byte*>(buffer); @@ -2692,19 +2692,21 @@ m.Return(m.Load(rep, base, index)); Type expected = buffer[i]; - Type actual = static_cast<CType>(m.Call()); - CHECK_EQ(expected, actual); - printf("XXX\n"); + Type actual = m.Call(); + CHECK(expected == actual); } } } TEST(RunLoadImmIndex) { - RunLoadImmIndex<int8_t, uint8_t>(kMachInt8); - RunLoadImmIndex<int16_t, uint16_t>(kMachInt16); - RunLoadImmIndex<int32_t, uint32_t>(kMachInt32); - RunLoadImmIndex<int32_t*, int32_t*>(kMachAnyTagged); + RunLoadImmIndex<int8_t>(kMachInt8); + RunLoadImmIndex<uint8_t>(kMachUint8); + RunLoadImmIndex<int16_t>(kMachInt16); + RunLoadImmIndex<uint16_t>(kMachUint16); + RunLoadImmIndex<int32_t>(kMachInt32); + RunLoadImmIndex<uint32_t>(kMachUint32); + RunLoadImmIndex<int32_t*>(kMachAnyTagged); // TODO(titzer): test kRepBit loads // TODO(titzer): test kMachFloat64 loads @@ -2734,17 +2736,20 @@ m.Store(rep, base, index1, load); m.Return(m.Int32Constant(OK)); - CHECK_NE(buffer[x], buffer[y]); + CHECK(buffer[x] != buffer[y]); CHECK_EQ(OK, m.Call()); - CHECK_EQ(buffer[x], buffer[y]); + CHECK(buffer[x] == buffer[y]); } } TEST(RunLoadStore) { RunLoadStore<int8_t>(kMachInt8); + RunLoadStore<uint8_t>(kMachUint8); RunLoadStore<int16_t>(kMachInt16); + RunLoadStore<uint16_t>(kMachUint16); RunLoadStore<int32_t>(kMachInt32); + RunLoadStore<uint32_t>(kMachUint32); RunLoadStore<void*>(kMachAnyTagged); RunLoadStore<double>(kMachFloat64); } @@ -3792,15 +3797,15 @@ // Test lower bound. input = min; - CHECK_EQ(max + 2, m.Call()); + CHECK_EQ(static_cast<IntType>(max + 2), m.Call()); CHECK_EQ(min + 1, input); // Test all one byte values that are not one byte bounds. for (int i = -127; i < 127; i++) { input = i; int expected = i >= 0 ? i + 1 : max + (i - min) + 2; - CHECK_EQ(expected, m.Call()); - CHECK_EQ(i + 1, input); + CHECK_EQ(static_cast<IntType>(expected), m.Call()); + CHECK_EQ(static_cast<IntType>(i + 1), input); } }
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 1a292fc..c910f0e 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc
@@ -1556,6 +1556,42 @@ } +THREADED_TEST(IsMapOrSet) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::Handle<Value> map = CompileRun("new Map()"); + v8::Handle<Value> set = CompileRun("new Set()"); + v8::Handle<Value> weak_map = CompileRun("new WeakMap()"); + v8::Handle<Value> weak_set = CompileRun("new WeakSet()"); + CHECK(map->IsMap()); + CHECK(set->IsSet()); + CHECK(weak_map->IsWeakMap()); + CHECK(weak_set->IsWeakSet()); + + CHECK(!map->IsSet()); + CHECK(!map->IsWeakMap()); + CHECK(!map->IsWeakSet()); + + CHECK(!set->IsMap()); + CHECK(!set->IsWeakMap()); + CHECK(!set->IsWeakSet()); + + CHECK(!weak_map->IsMap()); + CHECK(!weak_map->IsSet()); + CHECK(!weak_map->IsWeakSet()); + + CHECK(!weak_set->IsMap()); + CHECK(!weak_set->IsSet()); + CHECK(!weak_set->IsWeakMap()); + + v8::Handle<Value> object = CompileRun("{a:42}"); + CHECK(!object->IsMap()); + CHECK(!object->IsSet()); + CHECK(!object->IsWeakMap()); + CHECK(!object->IsWeakSet()); +} + + THREADED_TEST(StringObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -2009,7 +2045,7 @@ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::LookupResult lookup(i_isolate); i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); - i::LookupIterator it(a, name, i::LookupIterator::CHECK_PROPERTY); + i::LookupIterator it(a, name, i::LookupIterator::OWN_PROPERTY); CHECK(it.HasProperty()); CHECK(it.GetAccessors()->IsExecutableAccessorInfo()); }
diff --git a/test/cctest/test-disasm-x87.cc b/test/cctest/test-disasm-x87.cc index 1515cc7..17c49af 100644 --- a/test/cctest/test-disasm-x87.cc +++ b/test/cctest/test-disasm-x87.cc
@@ -32,9 +32,9 @@ #include "src/debug.h" #include "src/disasm.h" #include "src/disassembler.h" +#include "src/ic/ic.h" #include "src/macro-assembler.h" #include "src/serialize.h" -#include "src/stub-cache.h" #include "test/cctest/cctest.h" using namespace v8::internal;
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 462979d..0fef82d 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc
@@ -4050,6 +4050,7 @@ TEST(NextCodeLinkIsWeak) { i::FLAG_allow_natives_syntax = true; + i::FLAG_turbo_deoptimization = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); v8::internal::Heap* heap = CcTest::heap();
diff --git a/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc b/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc index 843285e..d8fbcf1 100644 --- a/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc +++ b/test/compiler-unittests/arm/instruction-selector-arm-unittest.cc
@@ -1188,6 +1188,140 @@ // ----------------------------------------------------------------------------- +// Memory access instructions. + + +namespace { + +struct MemoryAccess { + MachineType type; + ArchOpcode ldr_opcode; + ArchOpcode str_opcode; + const int32_t immediates[40]; +}; + + +std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { + OStringStream ost; + ost << memacc.type; + return os << ost.c_str(); +} + + +static const MemoryAccess kMemoryAccesses[] = { + {kMachInt8, + kArmLdrsb, + kArmStrb, + {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89, + -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109, + 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}}, + {kMachUint8, + kArmLdrb, + kArmStrb, + {-4095, -3914, -3536, -3234, -3185, -3169, -1073, -990, -859, -720, -434, + -127, -124, -122, -105, -91, -86, -64, -55, -53, -30, -10, -3, 0, 20, 28, + 39, 58, 64, 73, 75, 100, 108, 121, 686, 963, 1363, 2759, 3449, 4095}}, + {kMachInt16, + kArmLdrsh, + kArmStrh, + {-255, -251, -232, -220, -144, -138, -130, -126, -116, -115, -102, -101, + -98, -69, -59, -56, -39, -35, -23, -19, -7, 0, 22, 26, 37, 68, 83, 87, 98, + 102, 108, 111, 117, 171, 195, 203, 204, 245, 246, 255}}, + {kMachUint16, + kArmLdrh, + kArmStrh, + {-255, -230, -201, -172, -125, -119, -118, -105, -98, -79, -54, -42, -41, + -32, -12, -11, -5, -4, 0, 5, 9, 25, 28, 51, 58, 60, 89, 104, 108, 109, + 114, 116, 120, 138, 150, 161, 166, 172, 228, 255}}, + {kMachInt32, + kArmLdr, + kArmStr, + {-4095, -1898, -1685, -1562, -1408, -1313, -344, -128, -116, -100, -92, + -80, -72, -71, -56, -25, -21, -11, -9, 0, 3, 5, 27, 28, 42, 52, 63, 88, + 93, 97, 125, 846, 1037, 2102, 2403, 2597, 2632, 2997, 3935, 4095}}, + {kMachFloat64, + kArmVldr64, + kArmVstr64, + {-1020, -948, -796, -696, -612, -364, -320, -308, -128, -112, -108, -104, + -96, -84, -80, -56, -48, -40, -20, 0, 24, 28, 36, 48, 64, 84, 96, 100, + 108, 116, 120, 140, 156, 408, 432, 444, 772, 832, 940, 1020}}}; + +} // namespace + + +typedef InstructionSelectorTestWithParam<MemoryAccess> + InstructionSelectorMemoryAccessTest; + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, memacc.type, kMachPtr); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, memacc.immediates) { + StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index), + m.Parameter(1)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessTest, + ::testing::ValuesIn(kMemoryAccesses)); + + +// ----------------------------------------------------------------------------- // Miscellaneous.
diff --git a/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc b/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc index a0c3ab5..109986c 100644 --- a/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc +++ b/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc
@@ -298,6 +298,76 @@ EXPECT_EQ(kArm64Mov32, s[0]->arch_opcode()); } + +// ----------------------------------------------------------------------------- +// Memory access instructions. + + +namespace { + +struct MemoryAccess { + MachineType type; + ArchOpcode ldr_opcode; + ArchOpcode str_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { + OStringStream ost; + ost << memacc.type; + return os << ost.c_str(); +} + +} // namespace + + +static const MemoryAccess kMemoryAccesses[] = { + {kMachInt8, kArm64Ldrsb, kArm64Strb}, + {kMachUint8, kArm64Ldrb, kArm64Strb}, + {kMachInt16, kArm64Ldrsh, kArm64Strh}, + {kMachUint16, kArm64Ldrh, kArm64Strh}, + {kMachInt32, kArm64LdrW, kArm64StrW}, + {kMachUint32, kArm64LdrW, kArm64StrW}, + {kMachInt64, kArm64Ldr, kArm64Str}, + {kMachUint64, kArm64Ldr, kArm64Str}, + {kMachFloat64, kArm64LdrD, kArm64StrD}}; + + +typedef InstructionSelectorTestWithParam<MemoryAccess> + InstructionSelectorMemoryAccessTest; + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_MRR, s[0]->addressing_mode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0U, s[0]->OutputCount()); +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessTest, + ::testing::ValuesIn(kMemoryAccesses)); + } // namespace compiler } // namespace internal } // namespace v8
diff --git a/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc b/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc index c9431ea..bab8f94 100644 --- a/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc +++ b/test/compiler-unittests/ia32/instruction-selector-ia32-unittest.cc
@@ -73,6 +73,138 @@ } } + +// ----------------------------------------------------------------------------- +// Loads and stores + +namespace { + +struct MemoryAccess { + MachineType type; + ArchOpcode load_opcode; + ArchOpcode store_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { + OStringStream ost; + ost << memacc.type; + return os << ost.c_str(); +} + + +static const MemoryAccess kMemoryAccesses[] = { + {kMachInt8, kIA32Movsxbl, kIA32Movb}, + {kMachUint8, kIA32Movzxbl, kIA32Movb}, + {kMachInt16, kIA32Movsxwl, kIA32Movw}, + {kMachUint16, kIA32Movzxwl, kIA32Movw}, + {kMachInt32, kIA32Movl, kIA32Movl}, + {kMachUint32, kIA32Movl, kIA32Movl}, + {kMachFloat64, kIA32Movsd, kIA32Movsd}}; + +} // namespace + + +typedef InstructionSelectorTestWithParam<MemoryAccess> + InstructionSelectorMemoryAccessTest; + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateBase) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, base, kImmediates) { + StreamBuilder m(this, memacc.type, kMachPtr); + m.Return(m.Load(memacc.type, m.Int32Constant(base), m.Parameter(0))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, kImmediates) { + StreamBuilder m(this, memacc.type, kMachPtr); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateBase) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, base, kImmediates) { + StreamBuilder m(this, kMachInt32, kMachInt32, memacc.type); + m.Store(memacc.type, m.Int32Constant(base), m.Parameter(0), m.Parameter(1)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(base, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) { + const MemoryAccess memacc = GetParam(); + TRACED_FOREACH(int32_t, index, kImmediates) { + StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index), + m.Parameter(1)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); + EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(0U, s[0]->OutputCount()); + } +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessTest, + ::testing::ValuesIn(kMemoryAccesses)); + } // namespace compiler } // namespace internal } // namespace v8
diff --git a/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc b/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc index 4e5c655..2d815a3 100644 --- a/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc +++ b/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc
@@ -38,6 +38,73 @@ EXPECT_EQ(kX64Movl, s[0]->arch_opcode()); } + +// ----------------------------------------------------------------------------- +// Loads and stores + +namespace { + +struct MemoryAccess { + MachineType type; + ArchOpcode load_opcode; + ArchOpcode store_opcode; +}; + + +std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) { + OStringStream ost; + ost << memacc.type; + return os << ost.c_str(); +} + + +static const MemoryAccess kMemoryAccesses[] = { + {kMachInt8, kX64Movsxbl, kX64Movb}, + {kMachUint8, kX64Movzxbl, kX64Movb}, + {kMachInt16, kX64Movsxwl, kX64Movw}, + {kMachUint16, kX64Movzxwl, kX64Movw}, + {kMachInt32, kX64Movl, kX64Movl}, + {kMachUint32, kX64Movl, kX64Movl}, + {kMachInt64, kX64Movq, kX64Movq}, + {kMachUint64, kX64Movq, kX64Movq}, + {kMachFloat64, kX64Movsd, kX64Movsd}}; + +} // namespace + + +typedef InstructionSelectorTestWithParam<MemoryAccess> + InstructionSelectorMemoryAccessTest; + + +TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32); + m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.load_opcode, s[0]->arch_opcode()); + EXPECT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) { + const MemoryAccess memacc = GetParam(); + StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type); + m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2)); + m.Return(m.Int32Constant(0)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(memacc.store_opcode, s[0]->arch_opcode()); + EXPECT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(0U, s[0]->OutputCount()); +} + + +INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, + InstructionSelectorMemoryAccessTest, + ::testing::ValuesIn(kMemoryAccesses)); + } // namespace compiler } // namespace internal } // namespace v8
diff --git a/test/mjsunit/es6/arguments-iterator.js b/test/mjsunit/es6/arguments-iterator.js new file mode 100644 index 0000000..a65bf8b --- /dev/null +++ b/test/mjsunit/es6/arguments-iterator.js
@@ -0,0 +1,230 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + + +// Note in general that "arguments.foo" and "var o = arguments; o.foo" +// are treated differently by full-codegen, and so both cases need to be +// tested. + +function TestDirectArgumentsIteratorProperty() { + assertTrue(arguments.hasOwnProperty(Symbol.iterator)); + assertFalse(arguments.propertyIsEnumerable(Symbol.iterator)); + var descriptor = Object.getOwnPropertyDescriptor(arguments, Symbol.iterator); + assertTrue(descriptor.writable); + assertFalse(descriptor.enumerable); + assertTrue(descriptor.configurable); + assertEquals(descriptor.value, [].values); + assertEquals(arguments[Symbol.iterator], [].values); +} +TestDirectArgumentsIteratorProperty(); + + +function TestIndirectArgumentsIteratorProperty() { + var o = arguments; + assertTrue(o.hasOwnProperty(Symbol.iterator)); + assertFalse(o.propertyIsEnumerable(Symbol.iterator)); + assertEquals(o[Symbol.iterator], [].values); +} +TestIndirectArgumentsIteratorProperty(); + + +function assertIteratorResult(value, done, result) { + assertEquals({value: value, done: done}, result); +} + + +function TestDirectValues1(a, b, c) { + var iterator = arguments[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); +} +TestDirectValues1(1, 2, 3); + + +function TestIndirectValues1(a, b, c) { + var args = arguments; + var iterator = args[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); +} +TestIndirectValues1(1, 2, 3); + + +function TestDirectValues2(a, b, c) { + var iterator = arguments[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); + + arguments[3] = 4; + arguments.length = 4; + assertIteratorResult(undefined, true, iterator.next()); +} +TestDirectValues2(1, 2, 3); + + +function TestIndirectValues2(a, b, c) { + var args = arguments; + var iterator = args[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); + + arguments[3] = 4; + arguments.length = 4; + assertIteratorResult(undefined, true, iterator.next()); +} +TestIndirectValues2(1, 2, 3); + + +function TestDirectValues3(a, b, c) { + var iterator = arguments[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + + arguments.length = 2; + assertIteratorResult(undefined, true, iterator.next()); +} +TestDirectValues3(1, 2, 3); + + +function TestIndirectValues3(a, b, c) { + var args = arguments; + var iterator = args[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + + arguments.length = 2; + assertIteratorResult(undefined, true, iterator.next()); +} +TestIndirectValues3(1, 2, 3); + + +function TestDirectValues4(a, b, c) { + var iterator = arguments[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + + arguments.length = 4; + assertIteratorResult(undefined, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); +} +TestDirectValues4(1, 2, 3); + + +function TestIndirectValues4(a, b, c) { + var args = arguments; + var iterator = args[Symbol.iterator](); + assertIteratorResult(a, false, iterator.next()); + assertIteratorResult(b, false, iterator.next()); + assertIteratorResult(c, false, iterator.next()); + + arguments.length = 4; + assertIteratorResult(undefined, false, iterator.next()); + assertIteratorResult(undefined, true, iterator.next()); +} +TestIndirectValues4(1, 2, 3); + + +function TestForOf() { + var i = 0; + for (var value of arguments) { + assertEquals(arguments[i++], value); + } + + assertEquals(arguments.length, i); +} +TestForOf(1, 2, 3, 4, 5); + + +function TestAssignmentToIterator() { + var i = 0; + arguments[Symbol.iterator] = [].entries; + for (var entry of arguments) { + assertEquals([i, arguments[i]], entry); + i++; + } + + assertEquals(arguments.length, i); +} +TestAssignmentToIterator(1, 2, 3, 4, 5); + + +function TestArgumentsMutation() { + var i = 0; + for (var x of arguments) { + assertEquals(arguments[i], x); + arguments[i+1] *= 2; + i++; + } + + assertEquals(arguments.length, i); +} +TestArgumentsMutation(1, 2, 3, 4, 5); + + +function TestSloppyArgumentsAliasing(a0, a1, a2, a3, a4) { + var i = 0; + for (var x of arguments) { + assertEquals(arguments[i], x); + a0 = a1; a1 = a2; a3 = a4; + i++; + } + + assertEquals(arguments.length, i); +} +TestSloppyArgumentsAliasing(1, 2, 3, 4, 5); + + +function TestStrictArgumentsAliasing(a0, a1, a2, a3, a4) { + "use strict"; + var i = 0; + for (var x of arguments) { + a0 = a1; a1 = a2; a3 = a4; + assertEquals(arguments[i], x); + i++; + } + + assertEquals(arguments.length, i); +} +TestStrictArgumentsAliasing(1, 2, 3, 4, 5); + + +function TestArgumentsAsProto() { + "use strict"; + + var o = {__proto__:arguments}; + assertSame([].values, o[Symbol.iterator]); + // Make o dict-mode. + %OptimizeObjectForAddingMultipleProperties(o, 0); + assertFalse(o.hasOwnProperty(Symbol.iterator)); + assertSame([].values, o[Symbol.iterator]); + o[Symbol.iterator] = 10; + assertTrue(o.hasOwnProperty(Symbol.iterator)); + assertEquals(10, o[Symbol.iterator]); + assertSame([].values, arguments[Symbol.iterator]); + + // Frozen o. + o = Object.freeze({__proto__:arguments}); + assertSame([].values, o[Symbol.iterator]); + assertFalse(o.hasOwnProperty(Symbol.iterator)); + assertSame([].values, o[Symbol.iterator]); + // This should throw, but currently it doesn't, because + // ExecutableAccessorInfo callbacks don't see the current strict mode. + // See note in accessors.cc:SetPropertyOnInstanceIfInherited. + o[Symbol.iterator] = 10; + assertFalse(o.hasOwnProperty(Symbol.iterator)); + assertEquals([].values, o[Symbol.iterator]); + assertSame([].values, arguments[Symbol.iterator]); +} +TestArgumentsAsProto();
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index 3dafda6..2183c31 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status
@@ -97,8 +97,6 @@ 'deserialize-reference': [PASS, NO_VARIANTS], # Support for %GetFrameDetails is missing and requires checkpoints. - 'debug-backtrace-text': [PASS, NO_VARIANTS], - 'debug-break-inline': [PASS, NO_VARIANTS], 'debug-evaluate-bool-constructor': [PASS, NO_VARIANTS], 'debug-evaluate-closure': [PASS, NO_VARIANTS], 'debug-evaluate-const': [PASS, NO_VARIANTS], @@ -162,6 +160,7 @@ 'es6/iteration-semantics': [PASS, NO_VARIANTS], 'es6/string-iterator': [PASS, NO_VARIANTS], 'es6/typed-array-iterator': [PASS, NO_VARIANTS], + 'es6/arguments-iterator': [PASS, NO_VARIANTS], ############################################################################## # Too slow in debug mode with --stress-opt mode.
diff --git a/test/test262-es6/test262-es6.status b/test/test262-es6/test262-es6.status index ceac845..73f4477 100644 --- a/test/test262-es6/test262-es6.status +++ b/test/test262-es6/test262-es6.status
@@ -38,51 +38,7 @@ '11.2.3_b': [FAIL], '12.2.3_b': [FAIL], - ###################### NEEDS INVESTIGATION (2014) ####################### - - # Cause unknown. - 'bug_596_1': [FAIL], - - # New ES6 Array functions. - 'S22.1.2.1_T1': [FAIL], - 'S22.1.2.1_T2': [FAIL], - 'S22.1.2.3_T1': [FAIL], - 'S22.1.2.3_T2': [FAIL], - 'S22.1.3.6_T1': [FAIL], - - # New ES6 function String.prototype.contains, unimplemented in v8. - 'String.prototype.contains_FailBadLocation': [FAIL], - 'String.prototype.contains_FailLocation': [FAIL], - 'String.prototype.contains_FailMissingLetter': [FAIL], - 'String.prototype.contains_Success': [FAIL], - 'String.prototype.contains_SuccessNoLocation': [FAIL], - 'String.prototype.contains_lengthProp': [FAIL], - - # New ES6 function String.prototype.endsWith, unimplemented in v8. - 'String.prototype.endsWith_Fail': [FAIL], - 'String.prototype.endsWith_Fail_2': [FAIL], - 'String.prototype.endsWith_Success': [FAIL], - 'String.prototype.endsWith_Success_2': [FAIL], - 'String.prototype.endsWith_Success_3': [FAIL], - 'String.prototype.endsWith_Success_4': [FAIL], - - # New ES6 function Array.prototype.find, unimplemented in v8. - 'Array.prototype.find_callable-predicate': [FAIL], - 'Array.prototype.find_empty-array-undefined': [FAIL], - 'Array.prototype.find_length-property': [FAIL], - 'Array.prototype.find_modify-after-start': [FAIL], - 'Array.prototype.find_non-returning-predicate': [FAIL], - 'Array.prototype.find_predicate-arguments': [FAIL], - 'Array.prototype.find_push-after-start': [FAIL], - 'Array.prototype.find_remove-after-start': [FAIL], - 'Array.prototype.find_return-found-value': [FAIL], - 'Array.prototype.find_skip-empty': [FAIL], - 'Array.prototype.find_this-defined': [FAIL], - 'Array.prototype.find_this-is-object': [FAIL], - 'Array.prototype.find_this-undefined': [FAIL], - - # This negative test fails for the wrong reason. - #'Array.prototype.find_noncallable-predicate': [FAIL], + ###################### NEEDS INVESTIGATION ####################### # Possibly same cause as S8.5_A2.1, below: floating-point tests. 'S15.8.2.16_A7': [PASS, FAIL_OK], @@ -94,6 +50,40 @@ # https://code.google.com/p/v8/issues/detail?id=705 '12.6.4-2': [PASS, FAIL_OK], + ###################### MISSING ES6 FEATURES ####################### + + # Array.from + 'S22.1.2.1_T1': [FAIL], + 'S22.1.2.1_T2': [FAIL], + + # Direct proxies + 'Array.prototype.find_callable-predicate': [FAIL], + + ######################## OBSOLETED BY ES6 ########################### + + # ES6 allows duplicate properties + # TODO(arv): Reactivate when check removal has relanded. + # '11.1.5-4-4-a-1-s': [FAIL], + # '11.1.5_4-4-b-1': [FAIL], + # '11.1.5_4-4-b-2': [FAIL], + # '11.1.5_4-4-c-1': [FAIL], + # '11.1.5_4-4-c-2': [FAIL], + # '11.1.5_4-4-d-1': [FAIL], + # '11.1.5_4-4-d-2': [FAIL], + # '11.1.5_4-4-d-3': [FAIL], + # '11.1.5_4-4-d-4': [FAIL], + + # ES6 allows block-local functions. + 'Sbp_A1_T1': [FAIL], + 'Sbp_A2_T1': [FAIL], + 'Sbp_A2_T2': [FAIL], + 'Sbp_A3_T1': [FAIL], + 'Sbp_A3_T2': [FAIL], + 'Sbp_A4_T1': [FAIL], + 'Sbp_A4_T2': [FAIL], + 'Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable) + 'Sbp_A5_T2': [FAIL], + ######################## NEEDS INVESTIGATION ########################### # These test failures are specific to the intl402 suite and need investigation @@ -133,17 +123,6 @@ 'S8.5_A2.1': [PASS, FAIL_OK], 'S8.5_A2.2': [PASS, FAIL_OK], - # ES6 allows duplicate properties - '11.1.5-4-4-a-1-s': [FAIL], - '11.1.5_4-4-b-1': [FAIL], - '11.1.5_4-4-b-2': [FAIL], - '11.1.5_4-4-c-1': [FAIL], - '11.1.5_4-4-c-2': [FAIL], - '11.1.5_4-4-d-1': [FAIL], - '11.1.5_4-4-d-2': [FAIL], - '11.1.5_4-4-d-3': [FAIL], - '11.1.5_4-4-d-4': [FAIL], - ############################ INVALID TESTS ############################# # The reference value calculated by Test262 is incorrect if you run these @@ -157,6 +136,10 @@ 'S15.9.3.1_A5_T5': [PASS, FAIL_OK], 'S15.9.3.1_A5_T6': [PASS, FAIL_OK], + # Test makes unjustified assumptions about the number of calls to SortCompare. + # Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=596 + 'bug_596_1': [PASS, FAIL_OK], + ############################ SKIPPED TESTS ############################# # These tests take a looong time to run in debug mode.
diff --git a/test/test262-es6/testcfg.py b/test/test262-es6/testcfg.py index 5231f38..7107f95 100644 --- a/test/test262-es6/testcfg.py +++ b/test/test262-es6/testcfg.py
@@ -79,7 +79,7 @@ def GetFlagsForTestCase(self, testcase, context): return (testcase.flags + context.mode_flags + self.harness + - self.GetIncludesForTest(testcase) + + self.GetIncludesForTest(testcase) + ["--harmony"] + [os.path.join(self.testroot, testcase.path + ".js")]) def LoadParseTestRecord(self):
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index f6279a1..052b83e 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp
@@ -603,6 +603,8 @@ '../../src/ic/access-compiler.h', '../../src/ic/call-optimization.cc', '../../src/ic/call-optimization.h', + '../../src/ic/handler-compiler.cc', + '../../src/ic/handler-compiler.h', '../../src/ic/ic-inl.h', '../../src/ic/ic.cc', '../../src/ic/ic.h', @@ -794,6 +796,7 @@ '../../src/compiler/arm/instruction-selector-arm.cc', '../../src/compiler/arm/linkage-arm.cc', '../../src/ic/arm/access-compiler-arm.cc', + '../../src/ic/arm/handler-compiler-arm.cc', '../../src/ic/arm/ic-arm.cc', '../../src/ic/arm/ic-compiler-arm.cc', '../../src/ic/arm/stub-cache-arm.cc', @@ -848,6 +851,7 @@ '../../src/compiler/arm64/instruction-selector-arm64.cc', '../../src/compiler/arm64/linkage-arm64.cc', '../../src/ic/arm64/access-compiler-arm64.cc', + '../../src/ic/arm64/handler-compiler-arm64.cc', '../../src/ic/arm64/ic-arm64.cc', '../../src/ic/arm64/ic-compiler-arm64.cc', '../../src/ic/arm64/stub-cache-arm64.cc', @@ -885,6 +889,7 @@ '../../src/compiler/ia32/instruction-selector-ia32.cc', '../../src/compiler/ia32/linkage-ia32.cc', '../../src/ic/ia32/access-compiler-ia32.cc', + '../../src/ic/ia32/handler-compiler-ia32.cc', '../../src/ic/ia32/ic-ia32.cc', '../../src/ic/ia32/ic-compiler-ia32.cc', '../../src/ic/ia32/stub-cache-ia32.cc', @@ -907,7 +912,6 @@ '../../src/x87/frames-x87.cc', '../../src/x87/frames-x87.h', '../../src/x87/full-codegen-x87.cc', - '../../src/x87/ic-x87.cc', '../../src/x87/lithium-codegen-x87.cc', '../../src/x87/lithium-codegen-x87.h', '../../src/x87/lithium-gap-resolver-x87.cc', @@ -918,7 +922,10 @@ '../../src/x87/macro-assembler-x87.h', '../../src/x87/regexp-macro-assembler-x87.cc', '../../src/x87/regexp-macro-assembler-x87.h', - '../../src/x87/stub-cache-x87.cc', + '../../src/ic/x87/access-compiler-x87.cc', + '../../src/ic/x87/ic-x87.cc', + '../../src/ic/x87/ic-compiler-x87.cc', + '../../src/ic/x87/stub-cache-x87.cc', ], }], ['v8_target_arch=="mips" or v8_target_arch=="mipsel"', { @@ -940,7 +947,6 @@ '../../src/mips/frames-mips.cc', '../../src/mips/frames-mips.h', '../../src/mips/full-codegen-mips.cc', - '../../src/mips/ic-mips.cc', '../../src/mips/lithium-codegen-mips.cc', '../../src/mips/lithium-codegen-mips.h', '../../src/mips/lithium-gap-resolver-mips.cc', @@ -952,7 +958,11 @@ '../../src/mips/regexp-macro-assembler-mips.cc', '../../src/mips/regexp-macro-assembler-mips.h', '../../src/mips/simulator-mips.cc', - '../../src/mips/stub-cache-mips.cc', + '../../src/ic/mips/access-compiler-mips.cc', + '../../src/ic/mips/handler-compiler-mips.cc', + '../../src/ic/mips/ic-mips.cc', + '../../src/ic/mips/ic-compiler-mips.cc', + '../../src/ic/mips/stub-cache-mips.cc', ], }], ['v8_target_arch=="mips64el"', { @@ -974,7 +984,6 @@ '../../src/mips64/frames-mips64.cc', '../../src/mips64/frames-mips64.h', '../../src/mips64/full-codegen-mips64.cc', - '../../src/mips64/ic-mips64.cc', '../../src/mips64/lithium-codegen-mips64.cc', '../../src/mips64/lithium-codegen-mips64.h', '../../src/mips64/lithium-gap-resolver-mips64.cc', @@ -986,7 +995,11 @@ '../../src/mips64/regexp-macro-assembler-mips64.cc', '../../src/mips64/regexp-macro-assembler-mips64.h', '../../src/mips64/simulator-mips64.cc', - '../../src/mips64/stub-cache-mips64.cc', + '../../src/ic/mips64/access-compiler-mips64.cc', + '../../src/ic/mips64/handler-compiler-mips64.cc', + '../../src/ic/mips64/ic-mips64.cc', + '../../src/ic/mips64/ic-compiler-mips64.cc', + '../../src/ic/mips64/stub-cache-mips64.cc', ], }], ['v8_target_arch=="x64" or v8_target_arch=="x32"', { @@ -1021,6 +1034,7 @@ '../../src/compiler/x64/instruction-selector-x64.cc', '../../src/compiler/x64/linkage-x64.cc', '../../src/ic/x64/access-compiler-x64.cc', + '../../src/ic/x64/handler-compiler-x64.cc', '../../src/ic/x64/ic-x64.cc', '../../src/ic/x64/ic-compiler-x64.cc', '../../src/ic/x64/stub-cache-x64.cc',
diff --git a/tools/push-to-trunk/git_recipes.py b/tools/push-to-trunk/git_recipes.py index 6ffb2da..1cbd8f5 100644 --- a/tools/push-to-trunk/git_recipes.py +++ b/tools/push-to-trunk/git_recipes.py
@@ -28,6 +28,9 @@ import re +SHA1_RE = re.compile('^[a-fA-F0-9]{40}$') +GIT_SVN_ID_RE = re.compile('^git-svn-id: .*@([0-9]+) .*$') + class GitFailedException(Exception): pass @@ -185,6 +188,20 @@ def GitPull(self): self.Git("pull") + def GitFetchOrigin(self): + self.Git("fetch origin") + + def GitConvertToSVNRevision(self, git_hash): + result = self.Git(MakeArgs(["rev-list", "-n", "1", git_hash])) + if not result or not SHA1_RE.match(result): + raise GitFailedException("Git hash %s is unknown." % git_hash) + log = self.GitLog(n=1, format="%B", git_hash=git_hash) + for line in reversed(log.splitlines()): + match = GIT_SVN_ID_RE.match(line.strip()) + if match: + return match.group(1) + raise GitFailedException("Couldn't convert %s to SVN." % git_hash) + def GitSVNFetch(self): self.Git("svn fetch")
diff --git a/tools/push-to-trunk/releases.py b/tools/push-to-trunk/releases.py index 586cbc1..239189e 100755 --- a/tools/push-to-trunk/releases.py +++ b/tools/push-to-trunk/releases.py
@@ -47,10 +47,10 @@ # Expression with three versions (historical) for extracting the v8 revision # from the chromium DEPS file. -DEPS_RE = re.compile(r'^\s*(?:"v8_revision": "' - '|\(Var\("googlecode_url"\) % "v8"\) \+ "\/trunk@' - '|"http\:\/\/v8\.googlecode\.com\/svn\/trunk@)' - '([0-9]+)".*$', re.M) +DEPS_RE = re.compile(r"""^\s*(?:["']v8_revision["']: ["']""" + """|\(Var\("googlecode_url"\) % "v8"\) \+ "\/trunk@""" + """|"http\:\/\/v8\.googlecode\.com\/svn\/trunk@)""" + """([^"']+)["'].*$""", re.M) # Expression to pick tag and revision for bleeding edge tags. To be used with # output of 'svn log'. @@ -374,6 +374,18 @@ self.GitCreateBranch(self.Config(BRANCHNAME)) +def ConvertToCommitNumber(step, revision): + # Simple check for git hashes. + if revision.isdigit() and len(revision) < 8: + return revision + try: + # TODO(machenbach): Add cwd to git calls. + os.chdir(os.path.join(step["chrome_path"], "v8")) + return step.GitConvertToSVNRevision(revision) + finally: + os.chdir(step["chrome_path"]) + + class RetrieveChromiumV8Releases(Step): MESSAGE = "Retrieve V8 releases from Chromium DEPS." REQUIRES = "chrome_path" @@ -387,6 +399,14 @@ print "No releases detected. Skipping chromium history." return True + # Update v8 checkout in chromium. + try: + # TODO(machenbach): Add cwd to git calls. + os.chdir(os.path.join(self["chrome_path"], "v8")) + self.GitFetchOrigin() + finally: + os.chdir(self["chrome_path"]) + oldest_v8_rev = int(releases[-1]["revision"]) cr_releases = [] @@ -401,7 +421,7 @@ if match: cr_rev = GetCommitPositionNumber(self, git_hash) if cr_rev: - v8_rev = match.group(1) + v8_rev = ConvertToCommitNumber(self, match.group(1)) cr_releases.append([cr_rev, v8_rev]) # Stop after reaching beyond the last v8 revision we want to update. @@ -458,7 +478,7 @@ deps = FileToText(self.Config(DEPS_FILE)) match = DEPS_RE.search(deps) if match: - v8_rev = match.group(1) + v8_rev = ConvertToCommitNumber(self, match.group(1)) cr_branches.append([str(branch), v8_rev]) # Stop after reaching beyond the last v8 revision we want to update.
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py index 7a40985..4b1f638 100644 --- a/tools/push-to-trunk/test_scripts.py +++ b/tools/push-to-trunk/test_scripts.py
@@ -1214,6 +1214,11 @@ git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3456 0039-1c4b """ + c_v8_22624_log = """V8 CL. + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22624 123 + +""" json_output = self.MakeEmptyTempFile() csv_output = self.MakeEmptyTempFile() TEST_CONFIG[VERSION_FILE] = self.MakeEmptyTempFile() @@ -1222,6 +1227,8 @@ TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile() if not os.path.exists(TEST_CONFIG[CHROMIUM]): os.makedirs(TEST_CONFIG[CHROMIUM]) + if not os.path.exists(os.path.join(TEST_CONFIG[CHROMIUM], "v8")): + os.makedirs(os.path.join(TEST_CONFIG[CHROMIUM], "v8")) def WriteDEPS(revision): TextToFile("Line\n \"v8_revision\": \"%s\",\n line\n" % revision, TEST_CONFIG[DEPS_FILE]) @@ -1290,12 +1297,17 @@ Git("checkout -f master", ""), Git("pull", ""), Git("checkout -b %s" % TEST_CONFIG[BRANCHNAME], ""), + Git("fetch origin", ""), Git("log --format=%H --grep=\"V8\"", "c_hash1\nc_hash2\nc_hash3\n"), Git("diff --name-only c_hash1 c_hash1^", ""), Git("diff --name-only c_hash2 c_hash2^", TEST_CONFIG[DEPS_FILE]), Git("checkout -f c_hash2 -- %s" % TEST_CONFIG[DEPS_FILE], "", - cb=ResetDEPS(22624)), + cb=ResetDEPS("0123456789012345678901234567890123456789")), Git("log -1 --format=%B c_hash2", c_hash2_commit_log), + Git("rev-list -n 1 0123456789012345678901234567890123456789", + "0123456789012345678901234567890123456789"), + Git("log -1 --format=%B 0123456789012345678901234567890123456789", + c_v8_22624_log), Git("diff --name-only c_hash3 c_hash3^", TEST_CONFIG[DEPS_FILE]), Git("checkout -f c_hash3 -- %s" % TEST_CONFIG[DEPS_FILE], "", cb=ResetDEPS(345)),
diff --git a/tools/run_benchmarks.py b/tools/run_benchmarks.py index d6e9145..b74f358 100755 --- a/tools/run_benchmarks.py +++ b/tools/run_benchmarks.py
@@ -113,6 +113,8 @@ "x64", "arm64"] +GENERIC_RESULTS_RE = re.compile( + r"^Trace\(([^\)]+)\), Result\(([^\)]+)\), StdDev\(([^\)]+)\)$") class Results(object): """Place holder for result traces.""" @@ -249,7 +251,7 @@ """ @property def main(self): - return self._suite["main"] + return self._suite.get("main", "") def ChangeCWD(self, suite_path): """Changes the cwd to to path defined in the current graph. @@ -289,6 +291,33 @@ return self.GetResults() +class RunnableGeneric(Runnable): + """Represents a runnable benchmark suite definition with generic traces.""" + def __init__(self, suite, parent, arch): + super(RunnableGeneric, self).__init__(suite, parent, arch) + + def Run(self, runner): + """Iterates over several runs and handles the output.""" + traces = {} + for stdout in runner(): + for line in stdout.strip().splitlines(): + match = GENERIC_RESULTS_RE.match(line) + if match: + trace = match.group(1) + result = match.group(2) + stddev = match.group(3) + trace_result = traces.setdefault(trace, Results([{ + "graphs": self.graphs + [trace], + "units": self.units, + "results": [], + "stddev": "", + }], [])) + trace_result.traces[0]["results"].append(result) + trace_result.traces[0]["stddev"] = stddev + + return reduce(lambda r, t: r + t, traces.itervalues(), Results()) + + def MakeGraph(suite, arch, parent): """Factory method for making graph objects.""" if isinstance(parent, Runnable): @@ -302,6 +331,10 @@ else: # This graph has no subbenchmarks, it's a leaf. return RunnableTrace(suite, parent, arch) + elif suite.get("generic"): + # This is a generic suite definition. It is either a runnable executable + # or has a main js file. + return RunnableGeneric(suite, parent, arch) elif suite.get("benchmarks"): # This is neither a leaf nor a runnable. return Graph(suite, parent, arch)
diff --git a/tools/unittests/run_benchmarks_test.py b/tools/unittests/run_benchmarks_test.py index 37a816e..0545220 100644 --- a/tools/unittests/run_benchmarks_test.py +++ b/tools/unittests/run_benchmarks_test.py
@@ -68,6 +68,15 @@ ] } +V8_GENERIC_JSON = { + "path": ["."], + "binary": "cc", + "flags": ["--flag"], + "generic": True, + "run_count": 1, + "units": "ms", +} + Output = namedtuple("Output", "stdout, stderr") class BenchmarksTest(unittest.TestCase): @@ -295,3 +304,17 @@ self._VerifyErrors( ["Regexp \"^Richards: (.+)$\" didn't match for benchmark Richards."]) self._VerifyMock(path.join("out", "x64.release", "d7"), "--flag", "run.js") + + def testOneRunGeneric(self): + test_input = dict(V8_GENERIC_JSON) + self._WriteTestInput(test_input) + self._MockCommand(["."], [ + "Trace(Test1), Result(1.234), StdDev(0.23)\n" + "Trace(Test2), Result(10657567), StdDev(106)\n"]) + self.assertEquals(0, self._CallMain()) + self._VerifyResults("test", "ms", [ + {"name": "Test1", "results": ["1.234"], "stddev": "0.23"}, + {"name": "Test2", "results": ["10657567"], "stddev": "106"}, + ]) + self._VerifyErrors([]) + self._VerifyMock(path.join("out", "x64.release", "cc"), "--flag", "")