OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 __ ldr(r0, MemOperand(sp, 0)); | 274 __ ldr(r0, MemOperand(sp, 0)); |
275 TestAndBranch(r0, &discard, false_label_); | 275 TestAndBranch(r0, &discard, false_label_); |
276 __ bind(&discard); | 276 __ bind(&discard); |
277 __ Drop(1); | 277 __ Drop(1); |
278 __ jmp(true_label_); | 278 __ jmp(true_label_); |
279 } | 279 } |
280 } | 280 } |
281 } | 281 } |
282 | 282 |
283 | 283 |
284 template <> | 284 MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { |
285 MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>( | 285 switch (slot->type()) { |
286 Slot* source, | |
287 Register scratch) { | |
288 switch (source->type()) { | |
289 case Slot::PARAMETER: | 286 case Slot::PARAMETER: |
290 case Slot::LOCAL: | 287 case Slot::LOCAL: |
291 return MemOperand(fp, SlotOffset(source)); | 288 return MemOperand(fp, SlotOffset(slot)); |
292 case Slot::CONTEXT: { | 289 case Slot::CONTEXT: { |
293 int context_chain_length = | 290 int context_chain_length = |
294 function_->scope()->ContextChainLength(source->var()->scope()); | 291 function_->scope()->ContextChainLength(slot->var()->scope()); |
295 __ LoadContext(scratch, context_chain_length); | 292 __ LoadContext(scratch, context_chain_length); |
296 return CodeGenerator::ContextOperand(scratch, source->index()); | 293 return CodeGenerator::ContextOperand(scratch, slot->index()); |
297 } | 294 } |
298 case Slot::LOOKUP: | 295 case Slot::LOOKUP: |
299 UNIMPLEMENTED(); | 296 UNREACHABLE(); |
300 } | 297 } |
301 UNREACHABLE(); | 298 UNREACHABLE(); |
302 return MemOperand(r0, 0); | 299 return MemOperand(r0, 0); |
303 } | 300 } |
304 | 301 |
305 | 302 |
306 void FastCodeGenerator::Move(Register dst, Slot* source) { | 303 void FastCodeGenerator::Move(Register destination, Slot* source) { |
307 // Use dst as scratch. | 304 // Use destination as scratch. |
308 MemOperand location = CreateSlotOperand<MemOperand>(source, dst); | 305 MemOperand location = EmitSlotSearch(source, destination); |
309 __ ldr(dst, location); | 306 __ ldr(destination, location); |
310 } | 307 } |
311 | 308 |
312 | 309 |
313 | 310 |
314 void FastCodeGenerator::Move(Expression::Context context, | 311 void FastCodeGenerator::Move(Expression::Context context, |
315 Slot* source, | 312 Slot* source, |
316 Register scratch) { | 313 Register scratch) { |
317 switch (context) { | 314 switch (context) { |
318 case Expression::kUninitialized: | 315 case Expression::kUninitialized: |
319 UNREACHABLE(); | 316 UNREACHABLE(); |
(...skipping 24 matching lines...) Expand all Loading... |
344 Move(context, ip); | 341 Move(context, ip); |
345 break; | 342 break; |
346 } | 343 } |
347 } | 344 } |
348 | 345 |
349 | 346 |
350 void FastCodeGenerator::Move(Slot* dst, | 347 void FastCodeGenerator::Move(Slot* dst, |
351 Register src, | 348 Register src, |
352 Register scratch1, | 349 Register scratch1, |
353 Register scratch2) { | 350 Register scratch2) { |
354 switch (dst->type()) { | 351 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. |
355 case Slot::PARAMETER: | 352 ASSERT(!scratch1.is(src) && !scratch2.is(src)); |
356 case Slot::LOCAL: | 353 MemOperand location = EmitSlotSearch(dst, scratch1); |
357 __ str(src, MemOperand(fp, SlotOffset(dst))); | 354 __ str(src, location); |
358 break; | 355 // Emit the write barrier code if the location is in the heap. |
359 case Slot::CONTEXT: { | 356 if (dst->type() == Slot::CONTEXT) { |
360 int context_chain_length = | 357 __ mov(scratch2, Operand(Context::SlotOffset(dst->index()))); |
361 function_->scope()->ContextChainLength(dst->var()->scope()); | 358 __ RecordWrite(scratch1, scratch2, src); |
362 __ LoadContext(scratch1, context_chain_length); | |
363 int index = Context::SlotOffset(dst->index()); | |
364 __ mov(scratch2, Operand(index)); | |
365 __ str(src, MemOperand(scratch1, index)); | |
366 __ RecordWrite(scratch1, scratch2, src); | |
367 break; | |
368 } | |
369 case Slot::LOOKUP: | |
370 UNIMPLEMENTED(); | |
371 } | 359 } |
372 } | 360 } |
373 | 361 |
374 | 362 |
375 | 363 |
376 void FastCodeGenerator::DropAndMove(Expression::Context context, | 364 void FastCodeGenerator::DropAndMove(Expression::Context context, |
377 Register source, | 365 Register source, |
378 int drop_count) { | 366 int drop_count) { |
379 ASSERT(drop_count > 0); | 367 ASSERT(drop_count > 0); |
380 switch (context) { | 368 switch (context) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 ASSERT(var != NULL); // Must have been resolved. | 432 ASSERT(var != NULL); // Must have been resolved. |
445 Slot* slot = var->slot(); | 433 Slot* slot = var->slot(); |
446 Property* prop = var->AsProperty(); | 434 Property* prop = var->AsProperty(); |
447 | 435 |
448 if (slot != NULL) { | 436 if (slot != NULL) { |
449 switch (slot->type()) { | 437 switch (slot->type()) { |
450 case Slot::PARAMETER: | 438 case Slot::PARAMETER: |
451 case Slot::LOCAL: | 439 case Slot::LOCAL: |
452 if (decl->mode() == Variable::CONST) { | 440 if (decl->mode() == Variable::CONST) { |
453 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 441 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
454 __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); | 442 __ str(ip, MemOperand(fp, SlotOffset(slot))); |
455 } else if (decl->fun() != NULL) { | 443 } else if (decl->fun() != NULL) { |
456 Visit(decl->fun()); | 444 Visit(decl->fun()); |
457 __ pop(ip); | 445 __ pop(ip); |
458 __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); | 446 __ str(ip, MemOperand(fp, SlotOffset(slot))); |
459 } | 447 } |
460 break; | 448 break; |
461 | 449 |
462 case Slot::CONTEXT: | 450 case Slot::CONTEXT: |
| 451 // We bypass the general EmitSlotSearch because we know more about |
| 452 // this specific context. |
| 453 |
463 // The variable in the decl always resides in the current context. | 454 // The variable in the decl always resides in the current context. |
464 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); | 455 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); |
465 if (FLAG_debug_code) { | 456 if (FLAG_debug_code) { |
466 // Check if we have the correct context pointer. | 457 // Check if we have the correct context pointer. |
467 __ ldr(r1, | 458 __ ldr(r1, |
468 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); | 459 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX)); |
469 __ cmp(r1, cp); | 460 __ cmp(r1, cp); |
470 __ Check(eq, "Unexpected declaration in current context."); | 461 __ Check(eq, "Unexpected declaration in current context."); |
471 } | 462 } |
472 if (decl->mode() == Variable::CONST) { | 463 if (decl->mode() == Variable::CONST) { |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 // r2, and the global object on the stack. | 896 // r2, and the global object on the stack. |
906 __ pop(r0); | 897 __ pop(r0); |
907 __ mov(r2, Operand(var->name())); | 898 __ mov(r2, Operand(var->name())); |
908 __ ldr(ip, CodeGenerator::GlobalObject()); | 899 __ ldr(ip, CodeGenerator::GlobalObject()); |
909 __ push(ip); | 900 __ push(ip); |
910 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 901 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
911 __ Call(ic, RelocInfo::CODE_TARGET); | 902 __ Call(ic, RelocInfo::CODE_TARGET); |
912 // Overwrite the global object on the stack with the result if needed. | 903 // Overwrite the global object on the stack with the result if needed. |
913 DropAndMove(context, r0); | 904 DropAndMove(context, r0); |
914 | 905 |
915 } else if (var->slot()) { | 906 } else if (var->slot() != NULL) { |
916 Slot* slot = var->slot(); | 907 Slot* slot = var->slot(); |
917 ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled. | |
918 switch (slot->type()) { | 908 switch (slot->type()) { |
919 case Slot::LOCAL: | 909 case Slot::LOCAL: |
920 case Slot::PARAMETER: { | 910 case Slot::PARAMETER: { |
| 911 MemOperand target = MemOperand(fp, SlotOffset(slot)); |
921 switch (context) { | 912 switch (context) { |
922 case Expression::kUninitialized: | 913 case Expression::kUninitialized: |
923 UNREACHABLE(); | 914 UNREACHABLE(); |
924 case Expression::kEffect: | 915 case Expression::kEffect: |
925 // Perform assignment and discard value. | 916 // Perform assignment and discard value. |
926 __ pop(r0); | 917 __ pop(r0); |
927 __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); | 918 __ str(r0, target); |
928 break; | 919 break; |
929 case Expression::kValue: | 920 case Expression::kValue: |
930 // Perform assignment and preserve value. | 921 // Perform assignment and preserve value. |
931 __ ldr(r0, MemOperand(sp)); | 922 __ ldr(r0, MemOperand(sp)); |
932 __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); | 923 __ str(r0, target); |
933 break; | 924 break; |
934 case Expression::kTest: | 925 case Expression::kTest: |
935 // Perform assignment and test (and discard) value. | 926 // Perform assignment and test (and discard) value. |
936 __ pop(r0); | 927 __ pop(r0); |
937 __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); | 928 __ str(r0, target); |
938 TestAndBranch(r0, true_label_, false_label_); | 929 TestAndBranch(r0, true_label_, false_label_); |
939 break; | 930 break; |
940 case Expression::kValueTest: { | 931 case Expression::kValueTest: { |
941 Label discard; | 932 Label discard; |
942 __ ldr(r0, MemOperand(sp)); | 933 __ ldr(r0, MemOperand(sp)); |
943 __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); | 934 __ str(r0, target); |
944 TestAndBranch(r0, true_label_, &discard); | 935 TestAndBranch(r0, true_label_, &discard); |
945 __ bind(&discard); | 936 __ bind(&discard); |
946 __ pop(); | 937 __ pop(); |
947 __ jmp(false_label_); | 938 __ jmp(false_label_); |
948 break; | 939 break; |
949 } | 940 } |
950 case Expression::kTestValue: { | 941 case Expression::kTestValue: { |
951 Label discard; | 942 Label discard; |
952 __ ldr(r0, MemOperand(sp)); | 943 __ ldr(r0, MemOperand(sp)); |
953 __ str(r0, MemOperand(fp, SlotOffset(var->slot()))); | 944 __ str(r0, target); |
954 TestAndBranch(r0, &discard, false_label_); | 945 TestAndBranch(r0, &discard, false_label_); |
955 __ bind(&discard); | 946 __ bind(&discard); |
956 __ pop(); | 947 __ pop(); |
957 __ jmp(true_label_); | 948 __ jmp(true_label_); |
958 break; | 949 break; |
959 } | 950 } |
960 } | 951 } |
961 break; | 952 break; |
962 } | 953 } |
963 | 954 |
964 case Slot::CONTEXT: { | 955 case Slot::CONTEXT: { |
965 int chain_length = | 956 MemOperand target = EmitSlotSearch(slot, r1); |
966 function_->scope()->ContextChainLength(slot->var()->scope()); | 957 __ pop(r0); |
967 if (chain_length > 0) { | 958 __ str(r0, target); |
968 // Move up the chain of contexts to the context containing the slot. | |
969 __ ldr(r0, CodeGenerator::ContextOperand(cp, Context::CLOSURE_INDEX)); | |
970 // Load the function context (which is the incoming, outer context). | |
971 __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset)); | |
972 for (int i = 1; i < chain_length; i++) { | |
973 __ ldr(r0, | |
974 CodeGenerator::ContextOperand(r0, Context::CLOSURE_INDEX)); | |
975 __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset)); | |
976 } | |
977 } else { // Slot is in the current context. Generate optimized code. | |
978 __ mov(r0, cp); | |
979 } | |
980 // The context may be an intermediate context, not a function context. | |
981 __ ldr(r0, CodeGenerator::ContextOperand(r0, Context::FCONTEXT_INDEX)); | |
982 __ pop(r1); | |
983 __ str(r1, CodeGenerator::ContextOperand(r0, slot->index())); | |
984 | 959 |
985 // RecordWrite may destroy all its register arguments. | 960 // RecordWrite may destroy all its register arguments. |
986 if (context == Expression::kValue) { | 961 if (context == Expression::kValue) { |
987 __ push(r1); | 962 __ push(r0); |
988 } else if (context != Expression::kEffect) { | 963 } else if (context != Expression::kEffect) { |
989 __ mov(r3, r1); | 964 __ mov(r3, r0); |
990 } | 965 } |
991 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 966 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
992 | 967 |
993 // Update the write barrier for the array store with r0 as the scratch | 968 // Update the write barrier for the array store with r0 as the scratch |
994 // register. Skip the write barrier if the value written (r1) is a smi. | 969 // register. Skip the write barrier if the value written (r1) is a smi. |
995 // The smi test is part of RecordWrite on other platforms, not on arm. | 970 // The smi test is part of RecordWrite on other platforms, not on arm. |
996 Label exit; | 971 Label exit; |
997 __ tst(r1, Operand(kSmiTagMask)); | 972 __ tst(r0, Operand(kSmiTagMask)); |
998 __ b(eq, &exit); | 973 __ b(eq, &exit); |
999 | 974 |
1000 __ mov(r2, Operand(offset)); | 975 __ mov(r2, Operand(offset)); |
1001 __ RecordWrite(r0, r2, r1); | 976 __ RecordWrite(r1, r2, r0); |
1002 __ bind(&exit); | 977 __ bind(&exit); |
1003 if (context != Expression::kEffect && | 978 if (context != Expression::kEffect && context != Expression::kValue) { |
1004 context != Expression::kValue) { | |
1005 Move(context, r3); | 979 Move(context, r3); |
1006 } | 980 } |
1007 break; | 981 break; |
1008 } | 982 } |
1009 | 983 |
1010 case Slot::LOOKUP: | 984 case Slot::LOOKUP: |
1011 UNREACHABLE(); | 985 UNREACHABLE(); |
1012 break; | 986 break; |
1013 } | 987 } |
| 988 } else { |
| 989 // Variables rewritten as properties are not treated as variables in |
| 990 // assignments. |
| 991 UNREACHABLE(); |
1014 } | 992 } |
1015 } | 993 } |
1016 | 994 |
1017 | 995 |
1018 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 996 void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1019 // Assignment to a property, using a named store IC. | 997 // Assignment to a property, using a named store IC. |
1020 Property* prop = expr->target()->AsProperty(); | 998 Property* prop = expr->target()->AsProperty(); |
1021 ASSERT(prop != NULL); | 999 ASSERT(prop != NULL); |
1022 ASSERT(prop->key()->AsLiteral() != NULL); | 1000 ASSERT(prop->key()->AsLiteral() != NULL); |
1023 | 1001 |
(...skipping 791 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1815 __ pop(result_register()); | 1793 __ pop(result_register()); |
1816 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 1794 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
1817 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 1795 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
1818 __ add(pc, r1, Operand(masm_->CodeObject())); | 1796 __ add(pc, r1, Operand(masm_->CodeObject())); |
1819 } | 1797 } |
1820 | 1798 |
1821 | 1799 |
1822 #undef __ | 1800 #undef __ |
1823 | 1801 |
1824 } } // namespace v8::internal | 1802 } } // namespace v8::internal |
OLD | NEW |