OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 2049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2060 ASSERT(length_node != NULL); | 2060 ASSERT(length_node != NULL); |
2061 | 2061 |
2062 int base_size = JSArray::kSize; | 2062 int base_size = JSArray::kSize; |
2063 if (mode_ == TRACK_ALLOCATION_SITE) { | 2063 if (mode_ == TRACK_ALLOCATION_SITE) { |
2064 base_size += AllocationMemento::kSize; | 2064 base_size += AllocationMemento::kSize; |
2065 } | 2065 } |
2066 | 2066 |
2067 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); | 2067 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
2068 base_size += FixedArray::kHeaderSize; | 2068 base_size += FixedArray::kHeaderSize; |
2069 | 2069 |
2070 if (length_node->IsConstant()) { | |
2071 HConstant* constant_length_node = HConstant::cast(length_node); | |
2072 if (constant_length_node->HasInteger32Value()) { | |
2073 int size = base_size + elements_size() * | |
2074 constant_length_node->Integer32Value(); | |
2075 HInstruction* const_size = builder()->Add<HConstant>(size); | |
2076 return const_size; | |
2077 } | |
2078 } | |
2079 | |
2070 HInstruction* elements_size_value = | 2080 HInstruction* elements_size_value = |
2071 builder()->Add<HConstant>(elements_size()); | 2081 builder()->Add<HConstant>(elements_size()); |
2072 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); | 2082 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); |
2073 mul->ClearFlag(HValue::kCanOverflow); | 2083 mul->ClearFlag(HValue::kCanOverflow); |
2074 | 2084 |
2075 HInstruction* base = builder()->Add<HConstant>(base_size); | 2085 HInstruction* base = builder()->Add<HConstant>(base_size); |
2076 HInstruction* total_size = builder()->Add<HAdd>(base, mul); | 2086 HInstruction* total_size = builder()->Add<HAdd>(base, mul); |
2077 total_size->ClearFlag(HValue::kCanOverflow); | 2087 total_size->ClearFlag(HValue::kCanOverflow); |
2078 return total_size; | 2088 return total_size; |
2079 } | 2089 } |
(...skipping 5082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7162 | 7172 |
7163 call = New<HCallFunction>(function, argument_count); | 7173 call = New<HCallFunction>(function, argument_count); |
7164 Drop(argument_count + 1); | 7174 Drop(argument_count + 1); |
7165 } | 7175 } |
7166 } | 7176 } |
7167 | 7177 |
7168 return ast_context()->ReturnInstruction(call, expr->id()); | 7178 return ast_context()->ReturnInstruction(call, expr->id()); |
7169 } | 7179 } |
7170 | 7180 |
7171 | 7181 |
7182 HValue* HOptimizedGraphBuilder::BuildInlinedCallNewArray_OneArg( | |
7183 CallNew* expr, | |
7184 HValue* constructor, | |
7185 HInstruction* cell_instruction) { | |
7186 ElementsKind kind = expr->elements_kind(); | |
7187 HValue* argument = environment()->ExpressionStackAt(0); | |
Toon Verwaest
2013/11/06 16:42:44
Top();
mvstanton
2013/11/07 16:34:05
Done.
| |
7188 HValue* new_object; | |
7189 if (argument->IsConstant()) { | |
7190 HConstant* constant_argument = HConstant::cast(argument); | |
7191 ASSERT(constant_argument->HasSmiValue()); | |
7192 int value = constant_argument->Integer32Value(); | |
Toon Verwaest
2013/11/06 16:42:44
Rename value to array_size.
mvstanton
2013/11/07 16:34:05
Done.
| |
7193 JSArrayBuilder array_builder(this, | |
7194 value == 0 | |
7195 ? kind | |
7196 : GetHoleyElementsKind(kind), | |
7197 cell_instruction, | |
7198 constructor, | |
7199 DISABLE_ALLOCATION_SITES); | |
7200 | |
7201 new_object = (value == 0) | |
7202 ? array_builder.AllocateEmptyArray() | |
7203 : array_builder.AllocateArray(argument, argument, true); | |
Toon Verwaest
2013/11/06 16:42:44
Can we replace that "true" with an enum indicating
mvstanton
2013/11/07 16:34:05
Done. Doing this correctly took me on a refactorin
| |
7204 } else { | |
7205 ASSERT(IsHoleyElementsKind(kind)); | |
7206 | |
7207 // Smi check and range check on the input arg. | |
7208 HValue* constant_zero = graph()->GetConstant0(); | |
7209 HConstant* max_alloc_length = | |
7210 Add<HConstant>(JSObject::kInitialMaxFastElementArray); | |
7211 const int initial_capacity = JSArray::kPreallocatedArrayElements; | |
7212 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); | |
7213 HInstruction* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length); | |
7214 IfBuilder if_builder(this); | |
7215 if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero, | |
7216 Token::EQ); | |
7217 | |
7218 if_builder.Then(); | |
7219 Push(initial_capacity_node); // capacity | |
7220 Push(constant_zero); // length | |
7221 if_builder.Else(); | |
7222 Push(checked_arg); // capacity | |
7223 Push(checked_arg); // length | |
7224 if_builder.End(); | |
7225 | |
7226 // Figure out total size | |
7227 HValue* length = Pop(); | |
7228 HValue* capacity = Pop(); | |
7229 JSArrayBuilder array_builder(this, | |
7230 kind, | |
7231 cell_instruction, | |
7232 constructor, | |
7233 DISABLE_ALLOCATION_SITES); | |
7234 new_object = array_builder.AllocateArray(capacity, length, true); | |
7235 } | |
7236 | |
7237 return new_object; | |
7238 } | |
7239 | |
7240 | |
7241 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { | |
7242 NoObservableSideEffectsScope no_effects(this); | |
7243 | |
7244 int argument_count = expr->arguments()->length(); | |
7245 // We should at least have the constructor on the expression stack. | |
7246 ASSERT(!environment()->ExpressionStackIsEmpty()); | |
7247 HValue* constructor = environment()->ExpressionStackAt(argument_count); | |
7248 | |
7249 ElementsKind kind = expr->elements_kind(); | |
7250 Handle<Cell> cell = expr->allocation_info_cell(); | |
7251 AllocationSite* site = AllocationSite::cast(cell->value()); | |
7252 | |
7253 // Register on the site for deoptimization if the cell value changes. | |
7254 site->AddDependentCompilationInfo(AllocationSite::TRANSITIONS, top_info()); | |
7255 HInstruction* cell_instruction = Add<HConstant>(cell); | |
7256 | |
7257 // Build the array. | |
7258 HValue* new_object; | |
7259 if (argument_count == 0) { | |
7260 JSArrayBuilder array_builder(this, | |
7261 kind, | |
7262 cell_instruction, | |
7263 constructor, | |
7264 DISABLE_ALLOCATION_SITES); | |
7265 new_object = array_builder.AllocateEmptyArray(); | |
7266 } else if (argument_count == 1) { | |
7267 new_object = BuildInlinedCallNewArray_OneArg(expr, constructor, | |
7268 cell_instruction); | |
7269 } else { | |
7270 ASSERT(argument_count <= 5); | |
Toon Verwaest
2013/11/06 16:42:44
Why 5? Can we at least make it a descriptive const
mvstanton
2013/11/07 16:34:05
Done.
| |
7271 JSArrayBuilder array_builder(this, | |
7272 kind, | |
7273 cell_instruction, | |
7274 constructor, | |
7275 DISABLE_ALLOCATION_SITES); | |
7276 HValue* length = Add<HConstant>(argument_count); | |
7277 bool fill_with_hole = IsFastSmiElementsKind(kind); | |
7278 new_object = array_builder.AllocateArray(length, length, fill_with_hole); | |
Toon Verwaest
2013/11/06 16:42:44
Why do we only fill with holes if the kind is smi?
mvstanton
2013/11/07 16:34:05
Done. Bailout could occur in the HStoreKeyed if we
| |
7279 HValue* elements = array_builder.GetElementsLocation(); | |
7280 for (int i = 0; i < argument_count; i++) { | |
7281 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1); | |
7282 HValue* constant_i = Add<HConstant>(i); | |
7283 Add<HStoreKeyed>(elements, constant_i, value, kind); | |
7284 } | |
7285 } | |
7286 | |
7287 Drop(argument_count + 1); // drop constructor and args. | |
7288 ast_context()->ReturnValue(new_object); | |
7289 } | |
7290 | |
7291 | |
7172 // Checks whether allocation using the given constructor can be inlined. | 7292 // Checks whether allocation using the given constructor can be inlined. |
7173 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7293 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
7174 return constructor->has_initial_map() && | 7294 return constructor->has_initial_map() && |
7175 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7295 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
7176 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 7296 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
7177 constructor->initial_map()->InitialPropertiesLength() == 0; | 7297 constructor->initial_map()->InitialPropertiesLength() == 0; |
7178 } | 7298 } |
7179 | 7299 |
7180 | 7300 |
7301 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { | |
7302 bool inline_ok = false; | |
7303 int argument_count = expr->arguments()->length(); | |
7304 // We should have the function plus array arguments on the environment stack. | |
7305 ASSERT(environment()->length() >= (argument_count + 1)); | |
7306 if (argument_count <= 5) { | |
Toon Verwaest
2013/11/06 16:42:44
Why 5?
mvstanton
2013/11/07 16:34:05
Why indeed. I eliminated this as any predicate.
| |
7307 Handle<Cell> cell = expr->allocation_info_cell(); | |
7308 AllocationSite* site = AllocationSite::cast(cell->value()); | |
7309 if (!site->DoNotInlineCall()) { | |
Toon Verwaest
2013/11/06 16:42:44
What about just CanInlineCall() rather than the do
mvstanton
2013/11/07 16:34:05
Done.
| |
7310 // We also want to avoid inlining in certain 1 argument scenarios. | |
7311 if (argument_count == 1) { | |
7312 HValue* argument = Top(); | |
7313 if (argument->IsConstant()) { | |
7314 // Do not inline if the constant length argument is not a smi or | |
7315 // outside the valid range for a fast array. | |
7316 HConstant* constant_argument = HConstant::cast(argument); | |
7317 if (constant_argument->HasSmiValue()) { | |
7318 int value = constant_argument->Integer32Value(); | |
7319 inline_ok = value >= 0 && | |
7320 value < JSObject::kInitialMaxFastElementArray; | |
7321 } | |
7322 } else { | |
7323 // The amount of code we'd have to generate doubles if we have a | |
7324 // non-constant length, but packed elements_kind feedback. Don't | |
7325 // inline this case. | |
Toon Verwaest
2013/11/06 16:42:44
Shouldn't we just generate a check whether the arg
mvstanton
2013/11/07 16:34:05
I think it's a lot of trouble for a corner case (n
| |
7326 inline_ok = IsHoleyElementsKind(expr->elements_kind()); | |
7327 } | |
7328 } else { | |
7329 inline_ok = true; | |
7330 } | |
7331 } | |
7332 } | |
7333 return inline_ok; | |
7334 } | |
7335 | |
7336 | |
7181 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7337 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
7182 ASSERT(!HasStackOverflow()); | 7338 ASSERT(!HasStackOverflow()); |
7183 ASSERT(current_block() != NULL); | 7339 ASSERT(current_block() != NULL); |
7184 ASSERT(current_block()->HasPredecessor()); | 7340 ASSERT(current_block()->HasPredecessor()); |
7185 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 7341 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
7186 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7342 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
7187 Factory* factory = isolate()->factory(); | 7343 Factory* factory = isolate()->factory(); |
7188 | 7344 |
7345 // The constructor function is on the stack in the unoptimized code | |
7346 // during evaluation of the arguments. | |
7347 CHECK_ALIVE(VisitForValue(expr->expression())); | |
7348 HValue* function = Top(); | |
7349 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
7350 | |
7189 if (FLAG_inline_construct && | 7351 if (FLAG_inline_construct && |
7190 expr->IsMonomorphic() && | 7352 expr->IsMonomorphic() && |
7191 IsAllocationInlineable(expr->target())) { | 7353 IsAllocationInlineable(expr->target())) { |
7192 // The constructor function is on the stack in the unoptimized code | |
7193 // during evaluation of the arguments. | |
7194 CHECK_ALIVE(VisitForValue(expr->expression())); | |
7195 HValue* function = Top(); | |
7196 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
7197 Handle<JSFunction> constructor = expr->target(); | 7354 Handle<JSFunction> constructor = expr->target(); |
7198 HValue* check = Add<HCheckValue>(function, constructor); | 7355 HValue* check = Add<HCheckValue>(function, constructor); |
7199 | 7356 |
7200 // Force completion of inobject slack tracking before generating | 7357 // Force completion of inobject slack tracking before generating |
7201 // allocation code to finalize instance size. | 7358 // allocation code to finalize instance size. |
7202 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7359 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
7203 constructor->shared()->CompleteInobjectSlackTracking(); | 7360 constructor->shared()->CompleteInobjectSlackTracking(); |
7204 } | 7361 } |
7205 | 7362 |
7206 // Calculate instance size from initial map of constructor. | 7363 // Calculate instance size from initial map of constructor. |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7273 check->DeleteAndReplaceWith(NULL); | 7430 check->DeleteAndReplaceWith(NULL); |
7274 environment()->SetExpressionStackAt(receiver_index, function); | 7431 environment()->SetExpressionStackAt(receiver_index, function); |
7275 HInstruction* call = | 7432 HInstruction* call = |
7276 PreProcessCall(New<HCallNew>(function, argument_count)); | 7433 PreProcessCall(New<HCallNew>(function, argument_count)); |
7277 return ast_context()->ReturnInstruction(call, expr->id()); | 7434 return ast_context()->ReturnInstruction(call, expr->id()); |
7278 } else { | 7435 } else { |
7279 // The constructor function is both an operand to the instruction and an | 7436 // The constructor function is both an operand to the instruction and an |
7280 // argument to the construct call. | 7437 // argument to the construct call. |
7281 Handle<JSFunction> array_function( | 7438 Handle<JSFunction> array_function( |
7282 isolate()->global_context()->array_function(), isolate()); | 7439 isolate()->global_context()->array_function(), isolate()); |
7283 CHECK_ALIVE(VisitArgument(expr->expression())); | 7440 bool use_call_new_array = expr->target().is_identical_to(array_function); |
7284 HValue* constructor = HPushArgument::cast(Top())->argument(); | 7441 Handle<Cell> cell = expr->allocation_info_cell(); |
Toon Verwaest
2013/11/06 16:42:44
Why is it ok to merge this with the code above? Th
mvstanton
2013/11/07 16:34:05
Because I changed this whole else block to work li
| |
7285 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7442 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
7443 // Verify we are still calling the array function for our native context. | |
7444 Add<HCheckValue>(function, array_function); | |
7445 BuildInlinedCallNewArray(expr); | |
7446 return; | |
7447 } | |
7448 | |
7286 HBinaryCall* call; | 7449 HBinaryCall* call; |
7287 if (expr->target().is_identical_to(array_function)) { | 7450 if (use_call_new_array) { |
7288 Handle<Cell> cell = expr->allocation_info_cell(); | 7451 Add<HCheckValue>(function, array_function); |
7289 Add<HCheckValue>(constructor, array_function); | 7452 call = New<HCallNewArray>(function, argument_count, cell, |
7290 call = New<HCallNewArray>(constructor, argument_count, | 7453 expr->elements_kind()); |
7291 cell, expr->elements_kind()); | |
7292 } else { | 7454 } else { |
7293 call = New<HCallNew>(constructor, argument_count); | 7455 call = New<HCallNew>(function, argument_count); |
7294 } | 7456 } |
7295 Drop(argument_count); | 7457 PreProcessCall(call); |
7296 return ast_context()->ReturnInstruction(call, expr->id()); | 7458 return ast_context()->ReturnInstruction(call, expr->id()); |
7297 } | 7459 } |
7298 } | 7460 } |
7299 | 7461 |
7300 | 7462 |
7301 // Support for generating inlined runtime functions. | 7463 // Support for generating inlined runtime functions. |
7302 | 7464 |
7303 // Lookup table for generators for runtime calls that are generated inline. | 7465 // Lookup table for generators for runtime calls that are generated inline. |
7304 // Elements of the table are member pointers to functions of | 7466 // Elements of the table are member pointers to functions of |
7305 // HOptimizedGraphBuilder. | 7467 // HOptimizedGraphBuilder. |
(...skipping 2517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9823 if (ShouldProduceTraceOutput()) { | 9985 if (ShouldProduceTraceOutput()) { |
9824 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9986 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
9825 } | 9987 } |
9826 | 9988 |
9827 #ifdef DEBUG | 9989 #ifdef DEBUG |
9828 graph_->Verify(false); // No full verify. | 9990 graph_->Verify(false); // No full verify. |
9829 #endif | 9991 #endif |
9830 } | 9992 } |
9831 | 9993 |
9832 } } // namespace v8::internal | 9994 } } // namespace v8::internal |
OLD | NEW |