| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |