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

Side by Side Diff: src/codegen-ia32.cc

Issue 5002: Port of fast-case switch to ARM (Closed)
Patch Set: Updates based on review comments Created 12 years, 2 months 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
« no previous file with comments | « src/codegen-arm.cc ('k') | src/macro-assembler-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 // this factor times the number of case labels. 318 // this factor times the number of case labels.
319 // Value is derived from comparing the size of code generated by the normal 319 // Value is derived from comparing the size of code generated by the normal
320 // switch code for Smi-labels to the size of a single pointer. If code 320 // switch code for Smi-labels to the size of a single pointer. If code
321 // quality increases this number should be decreased to match. 321 // quality increases this number should be decreased to match.
322 static const int kFastSwitchMaxOverheadFactor = 5; 322 static const int kFastSwitchMaxOverheadFactor = 5;
323 323
324 // Minimal number of switch cases required before we allow jump-table 324 // Minimal number of switch cases required before we allow jump-table
325 // optimization. 325 // optimization.
326 static const int kFastSwitchMinCaseCount = 5; 326 static const int kFastSwitchMinCaseCount = 5;
327 327
328 // Create fast switch implementation if all labels are small integers 328 virtual int FastCaseSwitchMaxOverheadFactor();
329 // in a limited range. Returns false if this is not the case, and no 329 virtual int FastCaseSwitchMinCaseCount();
330 // code has been generated (i.e., the default implementation should be used).
331 bool TryFastCaseSwitchStatement(SwitchStatement *switchStmt);
332 330
333 // Generate a computed jump with an empty jump table. 331 // Generate a computed jump with an empty jump table.
334 // Binds a label to the start of the jump table. This table must 332 // Binds a label to the start of the jump table. This table must
335 // be populated later when the adresses of the targets are known. 333 // be populated later when the adresses of the targets are known.
336 // Used by GenerateFastCaseSwitchStatement. 334 // Used by GenerateFastCaseSwitchStatement.
337 void GenerateFastCaseSwitchJumpTable( 335 virtual void GenerateFastCaseSwitchJumpTable(
338 int min_index, int range, Label *fail_label, Label &table_start); 336 SwitchStatement* node, int min_index, int range, Label *fail_label,
339 337 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels);
340 // Populate an empty jump table with the adresses of bound labels.
341 // Used by GenerateFastCaseSwitchStatement.
342 void PopulateFastCaseSwitchJumpTable(
343 Label &table_start, SmartPointer<Label*> &case_targets, int table_size);
344
345 // Generates a fast-case switch statement for a switch with all-Smi labels
346 // in a limited range.
347 // Used by TryFastCaseSwitchStatement.
348 void GenerateFastCaseSwitchStatement(
349 SwitchStatement *node, int min_index, int range, int default_index);
350 338
351 void RecordStatementPosition(Node* node); 339 void RecordStatementPosition(Node* node);
352 340
353 // Activation frames. 341 // Activation frames.
354 void EnterJSFrame(); 342 void EnterJSFrame();
355 void ExitJSFrame(); 343 void ExitJSFrame();
356 344
357 virtual void GenerateIsSmi(ZoneList<Expression*>* args); 345 virtual void GenerateIsSmi(ZoneList<Expression*>* args);
358 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); 346 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
359 virtual void GenerateIsArray(ZoneList<Expression*>* args); 347 virtual void GenerateIsArray(ZoneList<Expression*>* args);
(...skipping 2566 matching lines...) Expand 10 before | Expand all | Expand 10 after
2926 2914
2927 2915
2928 void Ia32CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { 2916 void Ia32CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
2929 Comment cmnt(masm_, "[ WithExitStatement"); 2917 Comment cmnt(masm_, "[ WithExitStatement");
2930 // Pop context. 2918 // Pop context.
2931 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); 2919 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
2932 // Update context local. 2920 // Update context local.
2933 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); 2921 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
2934 } 2922 }
2935 2923
2924 int Ia32CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
2925 return kFastSwitchMaxOverheadFactor;
2926 }
2936 2927
2937 // Generate a computed jump with an empty jump table. 2928 int Ia32CodeGenerator::FastCaseSwitchMinCaseCount() {
2938 // Returns a label pointing to the start of the jump table. This must 2929 return kFastSwitchMinCaseCount;
2939 // be populated later when the adresses of the targets are known 2930 }
2931
2932 // Generate a computed jump to a switch case.
2940 void Ia32CodeGenerator::GenerateFastCaseSwitchJumpTable( 2933 void Ia32CodeGenerator::GenerateFastCaseSwitchJumpTable(
2941 int min_index, int range, Label *fail_label, Label &table_start) { 2934 SwitchStatement* node, int min_index, int range, Label *fail_label,
2935 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) {
2942 // Notice: Internal references, used by both the jmp instruction and 2936 // Notice: Internal references, used by both the jmp instruction and
2943 // the table entries, need to be relocated if the buffer grows. This 2937 // the table entries, need to be relocated if the buffer grows. This
2944 // prevents the forward use of Labels, since a displacement cannot 2938 // prevents the forward use of Labels, since a displacement cannot
2945 // survive relocation, and it also cannot safely be distinguished 2939 // survive relocation, and it also cannot safely be distinguished
2946 // from a real address. Instead we put in zero-values as 2940 // from a real address. Instead we put in zero-values as
2947 // placeholders, and fill in the adresses after the labels have been 2941 // placeholders, and fill in the addresses after the labels have been
2948 // bound. 2942 // bound.
2949 2943
2950 __ pop(eax); // supposed smi 2944 __ pop(eax); // supposed smi
2951 // check range of value, if outside [0..length-1] jump to default/end label. 2945 // check range of value, if outside [0..length-1] jump to default/end label.
2952 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 2946 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
2953 if (min_index != 0) { 2947 if (min_index != 0) {
2954 __ sub(Operand(eax), Immediate(min_index * 2)); // smi subtraction 2948 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
2955 } 2949 }
2956 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not smi 2950 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi
2957 __ j(not_equal, fail_label, not_taken); 2951 __ j(not_equal, fail_label, not_taken);
2958 __ cmp(eax, range * 2); 2952 __ cmp(eax, range << kSmiTagSize);
2959 __ j(greater_equal, fail_label, not_taken); 2953 __ j(greater_equal, fail_label, not_taken);
2960 2954
2961 __ jmp(Operand(eax, times_2, 0x0, internal_reference)); // 0 is placeholder 2955 __ jmp(Operand(eax, times_2, 0x0, internal_reference)); // 0 is placeholder
2962 // calculate address to overwrite later with actual address of table. 2956 // calculate address to overwrite later with actual address of table.
2963 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); 2957 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
2964 2958
2965 __ Align(4); 2959 __ Align(4);
2960 Label table_start;
2966 __ bind(&table_start); 2961 __ bind(&table_start);
2967 __ WriteInternalReference(jump_table_ref, table_start); 2962 __ WriteInternalReference(jump_table_ref, table_start);
2968 2963
2969 for (int i = 0; i < range; i++) { 2964 for (int i = 0; i < range; i++) {
2970 __ dd(0x0, internal_reference); // table entry, 0 is placeholder 2965 __ dd(0x0, internal_reference); // table entry, 0 is placeholder
2971 } 2966 }
2972 }
2973 2967
2968 GenerateFastCaseSwitchCases(node, case_labels);
2974 2969
2975 // Populate an empty jump table with the adresses of bound labels. 2970 for (int i = 0, entry_pos = table_start.pos();
2976 void Ia32CodeGenerator::PopulateFastCaseSwitchJumpTable( 2971 i < range; i++, entry_pos += sizeof(uint32_t)) {
2977 Label &table_start, SmartPointer<Label*> &case_targets, int table_size) { 2972 __ WriteInternalReference(entry_pos, *case_targets[i]);
2978 for (int i = 0; i < table_size; i++) {
2979 int table_entry_pos = table_start.pos() + i * sizeof(uint32_t);
2980 __ WriteInternalReference(table_entry_pos, *case_targets[i]);
2981 } 2973 }
2982 } 2974 }
2983 2975
2984 2976
2985 // Generates a fast-case switch statement for a switch with all-Smi labels
2986 // in a limited range.
2987 void Ia32CodeGenerator::GenerateFastCaseSwitchStatement(
2988 SwitchStatement *node, int min_index, int range, int default_index) {
2989 ZoneList<CaseClause*>* cases = node->cases();
2990 int length = cases->length();
2991
2992 SmartPointer<Label*> case_targets(NewArray<Label*>(range));
2993 SmartPointer<Label> case_labels(NewArray<Label>(length));
2994
2995 Label* fail_label = (default_index >= 0 ? &(case_labels[default_index])
2996 : node->break_target());
2997
2998 // Create array of labels to jump to by index and set default jump
2999 // targets everywhere.
3000 for (int i = 0; i < range; i++) {
3001 // length => end label
3002 case_targets[i] = fail_label;
3003 }
3004
3005 // Overwrite for values of cases:
3006 // (reverse order, so that if same label twice, the first one wins).
3007 for (int i = length-1; i >= 0 ; i--) {
3008 CaseClause* clause = cases->at(i);
3009 if (!clause->is_default()) {
3010 Object* label_value = *(clause->label()->AsLiteral()->handle());
3011 int case_value = Smi::cast(label_value)->value();
3012 case_targets[case_value - min_index] = &(case_labels[i]);
3013 }
3014 }
3015
3016 // Generate the jump table and code for all cases.
3017 Label table_start;
3018
3019 GenerateFastCaseSwitchJumpTable(min_index, range, fail_label, table_start);
3020
3021 for (int i = 0; i < length; i++) {
3022 Comment cmnt(masm_, "[ case clause");
3023 __ bind(&(case_labels[i]));
3024 VisitStatements(cases->at(i)->statements());
3025 }
3026
3027 __ bind(node->break_target());
3028
3029 // All labels bound now, so we can populate the table with the
3030 // correct addresses.
3031 PopulateFastCaseSwitchJumpTable(table_start, case_targets, range);
3032 }
3033
3034
3035 bool Ia32CodeGenerator::TryFastCaseSwitchStatement(SwitchStatement *node) {
3036 ZoneList<CaseClause*>* cases = node->cases();
3037 int length = cases->length();
3038
3039 if (length < kFastSwitchMinCaseCount) {
3040 return false;
3041 }
3042
3043 // Test whether fast-case should be used.
3044 int default_index = -1;
3045 int min_index = Smi::kMaxValue;
3046 int max_index = Smi::kMinValue;
3047 for (int i = 0; i < length; i++) {
3048 CaseClause* clause = cases->at(i);
3049 if (clause->is_default()) {
3050 if (default_index >= 0) {
3051 return false; // More than one default label:
3052 // Defer to normal case for error.
3053 }
3054 default_index = i;
3055 } else {
3056 Expression* label = clause->label();
3057 Literal* literal = label->AsLiteral();
3058 if (literal == NULL) {
3059 return false; // fail fast case
3060 }
3061 Object* value = *(literal->handle());
3062 if (!value->IsSmi()) {
3063 return false;
3064 }
3065 int smi = Smi::cast(value)->value();
3066 if (smi < min_index) { min_index = smi; }
3067 if (smi > max_index) { max_index = smi; }
3068 }
3069 }
3070
3071 // After this all labels are smis.
3072 int range = max_index - min_index + 1; // |min..max| inclusive
3073 if (range / kFastSwitchMaxOverheadFactor > length) {
3074 return false; // range of labels is too sparse
3075 }
3076
3077 // Optimization accepted, generate code.
3078 GenerateFastCaseSwitchStatement(node, min_index, range, default_index);
3079 return true;
3080 }
3081
3082
3083 void Ia32CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { 2977 void Ia32CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
3084 Comment cmnt(masm_, "[ SwitchStatement"); 2978 Comment cmnt(masm_, "[ SwitchStatement");
3085 RecordStatementPosition(node); 2979 RecordStatementPosition(node);
3086 node->set_break_stack_height(break_stack_height_); 2980 node->set_break_stack_height(break_stack_height_);
3087 2981
3088 Load(node->tag()); 2982 Load(node->tag());
3089 2983
3090 if (TryFastCaseSwitchStatement(node)) { 2984 if (TryGenerateFastCaseSwitchStatement(node)) {
3091 return; 2985 return;
3092 } 2986 }
3093 2987
3094 Label next, fall_through, default_case; 2988 Label next, fall_through, default_case;
3095 ZoneList<CaseClause*>* cases = node->cases(); 2989 ZoneList<CaseClause*>* cases = node->cases();
3096 int length = cases->length(); 2990 int length = cases->length();
3097 2991
3098 for (int i = 0; i < length; i++) { 2992 for (int i = 0; i < length; i++) {
3099 CaseClause* clause = cases->at(i); 2993 CaseClause* clause = cases->at(i);
3100 Comment cmnt(masm_, "[ case clause"); 2994 Comment cmnt(masm_, "[ case clause");
(...skipping 2482 matching lines...) Expand 10 before | Expand all | Expand 10 after
5583 bool is_eval) { 5477 bool is_eval) {
5584 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); 5478 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval);
5585 if (!code.is_null()) { 5479 if (!code.is_null()) {
5586 Counters::total_compiled_code_size.Increment(code->instruction_size()); 5480 Counters::total_compiled_code_size.Increment(code->instruction_size());
5587 } 5481 }
5588 return code; 5482 return code;
5589 } 5483 }
5590 5484
5591 5485
5592 } } // namespace v8::internal 5486 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.cc ('k') | src/macro-assembler-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698