| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 __ mov(eax, CodeGenerator::GlobalObject()); | 940 __ mov(eax, CodeGenerator::GlobalObject()); |
| 941 __ mov(ecx, slot->var()->name()); | 941 __ mov(ecx, slot->var()->name()); |
| 942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 943 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 943 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 944 ? RelocInfo::CODE_TARGET | 944 ? RelocInfo::CODE_TARGET |
| 945 : RelocInfo::CODE_TARGET_CONTEXT; | 945 : RelocInfo::CODE_TARGET_CONTEXT; |
| 946 __ call(ic, mode); | 946 __ call(ic, mode); |
| 947 } | 947 } |
| 948 | 948 |
| 949 | 949 |
| 950 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 951 Slot* slot, |
| 952 Label* slow) { |
| 953 ASSERT(slot->type() == Slot::CONTEXT); |
| 954 Register context = esi; |
| 955 Register temp = ebx; |
| 956 |
| 957 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 958 if (s->num_heap_slots() > 0) { |
| 959 if (s->calls_eval()) { |
| 960 // Check that extension is NULL. |
| 961 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
| 962 Immediate(0)); |
| 963 __ j(not_equal, slow); |
| 964 } |
| 965 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 966 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 967 // Walk the rest of the chain using a single register without |
| 968 // clobbering esi. |
| 969 context = temp; |
| 970 } |
| 971 } |
| 972 // Check that last extension is NULL. |
| 973 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 974 __ j(not_equal, slow); |
| 975 __ mov(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 976 return ContextOperand(temp, slot->index()); |
| 977 } |
| 978 |
| 979 |
| 980 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
| 981 Slot* slot, |
| 982 TypeofState typeof_state, |
| 983 Label* slow, |
| 984 Label* done) { |
| 985 // Generate fast-case code for variables that might be shadowed by |
| 986 // eval-introduced variables. Eval is used a lot without |
| 987 // introducing variables. In those cases, we do not want to |
| 988 // perform a runtime call for all variables in the scope |
| 989 // containing the eval. |
| 990 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 991 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); |
| 992 __ jmp(done); |
| 993 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 994 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 995 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); |
| 996 if (potential_slot != NULL) { |
| 997 // Generate fast case for locals that rewrite to slots. |
| 998 __ mov(eax, |
| 999 ContextSlotOperandCheckExtensions(potential_slot, slow)); |
| 1000 if (potential_slot->var()->mode() == Variable::CONST) { |
| 1001 __ cmp(eax, Factory::the_hole_value()); |
| 1002 __ j(not_equal, done); |
| 1003 __ mov(eax, Factory::undefined_value()); |
| 1004 } |
| 1005 __ jmp(done); |
| 1006 } else if (rewrite != NULL) { |
| 1007 // Generate fast case for calls of an argument function. |
| 1008 Property* property = rewrite->AsProperty(); |
| 1009 if (property != NULL) { |
| 1010 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1011 Literal* key_literal = property->key()->AsLiteral(); |
| 1012 if (obj_proxy != NULL && |
| 1013 key_literal != NULL && |
| 1014 obj_proxy->IsArguments() && |
| 1015 key_literal->handle()->IsSmi()) { |
| 1016 // Load arguments object if there are no eval-introduced |
| 1017 // variables. Then load the argument from the arguments |
| 1018 // object using keyed load. |
| 1019 __ mov(edx, |
| 1020 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(), |
| 1021 slow)); |
| 1022 __ mov(eax, Immediate(key_literal->handle())); |
| 1023 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1024 __ call(ic, RelocInfo::CODE_TARGET); |
| 1025 __ jmp(done); |
| 1026 } |
| 1027 } |
| 1028 } |
| 1029 } |
| 1030 } |
| 1031 |
| 1032 |
| 950 void FullCodeGenerator::EmitVariableLoad(Variable* var, | 1033 void FullCodeGenerator::EmitVariableLoad(Variable* var, |
| 951 Expression::Context context) { | 1034 Expression::Context context) { |
| 952 // Four cases: non-this global variables, lookup slots, all other | 1035 // Four cases: non-this global variables, lookup slots, all other |
| 953 // types of slots, and parameters that rewrite to explicit property | 1036 // types of slots, and parameters that rewrite to explicit property |
| 954 // accesses on the arguments object. | 1037 // accesses on the arguments object. |
| 955 Slot* slot = var->slot(); | 1038 Slot* slot = var->slot(); |
| 956 Property* property = var->AsProperty(); | 1039 Property* property = var->AsProperty(); |
| 957 | 1040 |
| 958 if (var->is_global() && !var->is_this()) { | 1041 if (var->is_global() && !var->is_this()) { |
| 959 Comment cmnt(masm_, "Global variable"); | 1042 Comment cmnt(masm_, "Global variable"); |
| 960 // Use inline caching. Variable name is passed in ecx and the global | 1043 // Use inline caching. Variable name is passed in ecx and the global |
| 961 // object on the stack. | 1044 // object on the stack. |
| 962 __ mov(eax, CodeGenerator::GlobalObject()); | 1045 __ mov(eax, CodeGenerator::GlobalObject()); |
| 963 __ mov(ecx, var->name()); | 1046 __ mov(ecx, var->name()); |
| 964 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1047 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 965 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1048 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 966 // By emitting a nop we make sure that we do not have a test eax | 1049 // By emitting a nop we make sure that we do not have a test eax |
| 967 // instruction after the call it is treated specially by the LoadIC code | 1050 // instruction after the call it is treated specially by the LoadIC code |
| 968 // Remember that the assembler may choose to do peephole optimization | 1051 // Remember that the assembler may choose to do peephole optimization |
| 969 // (eg, push/pop elimination). | 1052 // (eg, push/pop elimination). |
| 970 __ nop(); | 1053 __ nop(); |
| 971 Apply(context, eax); | 1054 Apply(context, eax); |
| 972 | 1055 |
| 973 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1056 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 974 Label done, slow; | 1057 Label done, slow; |
| 975 | 1058 |
| 976 // Generate fast-case code for variables that might be shadowed by | 1059 // Generate code for loading from variables potentially shadowed |
| 977 // eval-introduced variables. Eval is used a lot without | 1060 // by eval-introduced variables. |
| 978 // introducing variables. In those cases, we do not want to | 1061 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 979 // perform a runtime call for all variables in the scope | |
| 980 // containing the eval. | |
| 981 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | |
| 982 EmitLoadGlobalSlotCheckExtensions(slot, NOT_INSIDE_TYPEOF, &slow); | |
| 983 Apply(context, eax); | |
| 984 __ jmp(&done); | |
| 985 } | |
| 986 | 1062 |
| 987 __ bind(&slow); | 1063 __ bind(&slow); |
| 988 Comment cmnt(masm_, "Lookup slot"); | 1064 Comment cmnt(masm_, "Lookup slot"); |
| 989 __ push(esi); // Context. | 1065 __ push(esi); // Context. |
| 990 __ push(Immediate(var->name())); | 1066 __ push(Immediate(var->name())); |
| 991 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1067 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1068 __ bind(&done); |
| 1069 |
| 992 Apply(context, eax); | 1070 Apply(context, eax); |
| 993 __ bind(&done); | |
| 994 | 1071 |
| 995 } else if (slot != NULL) { | 1072 } else if (slot != NULL) { |
| 996 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1073 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 997 ? "Context slot" | 1074 ? "Context slot" |
| 998 : "Stack slot"); | 1075 : "Stack slot"); |
| 999 if (var->mode() == Variable::CONST) { | 1076 if (var->mode() == Variable::CONST) { |
| 1000 // Constants may be the hole value if they have not been initialized. | 1077 // Constants may be the hole value if they have not been initialized. |
| 1001 // Unhole them. | 1078 // Unhole them. |
| 1002 Label done; | 1079 Label done; |
| 1003 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1080 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| (...skipping 1019 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2023 __ CallStub(&stub); | 2100 __ CallStub(&stub); |
| 2024 // Restore context register. | 2101 // Restore context register. |
| 2025 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2102 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2026 DropAndApply(1, context_, eax); | 2103 DropAndApply(1, context_, eax); |
| 2027 } else if (var != NULL && !var->is_this() && var->is_global()) { | 2104 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 2028 // Push global object as receiver for the call IC. | 2105 // Push global object as receiver for the call IC. |
| 2029 __ push(CodeGenerator::GlobalObject()); | 2106 __ push(CodeGenerator::GlobalObject()); |
| 2030 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 2107 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
| 2031 } else if (var != NULL && var->slot() != NULL && | 2108 } else if (var != NULL && var->slot() != NULL && |
| 2032 var->slot()->type() == Slot::LOOKUP) { | 2109 var->slot()->type() == Slot::LOOKUP) { |
| 2033 // Call to a lookup slot (dynamically introduced variable). Call the | 2110 // Call to a lookup slot (dynamically introduced variable). |
| 2034 // runtime to find the function to call (returned in eax) and the object | 2111 Label slow, done; |
| 2035 // holding it (returned in edx). | 2112 |
| 2113 // Generate code for loading from variables potentially shadowed |
| 2114 // by eval-introduced variables. |
| 2115 EmitDynamicLoadFromSlotFastCase(var->slot(), |
| 2116 NOT_INSIDE_TYPEOF, |
| 2117 &slow, |
| 2118 &done); |
| 2119 |
| 2120 __ bind(&slow); |
| 2121 // Call the runtime to find the function to call (returned in eax) |
| 2122 // and the object holding it (returned in edx). |
| 2036 __ push(context_register()); | 2123 __ push(context_register()); |
| 2037 __ push(Immediate(var->name())); | 2124 __ push(Immediate(var->name())); |
| 2038 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2125 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2039 __ push(eax); // Function. | 2126 __ push(eax); // Function. |
| 2040 __ push(edx); // Receiver. | 2127 __ push(edx); // Receiver. |
| 2128 |
| 2129 // If fast case code has been generated, emit code to push the |
| 2130 // function and receiver and have the slow path jump around this |
| 2131 // code. |
| 2132 if (done.is_linked()) { |
| 2133 Label call; |
| 2134 __ jmp(&call); |
| 2135 __ bind(&done); |
| 2136 // Push function. |
| 2137 __ push(eax); |
| 2138 // Push global receiver. |
| 2139 __ mov(ebx, CodeGenerator::GlobalObject()); |
| 2140 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 2141 __ bind(&call); |
| 2142 } |
| 2143 |
| 2041 EmitCallWithStub(expr); | 2144 EmitCallWithStub(expr); |
| 2042 } else if (fun->AsProperty() != NULL) { | 2145 } else if (fun->AsProperty() != NULL) { |
| 2043 // Call to an object property. | 2146 // Call to an object property. |
| 2044 Property* prop = fun->AsProperty(); | 2147 Property* prop = fun->AsProperty(); |
| 2045 Literal* key = prop->key()->AsLiteral(); | 2148 Literal* key = prop->key()->AsLiteral(); |
| 2046 if (key != NULL && key->handle()->IsSymbol()) { | 2149 if (key != NULL && key->handle()->IsSymbol()) { |
| 2047 // Call to a named property, use call IC. | 2150 // Call to a named property, use call IC. |
| 2048 VisitForValue(prop->obj(), kStack); | 2151 VisitForValue(prop->obj(), kStack); |
| 2049 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2152 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2050 } else { | 2153 } else { |
| (...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3334 __ mov(eax, CodeGenerator::GlobalObject()); | 3437 __ mov(eax, CodeGenerator::GlobalObject()); |
| 3335 __ mov(ecx, Immediate(proxy->name())); | 3438 __ mov(ecx, Immediate(proxy->name())); |
| 3336 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3439 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3337 // Use a regular load, not a contextual load, to avoid a reference | 3440 // Use a regular load, not a contextual load, to avoid a reference |
| 3338 // error. | 3441 // error. |
| 3339 __ call(ic, RelocInfo::CODE_TARGET); | 3442 __ call(ic, RelocInfo::CODE_TARGET); |
| 3340 if (where == kStack) __ push(eax); | 3443 if (where == kStack) __ push(eax); |
| 3341 } else if (proxy != NULL && | 3444 } else if (proxy != NULL && |
| 3342 proxy->var()->slot() != NULL && | 3445 proxy->var()->slot() != NULL && |
| 3343 proxy->var()->slot()->type() == Slot::LOOKUP) { | 3446 proxy->var()->slot()->type() == Slot::LOOKUP) { |
| 3447 Label done, slow; |
| 3448 |
| 3449 // Generate code for loading from variables potentially shadowed |
| 3450 // by eval-introduced variables. |
| 3451 Slot* slot = proxy->var()->slot(); |
| 3452 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3453 |
| 3454 __ bind(&slow); |
| 3344 __ push(esi); | 3455 __ push(esi); |
| 3345 __ push(Immediate(proxy->name())); | 3456 __ push(Immediate(proxy->name())); |
| 3346 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3457 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3458 __ bind(&done); |
| 3459 |
| 3347 if (where == kStack) __ push(eax); | 3460 if (where == kStack) __ push(eax); |
| 3348 } else { | 3461 } else { |
| 3349 // This expression cannot throw a reference error at the top level. | 3462 // This expression cannot throw a reference error at the top level. |
| 3350 VisitForValue(expr, where); | 3463 VisitForValue(expr, where); |
| 3351 } | 3464 } |
| 3352 } | 3465 } |
| 3353 | 3466 |
| 3354 | 3467 |
| 3355 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3468 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, |
| 3356 Expression* left, | 3469 Expression* left, |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3620 // And return. | 3733 // And return. |
| 3621 __ ret(0); | 3734 __ ret(0); |
| 3622 } | 3735 } |
| 3623 | 3736 |
| 3624 | 3737 |
| 3625 #undef __ | 3738 #undef __ |
| 3626 | 3739 |
| 3627 } } // namespace v8::internal | 3740 } } // namespace v8::internal |
| 3628 | 3741 |
| 3629 #endif // V8_TARGET_ARCH_IA32 | 3742 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |