Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: src/hydrogen.cc

Issue 55933002: Inline array constructor. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Even better codegen for 1 arg case, and refactoring. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/ia32/code-stubs-ia32.cc » ('j') | src/ia32/code-stubs-ia32.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698