diff options
Diffstat (limited to 'chromium/v8/src/code-stubs-hydrogen.cc')
-rw-r--r-- | chromium/v8/src/code-stubs-hydrogen.cc | 462 |
1 files changed, 349 insertions, 113 deletions
diff --git a/chromium/v8/src/code-stubs-hydrogen.cc b/chromium/v8/src/code-stubs-hydrogen.cc index 9130a731594..96cfc378476 100644 --- a/chromium/v8/src/code-stubs-hydrogen.cc +++ b/chromium/v8/src/code-stubs-hydrogen.cc @@ -146,40 +146,33 @@ bool CodeStubGraphBuilderBase::BuildGraph() { int param_count = descriptor_->register_param_count_; HEnvironment* start_environment = graph()->start_environment(); HBasicBlock* next_block = CreateBasicBlock(start_environment); - current_block()->Goto(next_block); + Goto(next_block); next_block->SetJoinId(BailoutId::StubEntry()); set_current_block(next_block); - HConstant* undefined_constant = - Add<HConstant>(isolate()->factory()->undefined_value()); - graph()->set_undefined_constant(undefined_constant); - + bool runtime_stack_params = descriptor_->stack_parameter_count_.is_valid(); + HInstruction* stack_parameter_count = NULL; for (int i = 0; i < param_count; ++i) { - HParameter* param = - Add<HParameter>(i, HParameter::REGISTER_PARAMETER); + Representation r = descriptor_->IsParameterCountRegister(i) + ? Representation::Integer32() + : Representation::Tagged(); + HParameter* param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r); start_environment->Bind(i, param); parameters_[i] = param; + if (descriptor_->IsParameterCountRegister(i)) { + param->set_type(HType::Smi()); + stack_parameter_count = param; + arguments_length_ = stack_parameter_count; + } } - HInstruction* stack_parameter_count; - if (descriptor_->stack_parameter_count_ != NULL) { - ASSERT(descriptor_->environment_length() == (param_count + 1)); - stack_parameter_count = New<HParameter>(param_count, - HParameter::REGISTER_PARAMETER, - Representation::Integer32()); - stack_parameter_count->set_type(HType::Smi()); - // It's essential to bind this value to the environment in case of deopt. - AddInstruction(stack_parameter_count); - start_environment->Bind(param_count, stack_parameter_count); - arguments_length_ = stack_parameter_count; - } else { - ASSERT(descriptor_->environment_length() == param_count); + ASSERT(!runtime_stack_params || arguments_length_ != NULL); + if (!runtime_stack_params) { stack_parameter_count = graph()->GetConstantMinus1(); arguments_length_ = graph()->GetConstant0(); } - context_ = New<HContext>(); - AddInstruction(context_); + context_ = Add<HContext>(); start_environment->BindContext(context_); Add<HSimulate>(BailoutId::StubEntry()); @@ -194,10 +187,11 @@ bool CodeStubGraphBuilderBase::BuildGraph() { if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) { if (!stack_parameter_count->IsConstant() && descriptor_->hint_stack_parameter_count_ < 0) { - HInstruction* amount = graph()->GetConstant1(); - stack_pop_count = Add<HAdd>(stack_parameter_count, amount); - stack_pop_count->ChangeRepresentation(Representation::Integer32()); + HInstruction* constant_one = graph()->GetConstant1(); + stack_pop_count = AddUncasted<HAdd>(stack_parameter_count, constant_one); stack_pop_count->ClearFlag(HValue::kCanOverflow); + // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a + // smi. } else { int count = descriptor_->hint_stack_parameter_count_; stack_pop_count = Add<HConstant>(count); @@ -207,8 +201,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() { if (current_block() != NULL) { HReturn* hreturn_instruction = New<HReturn>(return_value, stack_pop_count); - current_block()->Finish(hreturn_instruction); - set_current_block(NULL); + FinishCurrentBlock(hreturn_instruction); } return true; } @@ -217,7 +210,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() { template <class Stub> class CodeStubGraphBuilder: public CodeStubGraphBuilderBase { public: - explicit CodeStubGraphBuilder(Isolate* isolate, Stub* stub) + CodeStubGraphBuilder(Isolate* isolate, Stub* stub) : CodeStubGraphBuilderBase(isolate, stub) {} protected: @@ -258,9 +251,6 @@ Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) { // Update the static counter each time a new code stub is generated. isolate->counters()->code_stubs()->Increment(); - // Nested stubs are not allowed for leaves. - AllowStubCallsScope allow_scope(&masm, false); - // Generate the code for the stub. masm.set_generating_stub(true); NoCurrentFrameScope scope(&masm); @@ -298,12 +288,21 @@ static Handle<Code> DoGenerateCode(Isolate* isolate, Stub* stub) { // the runtime that is significantly faster than using the standard // stub-failure deopt mechanism. if (stub->IsUninitialized() && descriptor->has_miss_handler()) { - ASSERT(descriptor->stack_parameter_count_ == NULL); + ASSERT(!descriptor->stack_parameter_count_.is_valid()); return stub->GenerateLightweightMissCode(isolate); } + ElapsedTimer timer; + if (FLAG_profile_hydrogen_code_stub_compilation) { + timer.Start(); + } CodeStubGraphBuilder<Stub> builder(isolate, stub); LChunk* chunk = OptimizeGraph(builder.CreateGraph()); - return chunk->Codegen(); + Handle<Code> code = chunk->Codegen(); + if (FLAG_profile_hydrogen_code_stub_compilation) { + double ms = timer.Elapsed().InMillisecondsF(); + PrintF("[Lazy compilation of %s took %0.3f ms]\n", *stub->GetName(), ms); + } + return code; } @@ -339,6 +338,19 @@ Handle<Code> ToNumberStub::GenerateCode(Isolate* isolate) { template <> +HValue* CodeStubGraphBuilder<NumberToStringStub>::BuildCodeStub() { + info()->MarkAsSavesCallerDoubles(); + HValue* number = GetParameter(NumberToStringStub::kNumber); + return BuildNumberToString(number, handle(Type::Number(), isolate())); +} + + +Handle<Code> NumberToStringStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + +template <> HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { Factory* factory = isolate()->factory(); HValue* undefined = graph()->GetConstantUndefined(); @@ -355,42 +367,48 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() { undefined); checker.Then(); - HObjectAccess access = HObjectAccess::ForAllocationSiteTransitionInfo(); + HObjectAccess access = HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kTransitionInfoOffset); HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access); + HValue* push_value; if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) { HValue* elements = AddLoadElements(boilerplate); IfBuilder if_fixed_cow(this); if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map()); if_fixed_cow.Then(); - environment()->Push(BuildCloneShallowArray(boilerplate, - allocation_site, - alloc_site_mode, - FAST_ELEMENTS, - 0/*copy-on-write*/)); + push_value = BuildCloneShallowArray(boilerplate, + allocation_site, + alloc_site_mode, + FAST_ELEMENTS, + 0/*copy-on-write*/); + environment()->Push(push_value); if_fixed_cow.Else(); IfBuilder if_fixed(this); if_fixed.If<HCompareMap>(elements, factory->fixed_array_map()); if_fixed.Then(); - environment()->Push(BuildCloneShallowArray(boilerplate, - allocation_site, - alloc_site_mode, - FAST_ELEMENTS, - length)); + push_value = BuildCloneShallowArray(boilerplate, + allocation_site, + alloc_site_mode, + FAST_ELEMENTS, + length); + environment()->Push(push_value); if_fixed.Else(); - environment()->Push(BuildCloneShallowArray(boilerplate, - allocation_site, - alloc_site_mode, - FAST_DOUBLE_ELEMENTS, - length)); + push_value = BuildCloneShallowArray(boilerplate, + allocation_site, + alloc_site_mode, + FAST_DOUBLE_ELEMENTS, + length); + environment()->Push(push_value); } else { ElementsKind elements_kind = casted_stub()->ComputeElementsKind(); - environment()->Push(BuildCloneShallowArray(boilerplate, - allocation_site, - alloc_site_mode, - elements_kind, - length)); + push_value = BuildCloneShallowArray(boilerplate, + allocation_site, + alloc_site_mode, + elements_kind, + length); + environment()->Push(push_value); } checker.ElseDeopt("Uninitialized boilerplate literals"); @@ -407,23 +425,33 @@ Handle<Code> FastCloneShallowArrayStub::GenerateCode(Isolate* isolate) { template <> HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { - Zone* zone = this->zone(); HValue* undefined = graph()->GetConstantUndefined(); - HInstruction* boilerplate = Add<HLoadKeyed>(GetParameter(0), - GetParameter(1), - static_cast<HValue*>(NULL), - FAST_ELEMENTS); + HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0), + GetParameter(1), + static_cast<HValue*>(NULL), + FAST_ELEMENTS); IfBuilder checker(this); - checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate, + checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site, undefined); checker.And(); + HObjectAccess access = HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kTransitionInfoOffset); + HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access); + int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize; - HValue* boilerplate_size = - AddInstruction(new(zone) HInstanceSize(boilerplate)); - HValue* size_in_words = Add<HConstant>(size >> kPointerSizeLog2); + int object_size = size; + if (FLAG_allocation_site_pretenuring) { + size += AllocationMemento::kSize; + } + + HValue* boilerplate_map = Add<HLoadNamedField>( + boilerplate, HObjectAccess::ForMap()); + HValue* boilerplate_size = Add<HLoadNamedField>( + boilerplate_map, HObjectAccess::ForMapInstanceSize()); + HValue* size_in_words = Add<HConstant>(object_size >> kPointerSizeLog2); checker.If<HCompareNumericAndBranch>(boilerplate_size, size_in_words, Token::EQ); checker.Then(); @@ -433,12 +461,18 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() { HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(), isolate()->heap()->GetPretenureMode(), JS_OBJECT_TYPE); - for (int i = 0; i < size; i += kPointerSize) { + for (int i = 0; i < object_size; i += kPointerSize) { HObjectAccess access = HObjectAccess::ForJSObjectOffset(i); Add<HStoreNamedField>(object, access, Add<HLoadNamedField>(boilerplate, access)); } + ASSERT(FLAG_allocation_site_pretenuring || (size == object_size)); + if (FLAG_allocation_site_pretenuring) { + BuildCreateAllocationMemento( + object, Add<HConstant>(object_size), allocation_site); + } + environment()->Push(object); checker.ElseDeopt("Uninitialized boilerplate in fast clone"); checker.End(); @@ -459,24 +493,55 @@ HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() { JS_OBJECT_TYPE); // Store the map - Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(), - isolate()); + Handle<Map> allocation_site_map = isolate()->factory()->allocation_site_map(); AddStoreMapConstant(object, allocation_site_map); // Store the payload (smi elements kind) HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind()); Add<HStoreNamedField>(object, - HObjectAccess::ForAllocationSiteTransitionInfo(), + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kTransitionInfoOffset), initial_elements_kind); + // Unlike literals, constructed arrays don't have nested sites + Add<HStoreNamedField>(object, + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kNestedSiteOffset), + graph()->GetConstant0()); + + // Pretenuring calculation fields. + Add<HStoreNamedField>(object, + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kMementoFoundCountOffset), + graph()->GetConstant0()); + + Add<HStoreNamedField>(object, + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kMementoCreateCountOffset), + graph()->GetConstant0()); + + Add<HStoreNamedField>(object, + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kPretenureDecisionOffset), + graph()->GetConstant0()); + + // Store an empty fixed array for the code dependency. + HConstant* empty_fixed_array = + Add<HConstant>(isolate()->factory()->empty_fixed_array()); + HStoreNamedField* store = Add<HStoreNamedField>( + object, + HObjectAccess::ForAllocationSiteOffset( + AllocationSite::kDependentCodeOffset), + empty_fixed_array); + // Link the object to the allocation site list HValue* site_list = Add<HConstant>( ExternalReference::allocation_sites_list_address(isolate())); HValue* site = Add<HLoadNamedField>(site_list, HObjectAccess::ForAllocationSiteList()); - HStoreNamedField* store = - Add<HStoreNamedField>(object, HObjectAccess::ForAllocationSiteWeakNext(), - site); + store = Add<HStoreNamedField>(object, + HObjectAccess::ForAllocationSiteOffset(AllocationSite::kWeakNextOffset), + site); store->SkipWriteBarrier(); Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(), object); @@ -519,7 +584,7 @@ HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() { HObjectAccess access = casted_stub()->is_inobject() ? HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) : HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep); - return AddInstruction(BuildLoadNamedField(GetParameter(0), access)); + return AddLoadNamedField(GetParameter(0), access); } @@ -534,7 +599,7 @@ HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() { HObjectAccess access = casted_stub()->is_inobject() ? HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) : HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep); - return AddInstruction(BuildLoadNamedField(GetParameter(0), access)); + return AddLoadNamedField(GetParameter(0), access); } @@ -543,6 +608,33 @@ Handle<Code> KeyedLoadFieldStub::GenerateCode(Isolate* isolate) { } +template<> +HValue* CodeStubGraphBuilder<KeyedArrayCallStub>::BuildCodeStub() { + int argc = casted_stub()->argc() + 1; + info()->set_parameter_count(argc); + + HValue* receiver = Add<HParameter>(1); + BuildCheckHeapObject(receiver); + + // Load the expected initial array map from the context. + JSArrayBuilder array_builder(this, casted_stub()->elements_kind()); + HValue* map = array_builder.EmitMapCode(); + + HValue* checked_receiver = Add<HCheckMapValue>(receiver, map); + + HValue* function = BuildUncheckedMonomorphicElementAccess( + checked_receiver, GetParameter(0), + NULL, true, casted_stub()->elements_kind(), + false, NEVER_RETURN_HOLE, STANDARD_STORE); + return Add<HCallFunction>(function, argc, TAIL_CALL); +} + + +Handle<Code> KeyedArrayCallStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + template <> HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() { BuildUncheckedMonomorphicElementAccess( @@ -640,46 +732,38 @@ HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor( HValue* constant_zero = graph()->GetConstant0(); HInstruction* elements = Add<HArgumentsElements>(false); - HInstruction* argument = AddInstruction( - new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero)); + HInstruction* argument = Add<HAccessArgumentsAt>( + elements, constant_one, constant_zero); - HConstant* max_alloc_length = - Add<HConstant>(JSObject::kInitialMaxFastElementArray); - const int initial_capacity = JSArray::kPreallocatedArrayElements; - HConstant* initial_capacity_node = New<HConstant>(initial_capacity); - AddInstruction(initial_capacity_node); - - HInstruction* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length); - IfBuilder if_builder(this); - if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero, - Token::EQ); - if_builder.Then(); - Push(initial_capacity_node); // capacity - Push(constant_zero); // length - if_builder.Else(); - Push(checked_arg); // capacity - Push(checked_arg); // length - if_builder.End(); - - // Figure out total size - HValue* length = Pop(); - HValue* capacity = Pop(); - return array_builder->AllocateArray(capacity, length, true); + return BuildAllocateArrayFromLength(array_builder, argument); } HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor( JSArrayBuilder* array_builder, ElementsKind kind) { + // Insert a bounds check because the number of arguments might exceed + // the kInitialMaxFastElementArray limit. This cannot happen for code + // that was parsed, but calling via Array.apply(thisArg, [...]) might + // trigger it. + HValue* length = GetArgumentsLength(); + HConstant* max_alloc_length = + Add<HConstant>(JSObject::kInitialMaxFastElementArray); + HValue* checked_length = Add<HBoundsCheck>(length, max_alloc_length); + // We need to fill with the hole if it's a smi array in the multi-argument // case because we might have to bail out while copying arguments into // the array because they aren't compatible with a smi array. // If it's a double array, no problem, and if it's fast then no // problem either because doubles are boxed. - HValue* length = GetArgumentsLength(); - bool fill_with_hole = IsFastSmiElementsKind(kind); - HValue* new_object = array_builder->AllocateArray(length, - length, - fill_with_hole); + // + // TODO(mvstanton): consider an instruction to memset fill the array + // with zero in this case instead. + JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) + ? JSArrayBuilder::FILL_WITH_HOLE + : JSArrayBuilder::DONT_FILL_WITH_HOLE; + HValue* new_object = array_builder->AllocateArray(checked_length, + checked_length, + fill_mode); HValue* elements = array_builder->GetElementsLocation(); ASSERT(elements != NULL); @@ -688,10 +772,10 @@ HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor( context(), LoopBuilder::kPostIncrement); HValue* start = graph()->GetConstant0(); - HValue* key = builder.BeginBody(start, length, Token::LT); + HValue* key = builder.BeginBody(start, checked_length, Token::LT); HInstruction* argument_elements = Add<HArgumentsElements>(false); - HInstruction* argument = AddInstruction(new(zone()) HAccessArgumentsAt( - argument_elements, length, key)); + HInstruction* argument = Add<HAccessArgumentsAt>( + argument_elements, checked_length, key); Add<HStoreKeyed>(elements, key, argument, kind); builder.EndBody(); @@ -792,7 +876,7 @@ HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() { HIfContinuation continuation; Handle<Map> sentinel_map(isolate->heap()->meta_map()); Handle<Type> type = stub->GetType(isolate, sentinel_map); - BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation); + BuildCompareNil(GetParameter(0), type, &continuation); IfBuilder if_nil(this, &continuation); if_nil.Then(); if (continuation.IsFalseReachable()) { @@ -812,6 +896,142 @@ Handle<Code> CompareNilICStub::GenerateCode(Isolate* isolate) { template <> +HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() { + BinaryOpIC::State state = casted_stub()->state(); + + HValue* left = GetParameter(BinaryOpICStub::kLeft); + HValue* right = GetParameter(BinaryOpICStub::kRight); + + Handle<Type> left_type = state.GetLeftType(isolate()); + Handle<Type> right_type = state.GetRightType(isolate()); + Handle<Type> result_type = state.GetResultType(isolate()); + + ASSERT(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) && + (state.HasSideEffects() || !result_type->Is(Type::None()))); + + HValue* result = NULL; + if (state.op() == Token::ADD && + (left_type->Maybe(Type::String()) || right_type->Maybe(Type::String())) && + !left_type->Is(Type::String()) && !right_type->Is(Type::String())) { + // For the generic add stub a fast case for string addition is performance + // critical. + if (left_type->Maybe(Type::String())) { + IfBuilder if_leftisstring(this); + if_leftisstring.If<HIsStringAndBranch>(left); + if_leftisstring.Then(); + { + Push(BuildBinaryOperation( + state.op(), left, right, + handle(Type::String(), isolate()), right_type, + result_type, state.fixed_right_arg())); + } + if_leftisstring.Else(); + { + Push(BuildBinaryOperation( + state.op(), left, right, + left_type, right_type, result_type, + state.fixed_right_arg())); + } + if_leftisstring.End(); + result = Pop(); + } else { + IfBuilder if_rightisstring(this); + if_rightisstring.If<HIsStringAndBranch>(right); + if_rightisstring.Then(); + { + Push(BuildBinaryOperation( + state.op(), left, right, + left_type, handle(Type::String(), isolate()), + result_type, state.fixed_right_arg())); + } + if_rightisstring.Else(); + { + Push(BuildBinaryOperation( + state.op(), left, right, + left_type, right_type, result_type, + state.fixed_right_arg())); + } + if_rightisstring.End(); + result = Pop(); + } + } else { + result = BuildBinaryOperation( + state.op(), left, right, + left_type, right_type, result_type, + state.fixed_right_arg()); + } + + // If we encounter a generic argument, the number conversion is + // observable, thus we cannot afford to bail out after the fact. + if (!state.HasSideEffects()) { + if (result_type->Is(Type::Smi())) { + if (state.op() == Token::SHR) { + // TODO(olivf) Replace this by a SmiTagU Instruction. + // 0x40000000: this number would convert to negative when interpreting + // the register as signed value; + IfBuilder if_of(this); + if_of.IfNot<HCompareNumericAndBranch>(result, + Add<HConstant>(static_cast<int>(SmiValuesAre32Bits() + ? 0x80000000 : 0x40000000)), Token::EQ_STRICT); + if_of.Then(); + if_of.ElseDeopt("UInt->Smi oveflow"); + if_of.End(); + } + } + result = EnforceNumberType(result, result_type); + } + + // Reuse the double box of one of the operands if we are allowed to (i.e. + // chained binops). + if (state.CanReuseDoubleBox()) { + HValue* operand = (state.mode() == OVERWRITE_LEFT) ? left : right; + IfBuilder if_heap_number(this); + if_heap_number.IfNot<HIsSmiAndBranch>(operand); + if_heap_number.Then(); + Add<HStoreNamedField>(operand, HObjectAccess::ForHeapNumberValue(), result); + Push(operand); + if_heap_number.Else(); + Push(result); + if_heap_number.End(); + result = Pop(); + } + + return result; +} + + +Handle<Code> BinaryOpICStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + +template <> +HValue* CodeStubGraphBuilder<NewStringAddStub>::BuildCodeInitializedStub() { + NewStringAddStub* stub = casted_stub(); + StringAddFlags flags = stub->flags(); + PretenureFlag pretenure_flag = stub->pretenure_flag(); + + HValue* left = GetParameter(NewStringAddStub::kLeft); + HValue* right = GetParameter(NewStringAddStub::kRight); + + // Make sure that both arguments are strings if not known in advance. + if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { + left = BuildCheckString(left); + } + if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { + right = BuildCheckString(right); + } + + return BuildStringAdd(left, right, pretenure_flag); +} + + +Handle<Code> NewStringAddStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + +template <> HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() { ToBooleanStub* stub = casted_stub(); @@ -918,8 +1138,7 @@ void CodeStubGraphBuilderBase::BuildInstallOptimizedCode( HValue* native_context, HValue* code_object) { Counters* counters = isolate()->counters(); - AddIncrementCounter(counters->fast_new_closure_install_optimized(), - context()); + AddIncrementCounter(counters->fast_new_closure_install_optimized()); // TODO(fschneider): Idea: store proper code pointers in the optimized code // map and either unmangle them on marking or do nothing as the whole map is @@ -967,7 +1186,7 @@ void CodeStubGraphBuilderBase::BuildInstallFromOptimizedCodeMap( } is_optimized.Else(); { - AddIncrementCounter(counters->fast_new_closure_try_optimized(), context()); + AddIncrementCounter(counters->fast_new_closure_try_optimized()); // optimized_map points to fixed array of 3-element entries // (native context, optimized code, literals). // Map must never be empty, so check the first elements. @@ -1012,8 +1231,8 @@ void CodeStubGraphBuilderBase::BuildInstallFromOptimizedCodeMap( } restore_check.Else(); { - HValue* keyed_minus = AddInstruction(HSub::New(zone(), context(), key, - shared_function_entry_length)); + HValue* keyed_minus = AddUncasted<HSub>( + key, shared_function_entry_length); HInstruction* keyed_lookup = Add<HLoadKeyed>(optimized_map, keyed_minus, static_cast<HValue*>(NULL), FAST_ELEMENTS); IfBuilder done_check(this); @@ -1022,8 +1241,8 @@ void CodeStubGraphBuilderBase::BuildInstallFromOptimizedCodeMap( done_check.Then(); { // Hit: fetch the optimized code. - HValue* keyed_plus = AddInstruction(HAdd::New(zone(), context(), - keyed_minus, graph()->GetConstant1())); + HValue* keyed_plus = AddUncasted<HAdd>( + keyed_minus, graph()->GetConstant1()); HValue* code_object = Add<HLoadKeyed>(optimized_map, keyed_plus, static_cast<HValue*>(NULL), FAST_ELEMENTS); BuildInstallOptimizedCode(js_function, native_context, code_object); @@ -1052,11 +1271,12 @@ HValue* CodeStubGraphBuilder<FastNewClosureStub>::BuildCodeStub() { Add<HConstant>(factory->empty_fixed_array()); HValue* shared_info = GetParameter(0); + AddIncrementCounter(counters->fast_new_closure_total()); + // Create a new closure from the given function info in new space HValue* size = Add<HConstant>(JSFunction::kSize); HInstruction* js_function = Add<HAllocate>(size, HType::JSObject(), NOT_TENURED, JS_FUNCTION_TYPE); - AddIncrementCounter(counters->fast_new_closure_total(), context()); int map_index = Context::FunctionMapIndex(casted_stub()->language_mode(), casted_stub()->is_generator()); @@ -1101,4 +1321,20 @@ Handle<Code> FastNewClosureStub::GenerateCode(Isolate* isolate) { } +template<> +HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::BuildCodeStub() { + HValue* receiver = GetParameter(0); + HValue* key = GetParameter(1); + + Add<HCheckSmi>(key); + + return BuildUncheckedDictionaryElementLoad(receiver, key); +} + + +Handle<Code> KeyedLoadDictionaryElementStub::GenerateCode(Isolate* isolate) { + return DoGenerateCode(isolate, this); +} + + } } // namespace v8::internal |