| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 49d379aa0b018a977da1d520d4d91c9b3823acfb..c146b2f5ffafef3db535c20a4809d41ed97ef88f 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -12104,6 +12104,240 @@ void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) {
|
| }
|
|
|
|
|
| +template <typename CollectionType>
|
| +HValue* HOptimizedGraphBuilder::BuildOrderedHashTableFindEntry(HValue* table,
|
| + HValue* key,
|
| + HValue* hash) {
|
| + HValue* num_buckets = Add<HLoadNamedField>(
|
| + table, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>());
|
| +
|
| + // Some things that won't change inside the loop
|
| + HValue* not_found = Add<HConstant>(CollectionType::kNotFound);
|
| + HValue* start_index = Add<HConstant>(CollectionType::kHashTableStartIndex);
|
| + HValue* entry_size = Add<HConstant>(CollectionType::kEntrySize);
|
| + HValue* chain_offset = Add<HConstant>(CollectionType::kChainOffset);
|
| + HValue* key_start = AddUncasted<HAdd>(start_index, num_buckets);
|
| + key_start->ClearFlag(HValue::kCanOverflow);
|
| +
|
| + // BuildHashToBucket
|
| + HValue* mask = AddUncasted<HSub>(num_buckets, graph()->GetConstant1());
|
| + mask->ChangeRepresentation(Representation::Integer32());
|
| + mask->ClearFlag(HValue::kCanOverflow);
|
| +
|
| + HValue* bucket = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
|
| +
|
| + // BuildHashToEntry
|
| + HValue* entry_index = AddUncasted<HAdd>(start_index, bucket);
|
| + entry_index->ClearFlag(HValue::kCanOverflow);
|
| + HValue* entry =
|
| + Add<HLoadKeyed>(table, entry_index, static_cast<HValue*>(NULL),
|
| + FAST_ELEMENTS, ALLOW_RETURN_HOLE);
|
| + entry->set_type(HType::Smi());
|
| +
|
| + Push(entry);
|
| +
|
| + LoopBuilder loop(this);
|
| + loop.BeginBody(1);
|
| +
|
| + entry = Pop();
|
| +
|
| + {
|
| + IfBuilder if_not_found(this);
|
| + if_not_found.If<HCompareNumericAndBranch>(entry, not_found, Token::EQ);
|
| + if_not_found.Then();
|
| + Push(entry);
|
| + loop.Break();
|
| + }
|
| +
|
| + // BuildEntryToIndex
|
| + HValue* key_index = AddUncasted<HMul>(entry, entry_size);
|
| + key_index->ClearFlag(HValue::kCanOverflow);
|
| + key_index = AddUncasted<HAdd>(key_index, key_start);
|
| + key_index->ClearFlag(HValue::kCanOverflow);
|
| + // BuildKeyAt
|
| + HValue* candidate_key =
|
| + Add<HLoadKeyed>(table, key_index, static_cast<HValue*>(NULL),
|
| + FAST_ELEMENTS, ALLOW_RETURN_HOLE);
|
| +
|
| + {
|
| + IfBuilder if_keys_equal(this);
|
| + if_keys_equal.If<HIsStringAndBranch>(candidate_key);
|
| + if_keys_equal.AndIf<HStringCompareAndBranch>(candidate_key, key,
|
| + Token::EQ_STRICT);
|
| + if_keys_equal.Then();
|
| + Push(key_index);
|
| + loop.Break();
|
| + }
|
| +
|
| + // BuildChainAt
|
| + HValue* chain_index = AddUncasted<HMul>(entry, entry_size);
|
| + chain_index->ClearFlag(HValue::kCanOverflow);
|
| + chain_index = AddUncasted<HAdd>(chain_index, key_start);
|
| + chain_index->ClearFlag(HValue::kCanOverflow);
|
| + chain_index = AddUncasted<HAdd>(chain_index, chain_offset);
|
| + chain_index->ClearFlag(HValue::kCanOverflow);
|
| + entry = Add<HLoadKeyed>(table, chain_index, static_cast<HValue*>(NULL),
|
| + FAST_ELEMENTS, ALLOW_RETURN_HOLE);
|
| + entry->set_type(HType::Smi());
|
| + Push(entry);
|
| +
|
| + loop.EndBody();
|
| +
|
| + return Pop();
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::GenerateMapGet(CallRuntime* call) {
|
| + DCHECK(call->arguments()->length() == 2);
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
| + HValue* key = Pop();
|
| + HValue* receiver = Pop();
|
| +
|
| + NoObservableSideEffectsScope no_effects(this);
|
| +
|
| + HIfContinuation continuation;
|
| + HValue* hash =
|
| + BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
|
| + {
|
| + IfBuilder string_checker(this, &continuation);
|
| + string_checker.Then();
|
| + {
|
| + HValue* table =
|
| + Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForJSCollectionTable());
|
| + HValue* key_index =
|
| + BuildOrderedHashTableFindEntry<OrderedHashMap>(table, key, hash);
|
| + IfBuilder if_found(this);
|
| + if_found.If<HCompareNumericAndBranch>(
|
| + key_index, Add<HConstant>(OrderedHashMap::kNotFound), Token::NE);
|
| + if_found.Then();
|
| + {
|
| + HValue* value_index = AddUncasted<HAdd>(
|
| + key_index, Add<HConstant>(OrderedHashMap::kValueOffset));
|
| + value_index->ClearFlag(HValue::kCanOverflow);
|
| + Push(Add<HLoadKeyed>(table, value_index, static_cast<HValue*>(NULL),
|
| + FAST_ELEMENTS));
|
| + }
|
| + if_found.Else();
|
| + Push(graph()->GetConstantUndefined());
|
| + if_found.End();
|
| + }
|
| + string_checker.Else();
|
| + {
|
| + Add<HPushArguments>(receiver, key);
|
| + Push(Add<HCallRuntime>(call->name(),
|
| + Runtime::FunctionForId(Runtime::kMapGet), 2));
|
| + }
|
| + }
|
| +
|
| + return ast_context()->ReturnValue(Pop());
|
| +}
|
| +
|
| +
|
| +HValue* HOptimizedGraphBuilder::BuildStringHashLoadIfIsStringAndHashComputed(
|
| + HValue* object, HIfContinuation* continuation) {
|
| + IfBuilder string_checker(this);
|
| + string_checker.If<HIsStringAndBranch>(object);
|
| + string_checker.And();
|
| + HValue* hash = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForStringHashField());
|
| + HValue* hash_not_computed_mask = Add<HConstant>(String::kHashNotComputedMask);
|
| + HValue* hash_computed_test =
|
| + AddUncasted<HBitwise>(Token::BIT_AND, hash, hash_not_computed_mask);
|
| + string_checker.If<HCompareNumericAndBranch>(
|
| + hash_computed_test, graph()->GetConstant0(), Token::EQ);
|
| + string_checker.Then();
|
| + HValue* shifted_hash =
|
| + AddUncasted<HShr>(hash, Add<HConstant>(String::kHashShift));
|
| + string_checker.CaptureContinuation(continuation);
|
| + return shifted_hash;
|
| +}
|
| +
|
| +
|
| +template <typename CollectionType>
|
| +void HOptimizedGraphBuilder::BuildJSCollectionHas(
|
| + CallRuntime* call, const Runtime::Function* c_function) {
|
| + DCHECK(call->arguments()->length() == 2);
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
|
| + HValue* key = Pop();
|
| + HValue* receiver = Pop();
|
| +
|
| + NoObservableSideEffectsScope no_effects(this);
|
| +
|
| + HIfContinuation continuation;
|
| + HValue* hash =
|
| + BuildStringHashLoadIfIsStringAndHashComputed(key, &continuation);
|
| + {
|
| + IfBuilder string_checker(this, &continuation);
|
| + string_checker.Then();
|
| + {
|
| + HValue* table =
|
| + Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForJSCollectionTable());
|
| + HValue* key_index =
|
| + BuildOrderedHashTableFindEntry<CollectionType>(table, key, hash);
|
| + {
|
| + IfBuilder if_found(this);
|
| + if_found.If<HCompareNumericAndBranch>(
|
| + key_index, Add<HConstant>(CollectionType::kNotFound), Token::NE);
|
| + if_found.Then();
|
| + Push(graph()->GetConstantTrue());
|
| + if_found.Else();
|
| + Push(graph()->GetConstantFalse());
|
| + }
|
| + }
|
| + string_checker.Else();
|
| + {
|
| + Add<HPushArguments>(receiver, key);
|
| + Push(Add<HCallRuntime>(call->name(), c_function, 2));
|
| + }
|
| + }
|
| +
|
| + return ast_context()->ReturnValue(Pop());
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::GenerateMapHas(CallRuntime* call) {
|
| + BuildJSCollectionHas<OrderedHashMap>(
|
| + call, Runtime::FunctionForId(Runtime::kMapHas));
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::GenerateSetHas(CallRuntime* call) {
|
| + BuildJSCollectionHas<OrderedHashSet>(
|
| + call, Runtime::FunctionForId(Runtime::kSetHas));
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::GenerateSetGetSize(CallRuntime* call) {
|
| + DCHECK(call->arguments()->length() == 1);
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
| + HValue* receiver = Pop();
|
| + HValue* table = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForJSCollectionTable());
|
| + HInstruction* result = New<HLoadNamedField>(
|
| + table, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashSet>());
|
| + return ast_context()->ReturnInstruction(result, call->id());
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::GenerateMapGetSize(CallRuntime* call) {
|
| + DCHECK(call->arguments()->length() == 1);
|
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
| + HValue* receiver = Pop();
|
| + HValue* table = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForJSCollectionTable());
|
| + HInstruction* result = New<HLoadNamedField>(
|
| + table, static_cast<HValue*>(NULL),
|
| + HObjectAccess::ForOrderedHashTableNumberOfElements<OrderedHashMap>());
|
| + return ast_context()->ReturnInstruction(result, call->id());
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
|
| DCHECK(call->arguments()->length() == 1);
|
| CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
|
|