OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); | 256 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
257 frame_->CallStub(&stub, 3); | 257 frame_->CallStub(&stub, 3); |
258 frame_->EmitPush(r0); | 258 frame_->EmitPush(r0); |
259 arguments_ref.SetValue(NOT_CONST_INIT); | 259 arguments_ref.SetValue(NOT_CONST_INIT); |
260 } | 260 } |
261 shadow_ref.SetValue(NOT_CONST_INIT); | 261 shadow_ref.SetValue(NOT_CONST_INIT); |
262 } | 262 } |
263 frame_->Drop(); // Value is no longer needed. | 263 frame_->Drop(); // Value is no longer needed. |
264 } | 264 } |
265 | 265 |
| 266 // Initialize ThisFunction reference if present. |
| 267 if (scope_->is_function_scope() && scope_->function() != NULL) { |
| 268 __ mov(ip, Operand(Factory::the_hole_value())); |
| 269 frame_->EmitPush(ip); |
| 270 StoreToSlot(scope_->function()->slot(), NOT_CONST_INIT); |
| 271 } |
| 272 |
266 // Generate code to 'execute' declarations and initialize functions | 273 // Generate code to 'execute' declarations and initialize functions |
267 // (source elements). In case of an illegal redeclaration we need to | 274 // (source elements). In case of an illegal redeclaration we need to |
268 // handle that instead of processing the declarations. | 275 // handle that instead of processing the declarations. |
269 if (scope_->HasIllegalRedeclaration()) { | 276 if (scope_->HasIllegalRedeclaration()) { |
270 Comment cmnt(masm_, "[ illegal redeclarations"); | 277 Comment cmnt(masm_, "[ illegal redeclarations"); |
271 scope_->VisitIllegalRedeclaration(this); | 278 scope_->VisitIllegalRedeclaration(this); |
272 } else { | 279 } else { |
273 Comment cmnt(masm_, "[ declarations"); | 280 Comment cmnt(masm_, "[ declarations"); |
274 ProcessDeclarations(scope_->declarations()); | 281 ProcessDeclarations(scope_->declarations()); |
275 // Bail out if a stack-overflow exception occurred when processing | 282 // Bail out if a stack-overflow exception occurred when processing |
(...skipping 2163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2439 frame_->EmitPop(r0); | 2446 frame_->EmitPop(r0); |
2440 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2447 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
2441 __ cmp(r0, ip); | 2448 __ cmp(r0, ip); |
2442 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 2449 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
2443 frame_->EmitPush(r0); | 2450 frame_->EmitPush(r0); |
2444 } | 2451 } |
2445 } | 2452 } |
2446 } | 2453 } |
2447 | 2454 |
2448 | 2455 |
| 2456 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
| 2457 ASSERT(slot != NULL); |
| 2458 if (slot->type() == Slot::LOOKUP) { |
| 2459 ASSERT(slot->var()->is_dynamic()); |
| 2460 |
| 2461 // For now, just do a runtime call. |
| 2462 frame_->EmitPush(cp); |
| 2463 __ mov(r0, Operand(slot->var()->name())); |
| 2464 frame_->EmitPush(r0); |
| 2465 |
| 2466 if (init_state == CONST_INIT) { |
| 2467 // Same as the case for a normal store, but ignores attribute |
| 2468 // (e.g. READ_ONLY) of context slot so that we can initialize |
| 2469 // const properties (introduced via eval("const foo = (some |
| 2470 // expr);")). Also, uses the current function context instead of |
| 2471 // the top context. |
| 2472 // |
| 2473 // Note that we must declare the foo upon entry of eval(), via a |
| 2474 // context slot declaration, but we cannot initialize it at the |
| 2475 // same time, because the const declaration may be at the end of |
| 2476 // the eval code (sigh...) and the const variable may have been |
| 2477 // used before (where its value is 'undefined'). Thus, we can only |
| 2478 // do the initialization when we actually encounter the expression |
| 2479 // and when the expression operands are defined and valid, and |
| 2480 // thus we need the split into 2 operations: declaration of the |
| 2481 // context slot followed by initialization. |
| 2482 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2483 } else { |
| 2484 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 2485 } |
| 2486 // Storing a variable must keep the (new) value on the expression |
| 2487 // stack. This is necessary for compiling assignment expressions. |
| 2488 frame_->EmitPush(r0); |
| 2489 |
| 2490 } else { |
| 2491 ASSERT(!slot->var()->is_dynamic()); |
| 2492 |
| 2493 JumpTarget exit; |
| 2494 if (init_state == CONST_INIT) { |
| 2495 ASSERT(slot->var()->mode() == Variable::CONST); |
| 2496 // Only the first const initialization must be executed (the slot |
| 2497 // still contains 'the hole' value). When the assignment is |
| 2498 // executed, the code is identical to a normal store (see below). |
| 2499 Comment cmnt(masm_, "[ Init const"); |
| 2500 __ ldr(r2, SlotOperand(slot, r2)); |
| 2501 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 2502 __ cmp(r2, ip); |
| 2503 exit.Branch(ne); |
| 2504 } |
| 2505 |
| 2506 // We must execute the store. Storing a variable must keep the |
| 2507 // (new) value on the stack. This is necessary for compiling |
| 2508 // assignment expressions. |
| 2509 // |
| 2510 // Note: We will reach here even with slot->var()->mode() == |
| 2511 // Variable::CONST because of const declarations which will |
| 2512 // initialize consts to 'the hole' value and by doing so, end up |
| 2513 // calling this code. r2 may be loaded with context; used below in |
| 2514 // RecordWrite. |
| 2515 frame_->EmitPop(r0); |
| 2516 __ str(r0, SlotOperand(slot, r2)); |
| 2517 frame_->EmitPush(r0); |
| 2518 if (slot->type() == Slot::CONTEXT) { |
| 2519 // Skip write barrier if the written value is a smi. |
| 2520 __ tst(r0, Operand(kSmiTagMask)); |
| 2521 exit.Branch(eq); |
| 2522 // r2 is loaded with context when calling SlotOperand above. |
| 2523 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 2524 __ mov(r3, Operand(offset)); |
| 2525 __ RecordWrite(r2, r3, r1); |
| 2526 } |
| 2527 // If we definitely did not jump over the assignment, we do not need |
| 2528 // to bind the exit label. Doing so can defeat peephole |
| 2529 // optimization. |
| 2530 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
| 2531 exit.Bind(); |
| 2532 } |
| 2533 } |
| 2534 } |
| 2535 |
| 2536 |
2449 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, | 2537 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
2450 TypeofState typeof_state, | 2538 TypeofState typeof_state, |
2451 Register tmp, | 2539 Register tmp, |
2452 Register tmp2, | 2540 Register tmp2, |
2453 JumpTarget* slow) { | 2541 JumpTarget* slow) { |
2454 // Check that no extension objects have been created by calls to | 2542 // Check that no extension objects have been created by calls to |
2455 // eval from the current scope to the global scope. | 2543 // eval from the current scope to the global scope. |
2456 Register context = cp; | 2544 Register context = cp; |
2457 Scope* s = scope(); | 2545 Scope* s = scope(); |
2458 while (s != NULL) { | 2546 while (s != NULL) { |
(...skipping 1796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4255 VirtualFrame* frame = cgen_->frame(); | 4343 VirtualFrame* frame = cgen_->frame(); |
4256 Property* property = expression_->AsProperty(); | 4344 Property* property = expression_->AsProperty(); |
4257 if (property != NULL) { | 4345 if (property != NULL) { |
4258 cgen_->CodeForSourcePosition(property->position()); | 4346 cgen_->CodeForSourcePosition(property->position()); |
4259 } | 4347 } |
4260 | 4348 |
4261 switch (type_) { | 4349 switch (type_) { |
4262 case SLOT: { | 4350 case SLOT: { |
4263 Comment cmnt(masm, "[ Store to Slot"); | 4351 Comment cmnt(masm, "[ Store to Slot"); |
4264 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4352 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
4265 ASSERT(slot != NULL); | 4353 cgen_->StoreToSlot(slot, init_state); |
4266 if (slot->type() == Slot::LOOKUP) { | |
4267 ASSERT(slot->var()->is_dynamic()); | |
4268 | |
4269 // For now, just do a runtime call. | |
4270 frame->EmitPush(cp); | |
4271 __ mov(r0, Operand(slot->var()->name())); | |
4272 frame->EmitPush(r0); | |
4273 | |
4274 if (init_state == CONST_INIT) { | |
4275 // Same as the case for a normal store, but ignores attribute | |
4276 // (e.g. READ_ONLY) of context slot so that we can initialize | |
4277 // const properties (introduced via eval("const foo = (some | |
4278 // expr);")). Also, uses the current function context instead of | |
4279 // the top context. | |
4280 // | |
4281 // Note that we must declare the foo upon entry of eval(), via a | |
4282 // context slot declaration, but we cannot initialize it at the | |
4283 // same time, because the const declaration may be at the end of | |
4284 // the eval code (sigh...) and the const variable may have been | |
4285 // used before (where its value is 'undefined'). Thus, we can only | |
4286 // do the initialization when we actually encounter the expression | |
4287 // and when the expression operands are defined and valid, and | |
4288 // thus we need the split into 2 operations: declaration of the | |
4289 // context slot followed by initialization. | |
4290 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
4291 } else { | |
4292 frame->CallRuntime(Runtime::kStoreContextSlot, 3); | |
4293 } | |
4294 // Storing a variable must keep the (new) value on the expression | |
4295 // stack. This is necessary for compiling assignment expressions. | |
4296 frame->EmitPush(r0); | |
4297 | |
4298 } else { | |
4299 ASSERT(!slot->var()->is_dynamic()); | |
4300 | |
4301 JumpTarget exit; | |
4302 if (init_state == CONST_INIT) { | |
4303 ASSERT(slot->var()->mode() == Variable::CONST); | |
4304 // Only the first const initialization must be executed (the slot | |
4305 // still contains 'the hole' value). When the assignment is | |
4306 // executed, the code is identical to a normal store (see below). | |
4307 Comment cmnt(masm, "[ Init const"); | |
4308 __ ldr(r2, cgen_->SlotOperand(slot, r2)); | |
4309 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
4310 __ cmp(r2, ip); | |
4311 exit.Branch(ne); | |
4312 } | |
4313 | |
4314 // We must execute the store. Storing a variable must keep the | |
4315 // (new) value on the stack. This is necessary for compiling | |
4316 // assignment expressions. | |
4317 // | |
4318 // Note: We will reach here even with slot->var()->mode() == | |
4319 // Variable::CONST because of const declarations which will | |
4320 // initialize consts to 'the hole' value and by doing so, end up | |
4321 // calling this code. r2 may be loaded with context; used below in | |
4322 // RecordWrite. | |
4323 frame->EmitPop(r0); | |
4324 __ str(r0, cgen_->SlotOperand(slot, r2)); | |
4325 frame->EmitPush(r0); | |
4326 if (slot->type() == Slot::CONTEXT) { | |
4327 // Skip write barrier if the written value is a smi. | |
4328 __ tst(r0, Operand(kSmiTagMask)); | |
4329 exit.Branch(eq); | |
4330 // r2 is loaded with context when calling SlotOperand above. | |
4331 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | |
4332 __ mov(r3, Operand(offset)); | |
4333 __ RecordWrite(r2, r3, r1); | |
4334 } | |
4335 // If we definitely did not jump over the assignment, we do not need | |
4336 // to bind the exit label. Doing so can defeat peephole | |
4337 // optimization. | |
4338 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | |
4339 exit.Bind(); | |
4340 } | |
4341 } | |
4342 break; | 4354 break; |
4343 } | 4355 } |
4344 | 4356 |
4345 case NAMED: { | 4357 case NAMED: { |
4346 Comment cmnt(masm, "[ Store to named Property"); | 4358 Comment cmnt(masm, "[ Store to named Property"); |
4347 // Call the appropriate IC code. | 4359 // Call the appropriate IC code. |
4348 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4360 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
4349 Handle<String> name(GetName()); | 4361 Handle<String> name(GetName()); |
4350 | 4362 |
4351 Result value(r0); | 4363 Result value(r0); |
(...skipping 2262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6614 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16)); | 6626 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16)); |
6615 int nnn_value = (never_nan_nan_ ? 2 : 0); | 6627 int nnn_value = (never_nan_nan_ ? 2 : 0); |
6616 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. | 6628 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. |
6617 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); | 6629 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); |
6618 } | 6630 } |
6619 | 6631 |
6620 | 6632 |
6621 #undef __ | 6633 #undef __ |
6622 | 6634 |
6623 } } // namespace v8::internal | 6635 } } // namespace v8::internal |
OLD | NEW |