Chromium Code Reviews| 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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 | 108 |
| 109 | 109 |
| 110 // ----------------------------------------------------------------------------- | 110 // ----------------------------------------------------------------------------- |
| 111 // Code generation state | 111 // Code generation state |
| 112 | 112 |
| 113 class CodeGenState BASE_EMBEDDED { | 113 class CodeGenState BASE_EMBEDDED { |
| 114 public: | 114 public: |
| 115 enum AccessType { | 115 enum AccessType { |
| 116 UNDEFINED, | 116 UNDEFINED, |
| 117 LOAD, | 117 LOAD, |
| 118 LOAD_TYPEOF_EXPR, | 118 LOAD_TYPEOF_EXPR |
| 119 STORE, | |
| 120 INIT_CONST | |
| 121 }; | 119 }; |
| 122 | 120 |
| 123 CodeGenState() | 121 CodeGenState() |
| 124 : access_(UNDEFINED), | 122 : access_(UNDEFINED), |
| 125 ref_(NULL), | 123 ref_(NULL), |
| 126 true_target_(NULL), | 124 true_target_(NULL), |
| 127 false_target_(NULL) { | 125 false_target_(NULL) { |
| 128 } | 126 } |
| 129 | 127 |
| 130 CodeGenState(AccessType access, | 128 CodeGenState(AccessType access, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 Handle<Script> script, | 178 Handle<Script> script, |
| 181 bool is_eval); | 179 bool is_eval); |
| 182 virtual ~Ia32CodeGenerator() { delete masm_; } | 180 virtual ~Ia32CodeGenerator() { delete masm_; } |
| 183 | 181 |
| 184 // Main code generation function | 182 // Main code generation function |
| 185 void GenCode(FunctionLiteral* fun); | 183 void GenCode(FunctionLiteral* fun); |
| 186 | 184 |
| 187 // The following are used by class Reference. | 185 // The following are used by class Reference. |
| 188 void LoadReference(Reference* ref); | 186 void LoadReference(Reference* ref); |
| 189 void UnloadReference(Reference* ref); | 187 void UnloadReference(Reference* ref); |
| 190 friend class Reference; | |
| 191 | 188 |
| 192 // State | 189 // State |
| 193 bool has_cc() const { return cc_reg_ >= 0; } | 190 bool has_cc() const { return cc_reg_ >= 0; } |
| 194 CodeGenState::AccessType access() const { return state_->access(); } | 191 CodeGenState::AccessType access() const { return state_->access(); } |
| 195 Reference* ref() const { return state_->ref(); } | 192 Reference* ref() const { return state_->ref(); } |
| 196 bool is_referenced() const { return state_->ref() != NULL; } | 193 bool is_referenced() const { return state_->ref() != NULL; } |
| 197 Label* true_target() const { return state_->true_target(); } | 194 Label* true_target() const { return state_->true_target(); } |
| 198 Label* false_target() const { return state_->false_target(); } | 195 Label* false_target() const { return state_->false_target(); } |
| 199 | 196 |
| 200 // Expressions | 197 // Expressions |
| 201 Operand GlobalObject() const { | 198 Operand GlobalObject() const { |
| 202 return ContextOperand(esi, Context::GLOBAL_INDEX); | 199 return ContextOperand(esi, Context::GLOBAL_INDEX); |
| 203 } | 200 } |
| 204 | 201 |
| 205 // Support functions for accessing parameters. | 202 // Support functions for accessing parameters. Static versions can |
| 203 // require some code generator state to be passed in as arguments. | |
| 204 static Operand ParameterOperand(Scope* scope, int index) { | |
| 205 ASSERT(-2 <= index && index < scope->num_parameters()); | |
| 206 return Operand(ebp, (1 + scope->num_parameters() - index) * kPointerSize); | |
| 207 } | |
| 208 | |
| 206 Operand ParameterOperand(int index) const { | 209 Operand ParameterOperand(int index) const { |
| 207 ASSERT(-2 <= index && index < scope_->num_parameters()); | 210 return ParameterOperand(scope_, index); |
| 208 return Operand(ebp, (1 + scope_->num_parameters() - index) * kPointerSize); | |
| 209 } | 211 } |
| 210 | 212 |
| 211 Operand ReceiverOperand() const { return ParameterOperand(-1); } | 213 Operand ReceiverOperand() const { return ParameterOperand(-1); } |
| 214 | |
| 212 Operand FunctionOperand() const { | 215 Operand FunctionOperand() const { |
| 213 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); | 216 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); |
| 214 } | 217 } |
| 215 | 218 |
| 216 Operand ContextOperand(Register context, int index) const { | 219 static Operand ContextOperand(Register context, int index) { |
| 217 return Operand(context, Context::SlotOffset(index)); | 220 return Operand(context, Context::SlotOffset(index)); |
| 218 } | 221 } |
| 219 | 222 |
| 220 Operand SlotOperand(Slot* slot, Register tmp); | 223 static Operand SlotOperand(MacroAssembler* masm, |
| 224 Scope* scope, | |
| 225 Slot* slot, | |
| 226 Register tmp); | |
| 227 | |
| 228 Operand SlotOperand(Slot* slot, Register tmp) { | |
| 229 return SlotOperand(masm_, scope_, slot, tmp); | |
| 230 } | |
| 221 | 231 |
| 222 void LoadCondition(Expression* x, | 232 void LoadCondition(Expression* x, |
| 223 CodeGenState::AccessType access, | 233 CodeGenState::AccessType access, |
| 224 Label* true_target, | 234 Label* true_target, |
| 225 Label* false_target, | 235 Label* false_target, |
| 226 bool force_cc); | 236 bool force_cc); |
| 227 void Load(Expression* x, | 237 void Load(Expression* x, |
| 228 CodeGenState::AccessType access = CodeGenState::LOAD); | 238 CodeGenState::AccessType access = CodeGenState::LOAD); |
| 229 void LoadGlobal(); | 239 void LoadGlobal(); |
| 230 | 240 |
| 231 // Special code for typeof expressions: Unfortunately, we must | 241 // Special code for typeof expressions: Unfortunately, we must |
| 232 // be careful when loading the expression in 'typeof' | 242 // be careful when loading the expression in 'typeof' |
| 233 // expressions. We are not allowed to throw reference errors for | 243 // expressions. We are not allowed to throw reference errors for |
| 234 // non-existing properties of the global object, so we must make it | 244 // non-existing properties of the global object, so we must make it |
| 235 // look like an explicit property access, instead of an access | 245 // look like an explicit property access, instead of an access |
| 236 // through the context chain. | 246 // through the context chain. |
| 237 void LoadTypeofExpression(Expression* x); | 247 void LoadTypeofExpression(Expression* x); |
| 238 | 248 |
| 239 // References | 249 // References |
| 240 void AccessReference(Reference* ref, CodeGenState::AccessType access); | |
| 241 | 250 |
| 242 void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); } | 251 // Generate code to fetch the value of a reference. The reference is |
| 243 void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); } | 252 // expected to be on top of the expression stack. It is left in place and |
| 253 // its value is pushed on top of it. | |
| 254 void GetValue(Reference* ref); | |
| 255 | |
| 256 // Generate code to store a value in a reference. The stored value is | |
| 257 // expected on top of the expression stack, with the reference immediately | |
| 258 // below it. The expression stack is left unchanged. | |
| 259 void SetValue(Reference* ref) { | |
| 260 ASSERT(!has_cc()); | |
| 261 ASSERT(!ref->is_illegal()); | |
| 262 ref->expression()->GenerateStoreCode(masm_, scope_, ref, false); | |
| 263 } | |
| 264 | |
| 265 // Same as SetValue, used to set the initial value of a constant. | |
| 244 void InitConst(Reference* ref) { | 266 void InitConst(Reference* ref) { |
| 245 AccessReference(ref, CodeGenState::INIT_CONST); | 267 ASSERT(!has_cc()); |
| 268 ASSERT(!ref->is_illegal()); | |
| 269 ref->expression()->GenerateStoreCode(masm_, scope_, ref, true); | |
| 246 } | 270 } |
| 247 | 271 |
| 272 // Generate code to fetch a value from a property of a reference. The | |
| 273 // reference is expected on top of the expression stack. It is left in | |
| 274 // place and its value is pushed on top of it. | |
| 275 void GetReferenceProperty(Expression* key); | |
| 276 | |
| 277 // Generate code to store a value in a property of a reference. The | |
| 278 // stored value is expected on top of the expression stack, with the | |
| 279 // reference immediately below it. The expression stack is left | |
| 280 // unchanged. | |
| 281 static void SetReferenceProperty(MacroAssembler* masm, | |
| 282 Reference* ref, | |
| 283 Expression* key); | |
| 284 | |
| 248 void ToBoolean(Label* true_target, Label* false_target); | 285 void ToBoolean(Label* true_target, Label* false_target); |
| 249 | 286 |
| 250 | |
| 251 // Access property from the reference (must be at the TOS). | |
| 252 void AccessReferenceProperty(Expression* key, | |
| 253 CodeGenState::AccessType access); | |
| 254 | |
| 255 void GenericBinaryOperation( | 287 void GenericBinaryOperation( |
| 256 Token::Value op, | 288 Token::Value op, |
| 257 const OverwriteMode overwrite_mode = NO_OVERWRITE); | 289 const OverwriteMode overwrite_mode = NO_OVERWRITE); |
| 258 void Comparison(Condition cc, bool strict = false); | 290 void Comparison(Condition cc, bool strict = false); |
| 259 | 291 |
| 260 // Inline small integer literals. To prevent long attacker-controlled byte | 292 // Inline small integer literals. To prevent long attacker-controlled byte |
| 261 // sequences, we only inline small Smi:s. | 293 // sequences, we only inline small Smi:s. |
| 262 static const int kMaxSmiInlinedBits = 16; | 294 static const int kMaxSmiInlinedBits = 16; |
| 263 bool IsInlineSmi(Literal* literal); | 295 bool IsInlineSmi(Literal* literal); |
| 264 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); | 296 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 | 341 |
| 310 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | 342 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); |
| 311 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | 343 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); |
| 312 | 344 |
| 313 virtual void GenerateValueOf(ZoneList<Expression*>* args); | 345 virtual void GenerateValueOf(ZoneList<Expression*>* args); |
| 314 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | 346 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); |
| 315 | 347 |
| 316 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | 348 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); |
| 317 | 349 |
| 318 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | 350 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
| 351 | |
| 352 friend class Reference; | |
| 353 friend class Property; | |
| 354 friend class VariableProxy; | |
| 355 friend class Slot; | |
| 319 }; | 356 }; |
| 320 | 357 |
| 321 | 358 |
| 322 // ----------------------------------------------------------------------------- | 359 // ----------------------------------------------------------------------------- |
| 323 // Ia32CodeGenerator implementation | 360 // Ia32CodeGenerator implementation |
| 324 | 361 |
| 325 #define __ masm_-> | 362 #define __ masm_-> |
| 326 | 363 |
| 327 | 364 |
| 328 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, | 365 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 state_ = NULL; | 663 state_ = NULL; |
| 627 } | 664 } |
| 628 | 665 |
| 629 // Code generation state must be reset. | 666 // Code generation state must be reset. |
| 630 scope_ = NULL; | 667 scope_ = NULL; |
| 631 ASSERT(!has_cc()); | 668 ASSERT(!has_cc()); |
| 632 ASSERT(state_ == NULL); | 669 ASSERT(state_ == NULL); |
| 633 } | 670 } |
| 634 | 671 |
| 635 | 672 |
| 636 Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 673 Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, |
| 674 Scope* scope, | |
| 675 Slot* slot, | |
| 676 Register tmp) { | |
| 637 // Currently, this assertion will fail if we try to assign to | 677 // Currently, this assertion will fail if we try to assign to |
| 638 // a constant variable that is constant because it is read-only | 678 // a constant variable that is constant because it is read-only |
| 639 // (such as the variable referring to a named function expression). | 679 // (such as the variable referring to a named function expression). |
| 640 // We need to implement assignments to read-only variables. | 680 // We need to implement assignments to read-only variables. |
| 641 // Ideally, we should do this during AST generation (by converting | 681 // Ideally, we should do this during AST generation (by converting |
| 642 // such assignments into expression statements); however, in general | 682 // such assignments into expression statements); however, in general |
| 643 // we may not be able to make the decision until past AST generation, | 683 // we may not be able to make the decision until past AST generation, |
| 644 // that is when the entire program is known. | 684 // that is when the entire program is known. |
| 645 ASSERT(slot != NULL); | 685 ASSERT(slot != NULL); |
| 646 int index = slot->index(); | 686 int index = slot->index(); |
| 647 switch (slot->type()) { | 687 switch (slot->type()) { |
| 648 case Slot::PARAMETER: return ParameterOperand(index); | 688 case Slot::PARAMETER: return ParameterOperand(scope, index); |
| 649 | 689 |
| 650 case Slot::LOCAL: { | 690 case Slot::LOCAL: { |
| 651 ASSERT(0 <= index && index < scope_->num_stack_slots()); | 691 ASSERT(0 <= index && index < scope->num_stack_slots()); |
| 652 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; | 692 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; |
| 653 return Operand(ebp, kLocal0Offset - index * kPointerSize); | 693 return Operand(ebp, kLocal0Offset - index * kPointerSize); |
| 654 } | 694 } |
| 655 | 695 |
| 656 case Slot::CONTEXT: { | 696 case Slot::CONTEXT: { |
| 657 // Follow the context chain if necessary. | 697 // Follow the context chain if necessary. |
| 658 ASSERT(!tmp.is(esi)); // do not overwrite context register | 698 ASSERT(!tmp.is(esi)); // do not overwrite context register |
| 659 Register context = esi; | 699 Register context = esi; |
| 660 int chain_length = scope_->ContextChainLength(slot->var()->scope()); | 700 int chain_length = scope->ContextChainLength(slot->var()->scope()); |
| 661 for (int i = chain_length; i-- > 0;) { | 701 for (int i = chain_length; i-- > 0;) { |
| 662 // Load the closure. | 702 // Load the closure. |
| 663 // (All contexts, even 'with' contexts, have a closure, | 703 // (All contexts, even 'with' contexts, have a closure, |
| 664 // and it is the same for all contexts inside a function. | 704 // and it is the same for all contexts inside a function. |
| 665 // There is no need to go to the function context first.) | 705 // There is no need to go to the function context first.) |
| 666 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 706 masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 667 // Load the function context (which is the incoming, outer context). | 707 // Load the function context (which is the incoming, outer context). |
| 668 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); | 708 masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
| 669 context = tmp; | 709 context = tmp; |
| 670 } | 710 } |
| 671 // We may have a 'with' context now. Get the function context. | 711 // We may have a 'with' context now. Get the function context. |
| 672 // (In fact this mov may never be the needed, since the scope analysis | 712 // (In fact this mov may never be the needed, since the scope analysis |
| 673 // may not permit a direct context access in this case and thus we are | 713 // may not permit a direct context access in this case and thus we are |
| 674 // always at a function context. However it is safe to dereference be- | 714 // always at a function context. However it is safe to dereference be- |
| 675 // cause the function context of a function context is itself. Before | 715 // cause the function context of a function context is itself. Before |
| 676 // deleting this mov we should try to create a counter-example first, | 716 // deleting this mov we should try to create a counter-example first, |
| 677 // though...) | 717 // though...) |
| 678 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 718 masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 679 return ContextOperand(tmp, index); | 719 return ContextOperand(tmp, index); |
| 680 } | 720 } |
| 681 | 721 |
| 682 default: | 722 default: |
| 683 UNREACHABLE(); | 723 UNREACHABLE(); |
| 684 return Operand(eax); | 724 return Operand(eax); |
| 685 } | 725 } |
| 686 } | 726 } |
| 687 | 727 |
| 688 | 728 |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 845 __ pop(eax); | 885 __ pop(eax); |
| 846 __ mov(TOS, eax); | 886 __ mov(TOS, eax); |
| 847 } else { | 887 } else { |
| 848 __ pop(eax); | 888 __ pop(eax); |
| 849 __ add(Operand(esp), Immediate(size * kPointerSize)); | 889 __ add(Operand(esp), Immediate(size * kPointerSize)); |
| 850 __ push(eax); | 890 __ push(eax); |
| 851 } | 891 } |
| 852 } | 892 } |
| 853 | 893 |
| 854 | 894 |
| 855 void Ia32CodeGenerator::AccessReference(Reference* ref, | 895 void Ia32CodeGenerator::GetValue(Reference* ref) { |
| 856 CodeGenState::AccessType access) { | |
| 857 ASSERT(!has_cc()); | 896 ASSERT(!has_cc()); |
| 858 ASSERT(ref->type() != Reference::ILLEGAL); | 897 ASSERT(ref->type() != Reference::ILLEGAL); |
| 859 CodeGenState* old_state = state_; | 898 CodeGenState* old_state = state_; |
| 860 CodeGenState new_state(access, ref, true_target(), false_target()); | 899 CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), |
| 900 false_target()); | |
| 861 state_ = &new_state; | 901 state_ = &new_state; |
| 862 Visit(ref->expression()); | 902 Visit(ref->expression()); |
| 863 state_ = old_state; | 903 state_ = old_state; |
| 864 } | 904 } |
| 865 | 905 |
| 866 | 906 |
| 907 void Property::GenerateStoreCode(MacroAssembler* masm, | |
| 908 Scope* scope, | |
| 909 Reference* ref, | |
| 910 bool is_const_init) { | |
| 911 Comment cmnt(masm, "[ Store to Property"); | |
| 912 masm->RecordPosition(position()); | |
| 913 Ia32CodeGenerator::SetReferenceProperty(masm, ref, key()); | |
| 914 } | |
| 915 | |
| 916 | |
| 917 void VariableProxy::GenerateStoreCode(MacroAssembler* masm, | |
| 918 Scope* scope, | |
| 919 Reference* ref, | |
| 920 bool is_const_init) { | |
| 921 | |
| 922 Comment cmnt(masm, "[ Store to VariableProxy"); | |
| 923 Variable* node = var(); | |
| 924 | |
| 925 Expression* expr = node->rewrite(); | |
| 926 if (expr != NULL) { | |
| 927 expr->GenerateStoreCode(masm, scope, ref, is_const_init); | |
| 928 } else { | |
| 929 ASSERT(node->is_global()); | |
| 930 if (node->AsProperty() != NULL) { | |
| 931 masm->RecordPosition(node->AsProperty()->position()); | |
| 932 } | |
| 933 Ia32CodeGenerator::SetReferenceProperty(masm, ref, | |
| 934 new Literal(node->name())); | |
| 935 } | |
| 936 } | |
| 937 | |
| 938 | |
| 939 void Slot::GenerateStoreCode(MacroAssembler* masm, | |
| 940 Scope* scope, | |
| 941 Reference* ref, | |
| 942 bool is_const_init) { | |
| 943 Comment cmnt(masm, "[ Store to Slot"); | |
| 944 | |
| 945 if (type() == Slot::LOOKUP) { | |
| 946 ASSERT(var()->mode() == Variable::DYNAMIC); | |
| 947 | |
| 948 // For now, just do a runtime call. | |
| 949 masm->push(Operand(esi)); | |
| 950 masm->push(Immediate(var()->name())); | |
| 951 | |
| 952 if (is_const_init) { | |
| 953 // Same as the case for a normal store, but ignores attribute | |
| 954 // (e.g. READ_ONLY) of context slot so that we can initialize const | |
| 955 // properties (introduced via eval("const foo = (some expr);")). Also, | |
| 956 // uses the current function context instead of the top context. | |
| 957 // | |
| 958 // Note that we must declare the foo upon entry of eval(), via a | |
| 959 // context slot declaration, but we cannot initialize it at the same | |
| 960 // time, because the const declaration may be at the end of the eval | |
| 961 // code (sigh...) and the const variable may have been used before | |
| 962 // (where its value is 'undefined'). Thus, we can only do the | |
| 963 // initialization when we actually encounter the expression and when | |
| 964 // the expression operands are defined and valid, and thus we need the | |
| 965 // split into 2 operations: declaration of the context slot followed | |
| 966 // by initialization. | |
| 967 masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 968 } else { | |
| 969 masm->CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 970 } | |
| 971 // Storing a variable must keep the (new) value on the expression | |
| 972 // stack. This is necessary for compiling assignment expressions. | |
| 973 masm->push(eax); | |
| 974 | |
| 975 } else { | |
| 976 ASSERT(var()->mode() != Variable::DYNAMIC); | |
| 977 | |
| 978 Label exit; | |
| 979 if (is_const_init) { | |
| 980 ASSERT(var()->mode() == Variable::CONST); | |
| 981 // Only the first const initialization must be executed (the slot | |
| 982 // still contains 'the hole' value). When the assignment is executed, | |
| 983 // the code is identical to a normal store (see below). | |
| 984 Comment cmnt(masm, "[ Init const"); | |
| 985 masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); | |
| 986 masm->cmp(eax, Factory::the_hole_value()); | |
| 987 masm->j(not_equal, &exit); | |
| 988 } | |
| 989 | |
| 990 // We must execute the store. | |
| 991 // Storing a variable must keep the (new) value on the stack. This is | |
| 992 // necessary for compiling assignment expressions. ecx may be loaded | |
| 993 // with context; used below in RecordWrite. | |
| 994 // | |
| 995 // Note: We will reach here even with node->var()->mode() == | |
| 996 // Variable::CONST because of const declarations which will initialize | |
| 997 // consts to 'the hole' value and by doing so, end up calling this | |
| 998 // code. | |
| 999 masm->pop(eax); | |
| 1000 masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); | |
| 1001 masm->push(eax); // RecordWrite may destroy the value in eax. | |
| 1002 if (type() == Slot::CONTEXT) { | |
| 1003 // ecx is loaded with context when calling SlotOperand above. | |
| 1004 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | |
| 1005 masm->RecordWrite(ecx, offset, eax, ebx); | |
| 1006 } | |
| 1007 masm->bind(&exit); | |
| 1008 } | |
| 1009 } | |
| 1010 | |
| 1011 | |
| 867 #undef __ | 1012 #undef __ |
| 868 #define __ masm-> | 1013 #define __ masm-> |
| 869 | 1014 |
| 870 class ToBooleanStub: public CodeStub { | 1015 class ToBooleanStub: public CodeStub { |
| 871 public: | 1016 public: |
| 872 ToBooleanStub() { } | 1017 ToBooleanStub() { } |
| 873 | 1018 |
| 874 void Generate(MacroAssembler* masm); | 1019 void Generate(MacroAssembler* masm); |
| 875 | 1020 |
| 876 private: | 1021 private: |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 984 ToBooleanStub stub; | 1129 ToBooleanStub stub; |
| 985 __ CallStub(&stub); | 1130 __ CallStub(&stub); |
| 986 // Convert result (eax) to condition code. | 1131 // Convert result (eax) to condition code. |
| 987 __ test(eax, Operand(eax)); | 1132 __ test(eax, Operand(eax)); |
| 988 | 1133 |
| 989 ASSERT(not_equal == not_zero); | 1134 ASSERT(not_equal == not_zero); |
| 990 cc_reg_ = not_equal; | 1135 cc_reg_ = not_equal; |
| 991 } | 1136 } |
| 992 | 1137 |
| 993 | 1138 |
| 994 void Ia32CodeGenerator::AccessReferenceProperty( | 1139 void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { |
| 995 Expression* key, | |
| 996 CodeGenState::AccessType access) { | |
| 997 Reference::Type type = ref()->type(); | 1140 Reference::Type type = ref()->type(); |
| 998 ASSERT(type != Reference::ILLEGAL); | 1141 ASSERT(!ref()->is_illegal()); |
|
iposva
2008/09/10 18:01:44
Same nit as on ARM: Don't you want to assert befor
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
| |
| 999 | 1142 |
| 1000 // TODO(1241834): Make sure that this is sufficient. If there is a chance | 1143 // TODO(1241834): Make sure that this it is safe to ignore the distinction |
| 1001 // that reference errors can be thrown below, we must distinguish | 1144 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance |
| 1002 // between the 2 kinds of loads (typeof expression loads must not | 1145 // that reference errors can be thrown below, we must distinguish between |
| 1003 // throw a reference error). | 1146 // the two kinds of loads (typeof expression loads must not throw a |
| 1004 bool is_load = (access == CodeGenState::LOAD || | 1147 // reference error). |
| 1005 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
| 1006 | |
| 1007 if (type == Reference::NAMED) { | 1148 if (type == Reference::NAMED) { |
| 1008 // Compute the name of the property. | 1149 // Compute the name of the property. |
| 1009 Literal* literal = key->AsLiteral(); | 1150 Literal* literal = key->AsLiteral(); |
| 1010 Handle<String> name(String::cast(*literal->handle())); | 1151 Handle<String> name(String::cast(*literal->handle())); |
| 1011 | 1152 |
| 1012 // Call the appropriate IC code. | 1153 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 1013 if (is_load) { | 1154 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| 1014 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1155 // Setup the name register. |
| 1015 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 1156 __ Set(ecx, Immediate(name)); |
| 1016 // Setup the name register. | 1157 if (var != NULL) { |
| 1017 __ Set(ecx, Immediate(name)); | 1158 ASSERT(var->is_global()); |
| 1018 if (var != NULL) { | 1159 __ call(ic, code_target_context); |
| 1019 ASSERT(var->is_global()); | |
| 1020 __ call(ic, code_target_context); | |
| 1021 } else { | |
| 1022 __ call(ic, code_target); | |
| 1023 } | |
| 1024 } else { | 1160 } else { |
| 1025 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
| 1026 // TODO(1222589): Make the IC grab the values from the stack. | |
| 1027 __ pop(eax); | |
| 1028 // Setup the name register. | |
| 1029 __ Set(ecx, Immediate(name)); | |
| 1030 __ call(ic, code_target); | 1161 __ call(ic, code_target); |
| 1031 } | 1162 } |
| 1032 } else { | 1163 } else { |
| 1033 // Access keyed property. | 1164 // Access keyed property. |
| 1034 ASSERT(type == Reference::KEYED); | 1165 ASSERT(type == Reference::KEYED); |
| 1035 | 1166 |
| 1036 if (is_load) { | 1167 // Call IC code. |
| 1037 // Call IC code. | 1168 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1038 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1169 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
| 1039 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 1170 if (var != NULL) { |
| 1040 if (var != NULL) { | 1171 ASSERT(var->is_global()); |
| 1041 ASSERT(var->is_global()); | 1172 __ call(ic, code_target_context); |
| 1042 __ call(ic, code_target_context); | |
| 1043 } else { | |
| 1044 __ call(ic, code_target); | |
| 1045 } | |
| 1046 } else { | 1173 } else { |
| 1047 // Call IC code. | |
| 1048 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | |
| 1049 // TODO(1222589): Make the IC grab the values from the stack. | |
| 1050 __ pop(eax); | |
| 1051 __ call(ic, code_target); | 1174 __ call(ic, code_target); |
| 1052 } | 1175 } |
| 1053 } | 1176 } |
| 1054 __ push(eax); // IC call leaves result in eax, push it out | 1177 __ push(eax); // IC call leaves result in eax, push it out |
| 1055 } | 1178 } |
| 1056 | 1179 |
| 1057 | 1180 |
| 1181 void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm, | |
| 1182 Reference* ref, | |
| 1183 Expression* key) { | |
| 1184 Reference::Type type = ref->type(); | |
| 1185 ASSERT(!ref->is_illegal()); | |
| 1186 | |
| 1187 if (type == Reference::NAMED) { | |
| 1188 // Compute the name of the property. | |
| 1189 Literal* literal = key->AsLiteral(); | |
| 1190 Handle<String> name(String::cast(*literal->handle())); | |
| 1191 | |
| 1192 // Call the appropriate IC code. | |
| 1193 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
| 1194 // TODO(1222589): Make the IC grab the values from the stack. | |
| 1195 masm->pop(eax); | |
| 1196 // Setup the name register. | |
| 1197 masm->Set(ecx, Immediate(name)); | |
| 1198 masm->call(ic, code_target); | |
| 1199 } else { | |
| 1200 // Access keyed property. | |
| 1201 ASSERT(type == Reference::KEYED); | |
| 1202 | |
| 1203 // Call IC code. | |
| 1204 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | |
| 1205 // TODO(1222589): Make the IC grab the values from the stack. | |
| 1206 masm->pop(eax); | |
| 1207 masm->call(ic, code_target); | |
| 1208 } | |
| 1209 masm->push(eax); // IC call leaves result in eax, push it out | |
| 1210 } | |
| 1211 | |
| 1212 | |
| 1058 #undef __ | 1213 #undef __ |
| 1059 #define __ masm-> | 1214 #define __ masm-> |
| 1060 | 1215 |
| 1061 | 1216 |
| 1062 class FloatingPointHelper : public AllStatic { | 1217 class FloatingPointHelper : public AllStatic { |
| 1063 public: | 1218 public: |
| 1064 // Code pattern for loading floating point values. Input values must | 1219 // Code pattern for loading floating point values. Input values must |
| 1065 // be either smi or heap number objects (fp values). Requirements: | 1220 // be either smi or heap number objects (fp values). Requirements: |
| 1066 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 1221 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
| 1067 // floating point numbers on FPU stack. | 1222 // floating point numbers on FPU stack. |
| (...skipping 2250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3318 __ bind(&then); | 3473 __ bind(&then); |
| 3319 Load(node->then_expression(), access()); | 3474 Load(node->then_expression(), access()); |
| 3320 __ jmp(&exit); | 3475 __ jmp(&exit); |
| 3321 __ bind(&else_); | 3476 __ bind(&else_); |
| 3322 Load(node->else_expression(), access()); | 3477 Load(node->else_expression(), access()); |
| 3323 __ bind(&exit); | 3478 __ bind(&exit); |
| 3324 } | 3479 } |
| 3325 | 3480 |
| 3326 | 3481 |
| 3327 void Ia32CodeGenerator::VisitSlot(Slot* node) { | 3482 void Ia32CodeGenerator::VisitSlot(Slot* node) { |
| 3483 ASSERT(access() != CodeGenState::UNDEFINED); | |
| 3328 Comment cmnt(masm_, "[ Slot"); | 3484 Comment cmnt(masm_, "[ Slot"); |
| 3329 | 3485 |
| 3330 if (node->type() == Slot::LOOKUP) { | 3486 if (node->type() == Slot::LOOKUP) { |
| 3331 ASSERT(node->var()->mode() == Variable::DYNAMIC); | 3487 ASSERT(node->var()->mode() == Variable::DYNAMIC); |
| 3332 | 3488 |
| 3333 // For now, just do a runtime call. | 3489 // For now, just do a runtime call. |
| 3334 __ push(Operand(esi)); | 3490 __ push(Operand(esi)); |
| 3335 __ push(Immediate(node->var()->name())); | 3491 __ push(Immediate(node->var()->name())); |
| 3336 | 3492 |
| 3337 switch (access()) { | 3493 if (access() == CodeGenState::LOAD) { |
| 3338 case CodeGenState::UNDEFINED: | 3494 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 3339 UNREACHABLE(); | 3495 } else { |
| 3340 break; | 3496 // CodeGenState::LOAD_TYPEOF_EXPR. |
|
iposva
2008/09/10 18:01:44
Same comment as on ARM: Please assert that the Cod
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
| |
| 3341 | 3497 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3342 case CodeGenState::LOAD: | |
| 3343 __ CallRuntime(Runtime::kLoadContextSlot, 2); | |
| 3344 __ push(eax); | |
| 3345 // result (TOS) is the value that was loaded | |
| 3346 break; | |
| 3347 | |
| 3348 case CodeGenState::LOAD_TYPEOF_EXPR: | |
| 3349 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
| 3350 __ push(eax); | |
| 3351 // result (TOS) is the value that was loaded | |
| 3352 break; | |
| 3353 | |
| 3354 case CodeGenState::STORE: | |
| 3355 // Storing a variable must keep the (new) value on the | |
| 3356 // stack. This is necessary for compiling assignment | |
| 3357 // expressions. | |
| 3358 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 3359 __ push(eax); | |
| 3360 // result (TOS) is the value that was stored | |
| 3361 break; | |
| 3362 | |
| 3363 case CodeGenState::INIT_CONST: | |
| 3364 // Same as STORE but ignores attribute (e.g. READ_ONLY) of | |
| 3365 // context slot so that we can initialize const properties | |
| 3366 // (introduced via eval("const foo = (some expr);")). Also, | |
| 3367 // uses the current function context instead of the top | |
| 3368 // context. | |
| 3369 // | |
| 3370 // Note that we must declare the foo upon entry of eval(), | |
| 3371 // via a context slot declaration, but we cannot initialize | |
| 3372 // it at the same time, because the const declaration may | |
| 3373 // be at the end of the eval code (sigh...) and the const | |
| 3374 // variable may have been used before (where its value is | |
| 3375 // 'undefined'). Thus, we can only do the initialization | |
| 3376 // when we actually encounter the expression and when the | |
| 3377 // expression operands are defined and valid, and thus we | |
| 3378 // need the split into 2 operations: declaration of the | |
| 3379 // context slot followed by initialization. | |
| 3380 // | |
| 3381 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 3382 __ push(eax); | |
| 3383 break; | |
| 3384 } | 3498 } |
| 3499 __ push(eax); | |
| 3385 | 3500 |
| 3386 } else { | 3501 } else { |
| 3387 // Note: We would like to keep the assert below, but it fires because | 3502 // Note: We would like to keep the assert below, but it fires because of |
| 3388 // of some nasty code in LoadTypeofExpression() which should be removed... | 3503 // some nasty code in LoadTypeofExpression() which should be removed... |
| 3389 // ASSERT(node->var()->mode() != Variable::DYNAMIC); | 3504 // ASSERT(node->var()->mode() != Variable::DYNAMIC); |
| 3390 | 3505 |
| 3391 switch (access()) { | 3506 if (node->var()->mode() == Variable::CONST) { |
| 3392 case CodeGenState::UNDEFINED: | 3507 // Const slots may contain 'the hole' value (the constant hasn't been |
| 3393 UNREACHABLE(); | 3508 // initialized yet) which needs to be converted into the 'undefined' |
| 3394 break; | 3509 // value. |
| 3395 | 3510 Comment cmnt(masm_, "[ Load const"); |
| 3396 case CodeGenState::LOAD: // fall through | 3511 Label L; |
| 3397 case CodeGenState::LOAD_TYPEOF_EXPR: | 3512 __ mov(eax, SlotOperand(node, ecx)); |
| 3398 if (node->var()->mode() == Variable::CONST) { | 3513 __ cmp(eax, Factory::the_hole_value()); |
| 3399 // Const slots may contain 'the hole' value (the constant hasn't | 3514 __ j(not_equal, &L); |
| 3400 // been initialized yet) which needs to be converted into the | 3515 __ mov(eax, Factory::undefined_value()); |
| 3401 // 'undefined' value. | 3516 __ bind(&L); |
| 3402 Comment cmnt(masm_, "[ Load const"); | 3517 __ push(eax); |
| 3403 Label L; | 3518 } else { |
| 3404 __ mov(eax, SlotOperand(node, ecx)); | 3519 __ push(SlotOperand(node, ecx)); |
| 3405 __ cmp(eax, Factory::the_hole_value()); | |
| 3406 __ j(not_equal, &L); | |
| 3407 __ mov(eax, Factory::undefined_value()); | |
| 3408 __ bind(&L); | |
| 3409 __ push(eax); | |
| 3410 } else { | |
| 3411 __ push(SlotOperand(node, ecx)); | |
| 3412 } | |
| 3413 break; | |
| 3414 | |
| 3415 case CodeGenState::INIT_CONST: | |
| 3416 ASSERT(node->var()->mode() == Variable::CONST); | |
| 3417 // Only the first const initialization must be executed (the slot | |
| 3418 // still contains 'the hole' value). When the assignment is executed, | |
| 3419 // the code is identical to a normal store (see below). | |
| 3420 { Comment cmnt(masm_, "[ Init const"); | |
| 3421 Label L; | |
| 3422 __ mov(eax, SlotOperand(node, ecx)); | |
| 3423 __ cmp(eax, Factory::the_hole_value()); | |
| 3424 __ j(not_equal, &L); | |
| 3425 // We must execute the store. | |
| 3426 __ mov(eax, TOS); | |
| 3427 __ mov(SlotOperand(node, ecx), eax); | |
| 3428 if (node->type() == Slot::CONTEXT) { | |
| 3429 // ecx is loaded with context when calling SlotOperand above. | |
| 3430 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
| 3431 __ RecordWrite(ecx, offset, eax, ebx); | |
| 3432 } | |
| 3433 __ bind(&L); | |
| 3434 } | |
| 3435 break; | |
| 3436 | |
| 3437 case CodeGenState::STORE: | |
| 3438 // Storing a variable must keep the (new) value on the stack. This | |
| 3439 // is necessary for compiling assignment expressions. | |
| 3440 // ecx may be loaded with context; used below in RecordWrite. | |
| 3441 // | |
| 3442 // Note: We will reach here even with node->var()->mode() == | |
| 3443 // Variable::CONST because of const declarations which will | |
| 3444 // initialize consts to 'the hole' value and by doing so, end | |
| 3445 // up calling this code. | |
| 3446 __ pop(eax); | |
| 3447 __ mov(SlotOperand(node, ecx), eax); | |
| 3448 __ push(eax); // RecordWrite may destroy the value in eax. | |
| 3449 if (node->type() == Slot::CONTEXT) { | |
| 3450 // ecx is loaded with context when calling SlotOperand above. | |
| 3451 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
| 3452 __ RecordWrite(ecx, offset, eax, ebx); | |
| 3453 } | |
| 3454 break; | |
| 3455 } | 3520 } |
| 3456 } | 3521 } |
| 3457 } | 3522 } |
| 3458 | 3523 |
| 3459 | 3524 |
| 3460 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) { | 3525 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 3461 Comment cmnt(masm_, "[ VariableProxy"); | 3526 Comment cmnt(masm_, "[ VariableProxy"); |
| 3462 Variable* node = proxy_node->var(); | 3527 Variable* var_node = node->var(); |
| 3463 | 3528 |
| 3464 Expression* x = node->rewrite(); | 3529 Expression* expr = var_node->rewrite(); |
| 3465 if (x != NULL) { | 3530 if (expr != NULL) { |
| 3466 Visit(x); | 3531 Visit(expr); |
| 3467 return; | 3532 } else { |
| 3468 } | 3533 ASSERT(var_node->is_global()); |
| 3469 | 3534 if (is_referenced()) { |
| 3470 ASSERT(node->is_global()); | 3535 if (var_node->AsProperty() != NULL) { |
| 3471 if (is_referenced()) { | 3536 __ RecordPosition(var_node->AsProperty()->position()); |
| 3472 if (node->AsProperty() != NULL) { | 3537 } |
| 3473 __ RecordPosition(node->AsProperty()->position()); | 3538 GetReferenceProperty(new Literal(var_node->name())); |
| 3539 } else { | |
| 3540 Reference property(this, node); | |
| 3541 GetValue(&property); | |
| 3474 } | 3542 } |
| 3475 AccessReferenceProperty(new Literal(node->name()), access()); | |
| 3476 | |
| 3477 } else { | |
| 3478 // All stores are through references. | |
| 3479 ASSERT(access() != CodeGenState::STORE); | |
| 3480 Reference property(this, proxy_node); | |
| 3481 GetValue(&property); | |
| 3482 } | 3543 } |
| 3483 } | 3544 } |
| 3484 | 3545 |
| 3485 | 3546 |
| 3486 void Ia32CodeGenerator::VisitLiteral(Literal* node) { | 3547 void Ia32CodeGenerator::VisitLiteral(Literal* node) { |
| 3487 Comment cmnt(masm_, "[ Literal"); | 3548 Comment cmnt(masm_, "[ Literal"); |
| 3488 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 3549 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 3489 // To prevent long attacker-controlled byte sequences in code, larger | 3550 // To prevent long attacker-controlled byte sequences in code, larger |
| 3490 // Smis are loaded in two steps. | 3551 // Smis are loaded in two steps. |
| 3491 int bits = reinterpret_cast<int>(*node->handle()); | 3552 int bits = reinterpret_cast<int>(*node->handle()); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3777 __ CallRuntime(Runtime::kThrow, 1); | 3838 __ CallRuntime(Runtime::kThrow, 1); |
| 3778 __ push(eax); | 3839 __ push(eax); |
| 3779 } | 3840 } |
| 3780 | 3841 |
| 3781 | 3842 |
| 3782 void Ia32CodeGenerator::VisitProperty(Property* node) { | 3843 void Ia32CodeGenerator::VisitProperty(Property* node) { |
| 3783 Comment cmnt(masm_, "[ Property"); | 3844 Comment cmnt(masm_, "[ Property"); |
| 3784 | 3845 |
| 3785 if (is_referenced()) { | 3846 if (is_referenced()) { |
| 3786 __ RecordPosition(node->position()); | 3847 __ RecordPosition(node->position()); |
| 3787 AccessReferenceProperty(node->key(), access()); | 3848 GetReferenceProperty(node->key()); |
| 3788 } else { | 3849 } else { |
| 3789 // All stores are through references. | |
| 3790 ASSERT(access() != CodeGenState::STORE); | |
| 3791 Reference property(this, node); | 3850 Reference property(this, node); |
| 3792 __ RecordPosition(node->position()); | 3851 __ RecordPosition(node->position()); |
| 3793 GetValue(&property); | 3852 GetValue(&property); |
| 3794 } | 3853 } |
| 3795 } | 3854 } |
| 3796 | 3855 |
| 3797 | 3856 |
| 3798 void Ia32CodeGenerator::VisitCall(Call* node) { | 3857 void Ia32CodeGenerator::VisitCall(Call* node) { |
| 3799 Comment cmnt(masm_, "[ Call"); | 3858 Comment cmnt(masm_, "[ Call"); |
| 3800 | 3859 |
| (...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5386 bool is_eval) { | 5445 bool is_eval) { |
| 5387 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | 5446 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); |
| 5388 if (!code.is_null()) { | 5447 if (!code.is_null()) { |
| 5389 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 5448 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
| 5390 } | 5449 } |
| 5391 return code; | 5450 return code; |
| 5392 } | 5451 } |
| 5393 | 5452 |
| 5394 | 5453 |
| 5395 } } // namespace v8::internal | 5454 } } // namespace v8::internal |
| OLD | NEW |