Chromium Code Reviews| 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 |