summaryrefslogtreecommitdiff
path: root/chromium/v8/src/code-stubs-hydrogen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/code-stubs-hydrogen.cc')
-rw-r--r--chromium/v8/src/code-stubs-hydrogen.cc462
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