}
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r1, r0 };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}
+
+
void LoadFieldStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
sub(t1, t1, Operand(1));
// Generate an unrolled loop that performs a few probes before giving up.
- static const int kProbes = 4;
- for (int i = 0; i < kProbes; i++) {
+ for (int i = 0; i < kNumberDictionaryProbes; i++) {
// Use t2 for index calculations and keep the hash intact in t0.
mov(t2, t0);
// Compute the masked index: (hash + i + i * i) & mask.
add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
ldr(ip, FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
cmp(key, Operand(ip));
- if (i != kProbes - 1) {
+ if (i != kNumberDictionaryProbes - 1) {
b(eq, &done);
} else {
b(ne, miss);
}
+template <>
+class CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>
+ : public CodeStubGraphBuilderBase {
+ public:
+ explicit CodeStubGraphBuilder(Isolate* isolate,
+ KeyedLoadDictionaryElementStub* stub)
+ : CodeStubGraphBuilderBase(isolate, stub) {}
+
+ protected:
+ HValue* BuildCodeStubHelper(HValue* dictionary,
+ HValue* key,
+ HValue* hash,
+ HValue* mask,
+ int current_probe);
+
+ virtual HValue* BuildCodeStub();
+
+ KeyedLoadDictionaryElementStub* casted_stub() {
+ return static_cast<KeyedLoadDictionaryElementStub*>(stub());
+ }
+};
+
+
+HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::
+ BuildCodeStubHelper(
+ HValue* elements,
+ HValue* key,
+ HValue* hash,
+ HValue* mask,
+ int current_probe) {
+ if (current_probe == kNumberDictionaryProbes) {
+ return NULL;
+ }
+
+ int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
+ HValue* raw_index = (current_probe == 0)
+ ? hash
+ : Add<HAdd>(hash, Add<HConstant>(offset));
+ raw_index = Add<HBitwise>(Token::BIT_AND, raw_index, mask);
+ int32_t entry_size = SeededNumberDictionary::kEntrySize;
+ raw_index = Add<HMul>(raw_index, Add<HConstant>(entry_size));
+ raw_index->ClearFlag(HValue::kCanOverflow);
+
+ int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
+ HValue* key_index = Add<HAdd>(raw_index, Add<HConstant>(base_offset));
+ key_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ IfBuilder key_compare(this);
+ key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
+ key_compare.Then();
+ {
+ // Key at the current probe doesn't match, try at the next probe.
+ HValue* result = BuildCodeStubHelper(elements, key, hash, mask,
+ current_probe + 1);
+ if (result == NULL) {
+ key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
+ result = graph()->GetConstantUndefined();
+ } else {
+ Push(result);
+ }
+ }
+ key_compare.Else();
+ {
+ // Key at current probe matches. Details must be zero, otherwise the
+ // dictionary element requires special handling.
+ HValue* details_index = Add<HAdd>(raw_index,
+ Add<HConstant>(base_offset + 2));
+ details_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* details = Add<HLoadKeyed>(elements, details_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+ IfBuilder details_compare(this);
+ details_compare.If<HCompareNumericAndBranch>(details,
+ graph()->GetConstant0(),
+ Token::NE);
+ details_compare.ThenDeopt("keyed load dictionary element not fast case");
+
+ details_compare.Else();
+ {
+ // Key matches and details are zero --> fast case. Load and return the
+ // value.
+ HValue* result_index = Add<HAdd>(raw_index,
+ Add<HConstant>(base_offset + 1));
+ result_index->ClearFlag(HValue::kCanOverflow);
+
+ Push(Add<HLoadKeyed>(elements, result_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS));
+ }
+ details_compare.End();
+ }
+ key_compare.End();
+
+ return Pop();
+}
+
+
+HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::BuildCodeStub() {
+ KeyedLoadDictionaryElementStub* stub = casted_stub();
+
+ HValue* dictionary = GetParameter(0);
+ HValue* key = GetParameter(1);
+ USE(stub);
+ USE(dictionary);
+
+ HValue* elements = AddLoadElements(dictionary);
+
+ Add<HCheckSmi>(key);
+
+ HValue* hash = BuildElementIndexHash(key);
+
+ HValue* capacity = Add<HLoadKeyed>(
+ elements,
+ Add<HConstant>(NameDictionary::kCapacityIndex),
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ HValue* mask = Add<HSub>(capacity, graph()->GetConstant1());
+ mask->ChangeRepresentation(Representation::Integer32());
+ mask->ClearFlag(HValue::kCanOverflow);
+
+ return BuildCodeStubHelper(elements, key, hash, mask, 0);
+}
+
+
+Handle<Code> KeyedLoadDictionaryElementStub::GenerateCode(Isolate* isolate) {
+ return DoGenerateCode(isolate, this);
+}
+
+
} } // namespace v8::internal
}
-void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) {
+void KeyedLoadDictionaryElementPlatformStub::Generate(
+ MacroAssembler* masm) {
KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
}
};
-class KeyedLoadDictionaryElementStub : public PlatformCodeStub {
+class KeyedLoadDictionaryElementStub : public HydrogenCodeStub {
public:
KeyedLoadDictionaryElementStub() {}
+ virtual Handle<Code> GenerateCode(Isolate* isolate) V8_OVERRIDE;
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) V8_OVERRIDE;
+
+ private:
+ Major MajorKey() { return KeyedLoadElement; }
+ int NotMissMinorKey() { return DICTIONARY_ELEMENTS; }
+
+ DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub);
+};
+
+
+class KeyedLoadDictionaryElementPlatformStub : public PlatformCodeStub {
+ public:
+ KeyedLoadDictionaryElementPlatformStub() {}
+
void Generate(MacroAssembler* masm);
private:
Major MajorKey() { return KeyedLoadElement; }
int MinorKey() { return DICTIONARY_ELEMENTS; }
- DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub);
+ DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementPlatformStub);
};
DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator);
};
+static const int kNumberDictionaryProbes = 4;
+
} } // namespace v8::internal
// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
+DEFINE_bool(compiled_keyed_dictionary_loads, false,
+ "use optimizing compiler to generate keyed dictionary load stubs")
DEFINE_bool(clever_optimizations, true,
"Optimize object size, Array shift, DOM strings and string +")
DEFINE_bool(pretenuring, true, "allocate objects in old space")
}
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper(
+ HValue* elements,
+ HValue* key,
+ HValue* hash,
+ HValue* mask,
+ int current_probe) {
+ if (current_probe == kNumberDictionaryProbes) {
+ return NULL;
+ }
+
+ int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
+ HValue* raw_index = (current_probe == 0)
+ ? hash
+ : Add<HAdd>(hash, Add<HConstant>(offset));
+ raw_index = Add<HBitwise>(Token::BIT_AND, raw_index, mask);
+ int32_t entry_size = SeededNumberDictionary::kEntrySize;
+ raw_index = Add<HMul>(raw_index, Add<HConstant>(entry_size));
+ raw_index->ClearFlag(HValue::kCanOverflow);
+
+ int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
+ HValue* key_index = Add<HAdd>(raw_index, Add<HConstant>(base_offset));
+ key_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ IfBuilder key_compare(this);
+ key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
+ key_compare.Then();
+ {
+ // Key at the current probe doesn't match, try at the next probe.
+ HValue* result = BuildUncheckedDictionaryElementLoadHelper(
+ elements, key, hash, mask, current_probe + 1);
+ if (result == NULL) {
+ key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
+ result = graph()->GetConstantUndefined();
+ } else {
+ Push(result);
+ }
+ }
+ key_compare.Else();
+ {
+ // Key at current probe matches. Details must be zero, otherwise the
+ // dictionary element requires special handling.
+ HValue* details_index = Add<HAdd>(raw_index,
+ Add<HConstant>(base_offset + 2));
+ details_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* details = Add<HLoadKeyed>(elements, details_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+ IfBuilder details_compare(this);
+ details_compare.If<HCompareNumericAndBranch>(details,
+ graph()->GetConstant0(),
+ Token::NE);
+ details_compare.ThenDeopt("keyed load dictionary element not fast case");
+
+ details_compare.Else();
+ {
+ // Key matches and details are zero --> fast case. Load and return the
+ // value.
+ HValue* result_index = Add<HAdd>(raw_index,
+ Add<HConstant>(base_offset + 1));
+ result_index->ClearFlag(HValue::kCanOverflow);
+
+ Push(Add<HLoadKeyed>(elements, result_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS));
+ }
+ details_compare.End();
+ }
+ key_compare.End();
+
+ return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
+ int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
+ HValue* seed = Add<HConstant>(seed_value);
+ HValue* hash = Add<HBitwise>(Token::BIT_XOR, index, seed);
+
+ // hash = ~hash + (hash << 15);
+ HValue* shifted_hash = Add<HShl>(hash, Add<HConstant>(15));
+ HValue* not_hash = Add<HBitwise>(Token::BIT_XOR, hash,
+ graph()->GetConstantMinus1());
+ hash = Add<HAdd>(shifted_hash, not_hash);
+
+ // hash = hash ^ (hash >> 12);
+ shifted_hash = Add<HShr>(hash, Add<HConstant>(12));
+ hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+ // hash = hash + (hash << 2);
+ shifted_hash = Add<HShl>(hash, Add<HConstant>(2));
+ hash = Add<HAdd>(hash, shifted_hash);
+
+ // hash = hash ^ (hash >> 4);
+ shifted_hash = Add<HShr>(hash, Add<HConstant>(4));
+ hash = Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+ // hash = hash * 2057;
+ hash = Add<HMul>(hash, Add<HConstant>(2057));
+ hash->ClearFlag(HValue::kCanOverflow);
+
+ // hash = hash ^ (hash >> 16);
+ shifted_hash = Add<HShr>(hash, Add<HConstant>(16));
+ return Add<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
+ HValue* key) {
+ HValue* elements = AddLoadElements(receiver);
+
+ HValue* hash = BuildElementIndexHash(key);
+
+ HValue* capacity = Add<HLoadKeyed>(
+ elements,
+ Add<HConstant>(NameDictionary::kCapacityIndex),
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ HValue* mask = Add<HSub>(capacity, graph()->GetConstant1());
+ mask->ChangeRepresentation(Representation::Integer32());
+ mask->ClearFlag(HValue::kCanOverflow);
+
+ return BuildUncheckedDictionaryElementLoadHelper(elements, key,
+ hash, mask, 0);
+}
+
+
HValue* HGraphBuilder::BuildNumberToString(HValue* object,
Handle<Type> type) {
NoObservableSideEffectsScope scope(this);
HValue* BuildNumberToString(HValue* object, Handle<Type> type);
+ HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver,
+ HValue* key);
+
// Computes the size for a sequential string of the given length and encoding.
HValue* BuildSeqStringSizeFor(HValue* length,
String::Encoding encoding);
ElementsKind kind,
int length);
+ HValue* BuildElementIndexHash(HValue* index);
+
void BuildCompareNil(
HValue* value,
Handle<Type> type,
private:
HGraphBuilder();
+ HValue* BuildUncheckedDictionaryElementLoadHelper(
+ HValue* elements,
+ HValue* key,
+ HValue* hash,
+ HValue* mask,
+ int current_probe);
+
void PadEnvironmentForContinuation(HBasicBlock* from,
HBasicBlock* continuation);
}
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { edx, ecx };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}
+
+
void LoadFieldStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
dec(r1);
// Generate an unrolled loop that performs a few probes before giving up.
- const int kProbes = 4;
- for (int i = 0; i < kProbes; i++) {
+ for (int i = 0; i < kNumberDictionaryProbes; i++) {
// Use r2 for index calculations and keep the hash intact in r0.
mov(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask.
r2,
times_pointer_size,
SeededNumberDictionary::kElementsStartOffset));
- if (i != (kProbes - 1)) {
+ if (i != (kNumberDictionaryProbes - 1)) {
j(equal, &done);
} else {
j(not_equal, miss);
elements_kind).GetCode(isolate());
__ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
} else {
- Handle<Code> stub =
- KeyedLoadDictionaryElementStub().GetCode(isolate());
+ Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
+ ? KeyedLoadDictionaryElementStub().GetCode(isolate())
+ : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate());
__ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
}
}
+void KeyedLoadDictionaryElementStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rdx, rcx };
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure);
+}
+
+
void LoadFieldStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
decl(r1);
// Generate an unrolled loop that performs a few probes before giving up.
- const int kProbes = 4;
- for (int i = 0; i < kProbes; i++) {
+ for (int i = 0; i < kNumberDictionaryProbes; i++) {
// Use r2 for index calculations and keep the hash intact in r0.
movq(r2, r0);
// Compute the masked index: (hash + i + i * i) & mask.
r2,
times_pointer_size,
SeededNumberDictionary::kElementsStartOffset));
- if (i != (kProbes - 1)) {
+ if (i != (kNumberDictionaryProbes - 1)) {
j(equal, &done);
} else {
j(not_equal, miss);