Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index b5cebbe327e10f9612bfd8cdee581ed7fc80b0d2..30824dad09cdc798e83a3bdf707be52da7fbed5a 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -804,6 +804,28 @@ void HGraphBuilder::IfBuilder::CaptureContinuation( |
| } |
| +void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { |
| + ASSERT(!finished_); |
| + ASSERT(!captured_); |
| + HBasicBlock* true_block = last_true_block_ == NULL |
| + ? first_true_block_ |
| + : last_true_block_; |
| + HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) |
| + ? builder_->current_block() |
| + : first_false_block_; |
| + if (true_block != NULL && !true_block->IsFinished()) { |
| + ASSERT(continuation->IsTrueReachable()); |
| + true_block->GotoNoSimulate(continuation->true_branch()); |
| + } |
| + if (false_block != NULL && !false_block->IsFinished()) { |
| + ASSERT(continuation->IsFalseReachable()); |
| + false_block->GotoNoSimulate(continuation->false_branch()); |
| + } |
| + captured_ = true; |
| + End(); |
| +} |
| + |
| + |
| void HGraphBuilder::IfBuilder::Then() { |
| ASSERT(!captured_); |
| ASSERT(!finished_); |
| @@ -1249,6 +1271,142 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object, |
| } |
| +HValue* HGraphBuilder::BuildLookupNumberStringCache( |
| + HValue* object, |
| + HIfContinuation* continuation) { |
| + // Create a joinable continuation. |
| + HIfContinuation found(graph()->CreateBasicBlock(), |
| + graph()->CreateBasicBlock()); |
| + |
| + // Load the number string cache. |
| + HValue* number_string_cache = |
| + Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); |
| + |
| + // Make the hash maks from the length of the number string cache. It |
| + // contains two elements (number and string) for each cache entry. |
| + HValue* mask = AddLoadFixedArrayLength(number_string_cache); |
| + mask->set_type(HType::Smi()); |
| + mask = Add<HSar>(mask, graph()->GetConstant1()); |
| + mask = Add<HSub>(mask, graph()->GetConstant1()); |
| + |
| + // Check whether object is a smi. |
| + IfBuilder if_objectissmi(this); |
| + if_objectissmi.If<HIsSmiAndBranch>(object); |
| + if_objectissmi.Then(); |
| + { |
| + // Compute hash for smi similar to smi_get_hash(). |
| + HValue* hash = Add<HBitwise>(Token::BIT_AND, object, mask); |
| + |
| + // Load the key. |
| + HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); |
| + HValue* key = AddFastElementAccess(number_string_cache, key_index, |
| + NULL, NULL, FAST_ELEMENTS, false, |
| + ALLOW_RETURN_HOLE, STANDARD_STORE); |
| + |
| + // Check if object == key. |
| + IfBuilder if_objectiskey(this); |
| + if_objectiskey.If<HCompareObjectEqAndBranch>(key, object); |
| + if_objectiskey.Then(); |
| + { |
| + // Make the key_index available. |
| + Push(key_index); |
| + } |
| + if_objectiskey.JoinContinuation(&found); |
| + } |
| + if_objectissmi.Else(); |
|
mvstanton
2013/09/23 09:32:34
All this is really nice that you can use the IfBui
|
| + { |
| + // Check if object is a heap number. |
| + IfBuilder if_objectisnumber(this); |
| + if_objectisnumber.If<HCompareMap>( |
| + object, isolate()->factory()->heap_number_map()); |
| + if_objectisnumber.Then(); |
| + { |
| + // Compute hash for heap number similar to double_get_hash(). |
| + HValue* low = Add<HLoadNamedField>( |
| + object, HObjectAccess::ForHeapNumberValueLowestBits()); |
| + HValue* high = Add<HLoadNamedField>( |
| + object, HObjectAccess::ForHeapNumberValueHighestBits()); |
| + HValue* hash = Add<HBitwise>(Token::BIT_XOR, low, high); |
| + hash = Add<HBitwise>(Token::BIT_AND, hash, mask); |
| + |
| + // Load the key. |
| + HValue* key_index = Add<HShl>(hash, graph()->GetConstant1()); |
| + HValue* key = AddFastElementAccess(number_string_cache, key_index, |
| + NULL, NULL, FAST_ELEMENTS, false, |
| + ALLOW_RETURN_HOLE, STANDARD_STORE); |
| + |
| + // Check if key is a heap number. |
| + IfBuilder if_keyisnumber(this); |
| + if_keyisnumber.IfNot<HIsSmiAndBranch>(key); |
| + if_keyisnumber.AndIf<HCompareMap>( |
| + key, isolate()->factory()->heap_number_map()); |
| + if_keyisnumber.Then(); |
| + { |
| + // Check if values of key and object match. |
| + IfBuilder if_keyeqobject(this); |
| + if_keyeqobject.If<HCompareNumericAndBranch>( |
| + Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()), |
| + Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()), |
| + Token::EQ); |
| + if_keyeqobject.Then(); |
| + { |
| + // Make the key_index available. |
| + Push(key_index); |
| + } |
| + if_keyeqobject.JoinContinuation(&found); |
| + } |
| + if_keyisnumber.JoinContinuation(&found); |
| + } |
| + if_objectisnumber.JoinContinuation(&found); |
| + } |
| + if_objectissmi.End(); |
| + |
| + // Check for cache hit. |
| + IfBuilder if_found(this, &found); |
| + if_found.Then(); |
| + |
| + // Load the value in case of cache hit. |
| + HValue* key_index = Pop(); |
| + HValue* value_index = Add<HAdd>(key_index, graph()->GetConstant1()); |
| + HValue* value = AddFastElementAccess(number_string_cache, value_index, |
| + NULL, NULL, FAST_ELEMENTS, false, |
| + ALLOW_RETURN_HOLE, STANDARD_STORE); |
| + AddIncrementCounter(isolate()->counters()->number_to_string_native()); |
| + |
| + if_found.CaptureContinuation(continuation); |
| + |
| + // The value is only available in true branch of continuation. |
| + return value; |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::BuildNumberToString(HValue* number) { |
| + NoObservableSideEffectsScope scope(this); |
| + |
| + // Lookup the number in the number string cache. |
| + HIfContinuation continuation; |
| + HValue* value = BuildLookupNumberStringCache(number, &continuation); |
| + IfBuilder if_found(this, &continuation); |
| + if_found.Then(); |
| + |
| + // Cache hit. |
| + Push(value); |
| + |
| + if_found.Else(); |
| + |
| + // Cache miss, fallback to runtime. |
| + Add<HPushArgument>(number); |
| + Push(Add<HCallRuntime>( |
| + isolate()->factory()->empty_string(), |
| + Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| + 1)); |
| + |
| + if_found.End(); |
| + |
| + return Pop(); |
| +} |
| + |
| + |
| HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| HValue* checked_object, |
| HValue* key, |
| @@ -8868,12 +9026,8 @@ void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| // Fast support for number to string. |
| void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| ASSERT_EQ(1, call->arguments()->length()); |
| - CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| - HValue* context = environment()->context(); |
| - HCallStub* result = |
| - new(zone()) HCallStub(context, CodeStub::NumberToString, 1); |
| - Drop(1); |
| - return ast_context()->ReturnInstruction(result, call->id()); |
| + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| + return ast_context()->ReturnValue(BuildNumberToString(Pop())); |
|
mvstanton
2013/09/23 09:32:34
Paranoia: This code reminds me of the problem that
Benedikt Meurer
2013/09/23 10:53:31
Done.
|
| } |