OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_MIPS | 5 #if V8_TARGET_ARCH_MIPS |
6 | 6 |
7 // Note on Mips implementation: | 7 // Note on Mips implementation: |
8 // | 8 // |
9 // The result_register() for mips is the 'v0' register, which is defined | 9 // The result_register() for mips is the 'v0' register, which is defined |
10 // by the ABI to contain function return values. However, the first | 10 // by the ABI to contain function return values. However, the first |
(...skipping 1145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS); | 1156 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS); |
1157 __ bind(&exit); | 1157 __ bind(&exit); |
1158 decrement_loop_depth(); | 1158 decrement_loop_depth(); |
1159 } | 1159 } |
1160 | 1160 |
1161 | 1161 |
1162 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, | 1162 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, |
1163 FeedbackVectorSlot slot) { | 1163 FeedbackVectorSlot slot) { |
1164 DCHECK(NeedsHomeObject(initializer)); | 1164 DCHECK(NeedsHomeObject(initializer)); |
1165 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); | 1165 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); |
| 1166 __ li(StoreDescriptor::NameRegister(), |
| 1167 Operand(isolate()->factory()->home_object_symbol())); |
1166 __ lw(StoreDescriptor::ValueRegister(), | 1168 __ lw(StoreDescriptor::ValueRegister(), |
1167 MemOperand(sp, offset * kPointerSize)); | 1169 MemOperand(sp, offset * kPointerSize)); |
1168 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1170 EmitLoadStoreICSlot(slot); |
| 1171 CallStoreIC(); |
1169 } | 1172 } |
1170 | 1173 |
1171 | 1174 |
1172 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, | 1175 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, |
1173 int offset, | 1176 int offset, |
1174 FeedbackVectorSlot slot) { | 1177 FeedbackVectorSlot slot) { |
1175 DCHECK(NeedsHomeObject(initializer)); | 1178 DCHECK(NeedsHomeObject(initializer)); |
1176 __ Move(StoreDescriptor::ReceiverRegister(), v0); | 1179 __ Move(StoreDescriptor::ReceiverRegister(), v0); |
| 1180 __ li(StoreDescriptor::NameRegister(), |
| 1181 Operand(isolate()->factory()->home_object_symbol())); |
1177 __ lw(StoreDescriptor::ValueRegister(), | 1182 __ lw(StoreDescriptor::ValueRegister(), |
1178 MemOperand(sp, offset * kPointerSize)); | 1183 MemOperand(sp, offset * kPointerSize)); |
1179 CallStoreIC(slot, isolate()->factory()->home_object_symbol()); | 1184 EmitLoadStoreICSlot(slot); |
| 1185 CallStoreIC(); |
1180 } | 1186 } |
1181 | 1187 |
1182 | 1188 |
1183 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | 1189 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, |
1184 TypeofMode typeof_mode, | 1190 TypeofMode typeof_mode, |
1185 Label* slow) { | 1191 Label* slow) { |
1186 Register current = cp; | 1192 Register current = cp; |
1187 Register next = a1; | 1193 Register next = a1; |
1188 Register temp = a2; | 1194 Register temp = a2; |
1189 | 1195 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1406 // Fall through. | 1412 // Fall through. |
1407 case ObjectLiteral::Property::COMPUTED: | 1413 case ObjectLiteral::Property::COMPUTED: |
1408 // It is safe to use [[Put]] here because the boilerplate already | 1414 // It is safe to use [[Put]] here because the boilerplate already |
1409 // contains computed properties with an uninitialized value. | 1415 // contains computed properties with an uninitialized value. |
1410 if (key->IsStringLiteral()) { | 1416 if (key->IsStringLiteral()) { |
1411 DCHECK(key->IsPropertyName()); | 1417 DCHECK(key->IsPropertyName()); |
1412 if (property->emit_store()) { | 1418 if (property->emit_store()) { |
1413 VisitForAccumulatorValue(value); | 1419 VisitForAccumulatorValue(value); |
1414 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 1420 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
1415 DCHECK(StoreDescriptor::ValueRegister().is(a0)); | 1421 DCHECK(StoreDescriptor::ValueRegister().is(a0)); |
| 1422 __ li(StoreDescriptor::NameRegister(), Operand(key->value())); |
1416 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); | 1423 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); |
1417 CallStoreIC(property->GetSlot(0), key->value()); | 1424 EmitLoadStoreICSlot(property->GetSlot(0)); |
| 1425 CallStoreIC(); |
1418 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); | 1426 PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS); |
1419 | 1427 |
1420 if (NeedsHomeObject(value)) { | 1428 if (NeedsHomeObject(value)) { |
1421 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); | 1429 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); |
1422 } | 1430 } |
1423 } else { | 1431 } else { |
1424 VisitForEffect(value); | 1432 VisitForEffect(value); |
1425 } | 1433 } |
1426 break; | 1434 break; |
1427 } | 1435 } |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1605 if (!result_saved) { | 1613 if (!result_saved) { |
1606 PushOperand(v0); // array literal | 1614 PushOperand(v0); // array literal |
1607 result_saved = true; | 1615 result_saved = true; |
1608 } | 1616 } |
1609 | 1617 |
1610 VisitForAccumulatorValue(subexpr); | 1618 VisitForAccumulatorValue(subexpr); |
1611 | 1619 |
1612 __ li(StoreDescriptor::NameRegister(), Operand(Smi::FromInt(array_index))); | 1620 __ li(StoreDescriptor::NameRegister(), Operand(Smi::FromInt(array_index))); |
1613 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0)); | 1621 __ lw(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0)); |
1614 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 1622 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
1615 CallKeyedStoreIC(expr->LiteralFeedbackSlot()); | 1623 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot()); |
| 1624 CallKeyedStoreIC(); |
1616 | 1625 |
1617 PrepareForBailoutForId(expr->GetIdForElement(array_index), | 1626 PrepareForBailoutForId(expr->GetIdForElement(array_index), |
1618 BailoutState::NO_REGISTERS); | 1627 BailoutState::NO_REGISTERS); |
1619 } | 1628 } |
1620 | 1629 |
1621 if (result_saved) { | 1630 if (result_saved) { |
1622 context()->PlugTOS(); | 1631 context()->PlugTOS(); |
1623 } else { | 1632 } else { |
1624 context()->Plug(v0); | 1633 context()->Plug(v0); |
1625 } | 1634 } |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2044 Variable* var = expr->AsVariableProxy()->var(); | 2053 Variable* var = expr->AsVariableProxy()->var(); |
2045 EffectContext context(this); | 2054 EffectContext context(this); |
2046 EmitVariableAssignment(var, Token::ASSIGN, slot); | 2055 EmitVariableAssignment(var, Token::ASSIGN, slot); |
2047 break; | 2056 break; |
2048 } | 2057 } |
2049 case NAMED_PROPERTY: { | 2058 case NAMED_PROPERTY: { |
2050 PushOperand(result_register()); // Preserve value. | 2059 PushOperand(result_register()); // Preserve value. |
2051 VisitForAccumulatorValue(prop->obj()); | 2060 VisitForAccumulatorValue(prop->obj()); |
2052 __ mov(StoreDescriptor::ReceiverRegister(), result_register()); | 2061 __ mov(StoreDescriptor::ReceiverRegister(), result_register()); |
2053 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. | 2062 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. |
2054 CallStoreIC(slot, prop->key()->AsLiteral()->value()); | 2063 __ li(StoreDescriptor::NameRegister(), |
| 2064 Operand(prop->key()->AsLiteral()->value())); |
| 2065 EmitLoadStoreICSlot(slot); |
| 2066 CallStoreIC(); |
2055 break; | 2067 break; |
2056 } | 2068 } |
2057 case NAMED_SUPER_PROPERTY: { | 2069 case NAMED_SUPER_PROPERTY: { |
2058 PushOperand(v0); | 2070 PushOperand(v0); |
2059 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); | 2071 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); |
2060 VisitForAccumulatorValue( | 2072 VisitForAccumulatorValue( |
2061 prop->obj()->AsSuperPropertyReference()->home_object()); | 2073 prop->obj()->AsSuperPropertyReference()->home_object()); |
2062 // stack: value, this; v0: home_object | 2074 // stack: value, this; v0: home_object |
2063 Register scratch = a2; | 2075 Register scratch = a2; |
2064 Register scratch2 = a3; | 2076 Register scratch2 = a3; |
(...skipping 26 matching lines...) Expand all Loading... |
2091 EmitKeyedSuperPropertyStore(prop); | 2103 EmitKeyedSuperPropertyStore(prop); |
2092 break; | 2104 break; |
2093 } | 2105 } |
2094 case KEYED_PROPERTY: { | 2106 case KEYED_PROPERTY: { |
2095 PushOperand(result_register()); // Preserve value. | 2107 PushOperand(result_register()); // Preserve value. |
2096 VisitForStackValue(prop->obj()); | 2108 VisitForStackValue(prop->obj()); |
2097 VisitForAccumulatorValue(prop->key()); | 2109 VisitForAccumulatorValue(prop->key()); |
2098 __ mov(StoreDescriptor::NameRegister(), result_register()); | 2110 __ mov(StoreDescriptor::NameRegister(), result_register()); |
2099 PopOperands(StoreDescriptor::ValueRegister(), | 2111 PopOperands(StoreDescriptor::ValueRegister(), |
2100 StoreDescriptor::ReceiverRegister()); | 2112 StoreDescriptor::ReceiverRegister()); |
2101 CallKeyedStoreIC(slot); | 2113 EmitLoadStoreICSlot(slot); |
| 2114 CallKeyedStoreIC(); |
2102 break; | 2115 break; |
2103 } | 2116 } |
2104 } | 2117 } |
2105 context()->Plug(v0); | 2118 context()->Plug(v0); |
2106 } | 2119 } |
2107 | 2120 |
2108 | 2121 |
2109 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2122 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2110 Variable* var, MemOperand location) { | 2123 Variable* var, MemOperand location) { |
2111 __ sw(result_register(), location); | 2124 __ sw(result_register(), location); |
2112 if (var->IsContextSlot()) { | 2125 if (var->IsContextSlot()) { |
2113 // RecordWrite may destroy all its register arguments. | 2126 // RecordWrite may destroy all its register arguments. |
2114 __ Move(a3, result_register()); | 2127 __ Move(a3, result_register()); |
2115 int offset = Context::SlotOffset(var->index()); | 2128 int offset = Context::SlotOffset(var->index()); |
2116 __ RecordWriteContextSlot( | 2129 __ RecordWriteContextSlot( |
2117 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | 2130 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
2118 } | 2131 } |
2119 } | 2132 } |
2120 | 2133 |
2121 | 2134 |
2122 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, | 2135 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, |
2123 FeedbackVectorSlot slot) { | 2136 FeedbackVectorSlot slot) { |
2124 if (var->IsUnallocated()) { | 2137 if (var->IsUnallocated()) { |
2125 // Global var, const, or let. | 2138 // Global var, const, or let. |
2126 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 2139 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
| 2140 __ li(StoreDescriptor::NameRegister(), Operand(var->name())); |
2127 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); | 2141 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); |
2128 CallStoreIC(slot, var->name()); | 2142 EmitLoadStoreICSlot(slot); |
| 2143 CallStoreIC(); |
2129 | 2144 |
2130 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { | 2145 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { |
2131 DCHECK(!var->IsLookupSlot()); | 2146 DCHECK(!var->IsLookupSlot()); |
2132 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2147 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2133 MemOperand location = VarOperand(var, a1); | 2148 MemOperand location = VarOperand(var, a1); |
2134 // Perform an initialization check for lexically declared variables. | 2149 // Perform an initialization check for lexically declared variables. |
2135 if (var->binding_needs_init()) { | 2150 if (var->binding_needs_init()) { |
2136 Label assign; | 2151 Label assign; |
2137 __ lw(a3, location); | 2152 __ lw(a3, location); |
2138 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2153 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2187 } | 2202 } |
2188 | 2203 |
2189 | 2204 |
2190 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2205 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
2191 // Assignment to a property, using a named store IC. | 2206 // Assignment to a property, using a named store IC. |
2192 Property* prop = expr->target()->AsProperty(); | 2207 Property* prop = expr->target()->AsProperty(); |
2193 DCHECK(prop != NULL); | 2208 DCHECK(prop != NULL); |
2194 DCHECK(prop->key()->IsLiteral()); | 2209 DCHECK(prop->key()->IsLiteral()); |
2195 | 2210 |
2196 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 2211 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
| 2212 __ li(StoreDescriptor::NameRegister(), |
| 2213 Operand(prop->key()->AsLiteral()->value())); |
2197 PopOperand(StoreDescriptor::ReceiverRegister()); | 2214 PopOperand(StoreDescriptor::ReceiverRegister()); |
2198 CallStoreIC(expr->AssignmentSlot(), prop->key()->AsLiteral()->value()); | 2215 EmitLoadStoreICSlot(expr->AssignmentSlot()); |
| 2216 CallStoreIC(); |
2199 | 2217 |
2200 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 2218 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
2201 context()->Plug(v0); | 2219 context()->Plug(v0); |
2202 } | 2220 } |
2203 | 2221 |
2204 | 2222 |
2205 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { | 2223 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { |
2206 // Assignment to named property of super. | 2224 // Assignment to named property of super. |
2207 // v0 : value | 2225 // v0 : value |
2208 // stack : receiver ('this'), home_object | 2226 // stack : receiver ('this'), home_object |
(...skipping 27 matching lines...) Expand all Loading... |
2236 // Call keyed store IC. | 2254 // Call keyed store IC. |
2237 // The arguments are: | 2255 // The arguments are: |
2238 // - a0 is the value, | 2256 // - a0 is the value, |
2239 // - a1 is the key, | 2257 // - a1 is the key, |
2240 // - a2 is the receiver. | 2258 // - a2 is the receiver. |
2241 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 2259 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
2242 PopOperands(StoreDescriptor::ReceiverRegister(), | 2260 PopOperands(StoreDescriptor::ReceiverRegister(), |
2243 StoreDescriptor::NameRegister()); | 2261 StoreDescriptor::NameRegister()); |
2244 DCHECK(StoreDescriptor::ValueRegister().is(a0)); | 2262 DCHECK(StoreDescriptor::ValueRegister().is(a0)); |
2245 | 2263 |
2246 CallKeyedStoreIC(expr->AssignmentSlot()); | 2264 EmitLoadStoreICSlot(expr->AssignmentSlot()); |
| 2265 CallKeyedStoreIC(); |
2247 | 2266 |
2248 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 2267 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
2249 context()->Plug(v0); | 2268 context()->Plug(v0); |
2250 } | 2269 } |
2251 | 2270 |
2252 | 2271 |
2253 void FullCodeGenerator::CallIC(Handle<Code> code, | 2272 void FullCodeGenerator::CallIC(Handle<Code> code, |
2254 TypeFeedbackId id) { | 2273 TypeFeedbackId id) { |
2255 ic_total_count_++; | 2274 ic_total_count_++; |
2256 __ Call(code, RelocInfo::CODE_TARGET, id); | 2275 __ Call(code, RelocInfo::CODE_TARGET, id); |
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3284 } else { | 3303 } else { |
3285 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3304 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3286 Token::ASSIGN, expr->CountSlot()); | 3305 Token::ASSIGN, expr->CountSlot()); |
3287 PrepareForBailoutForId(expr->AssignmentId(), | 3306 PrepareForBailoutForId(expr->AssignmentId(), |
3288 BailoutState::TOS_REGISTER); | 3307 BailoutState::TOS_REGISTER); |
3289 context()->Plug(v0); | 3308 context()->Plug(v0); |
3290 } | 3309 } |
3291 break; | 3310 break; |
3292 case NAMED_PROPERTY: { | 3311 case NAMED_PROPERTY: { |
3293 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 3312 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
| 3313 __ li(StoreDescriptor::NameRegister(), |
| 3314 Operand(prop->key()->AsLiteral()->value())); |
3294 PopOperand(StoreDescriptor::ReceiverRegister()); | 3315 PopOperand(StoreDescriptor::ReceiverRegister()); |
3295 CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); | 3316 EmitLoadStoreICSlot(expr->CountSlot()); |
| 3317 CallStoreIC(); |
3296 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 3318 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
3297 if (expr->is_postfix()) { | 3319 if (expr->is_postfix()) { |
3298 if (!context()->IsEffect()) { | 3320 if (!context()->IsEffect()) { |
3299 context()->PlugTOS(); | 3321 context()->PlugTOS(); |
3300 } | 3322 } |
3301 } else { | 3323 } else { |
3302 context()->Plug(v0); | 3324 context()->Plug(v0); |
3303 } | 3325 } |
3304 break; | 3326 break; |
3305 } | 3327 } |
(...skipping 18 matching lines...) Expand all Loading... |
3324 } | 3346 } |
3325 } else { | 3347 } else { |
3326 context()->Plug(v0); | 3348 context()->Plug(v0); |
3327 } | 3349 } |
3328 break; | 3350 break; |
3329 } | 3351 } |
3330 case KEYED_PROPERTY: { | 3352 case KEYED_PROPERTY: { |
3331 __ mov(StoreDescriptor::ValueRegister(), result_register()); | 3353 __ mov(StoreDescriptor::ValueRegister(), result_register()); |
3332 PopOperands(StoreDescriptor::ReceiverRegister(), | 3354 PopOperands(StoreDescriptor::ReceiverRegister(), |
3333 StoreDescriptor::NameRegister()); | 3355 StoreDescriptor::NameRegister()); |
3334 CallKeyedStoreIC(expr->CountSlot()); | 3356 EmitLoadStoreICSlot(expr->CountSlot()); |
| 3357 CallKeyedStoreIC(); |
3335 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); | 3358 PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); |
3336 if (expr->is_postfix()) { | 3359 if (expr->is_postfix()) { |
3337 if (!context()->IsEffect()) { | 3360 if (!context()->IsEffect()) { |
3338 context()->PlugTOS(); | 3361 context()->PlugTOS(); |
3339 } | 3362 } |
3340 } else { | 3363 } else { |
3341 context()->Plug(v0); | 3364 context()->Plug(v0); |
3342 } | 3365 } |
3343 break; | 3366 break; |
3344 } | 3367 } |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3709 reinterpret_cast<uint32_t>( | 3732 reinterpret_cast<uint32_t>( |
3710 isolate->builtins()->OnStackReplacement()->entry())); | 3733 isolate->builtins()->OnStackReplacement()->entry())); |
3711 return ON_STACK_REPLACEMENT; | 3734 return ON_STACK_REPLACEMENT; |
3712 } | 3735 } |
3713 | 3736 |
3714 | 3737 |
3715 } // namespace internal | 3738 } // namespace internal |
3716 } // namespace v8 | 3739 } // namespace v8 |
3717 | 3740 |
3718 #endif // V8_TARGET_ARCH_MIPS | 3741 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |