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 1161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1172 int value_; | 1172 int value_; |
| 1173 }; | 1173 }; |
| 1174 | 1174 |
| 1175 | 1175 |
| 1176 void SmiComparisonDeferred::Generate() { | 1176 void SmiComparisonDeferred::Generate() { |
| 1177 CompareStub stub(cc_, strict_); | 1177 CompareStub stub(cc_, strict_); |
| 1178 // Setup parameters and call stub. | 1178 // Setup parameters and call stub. |
| 1179 __ mov(edx, Operand(eax)); | 1179 __ mov(edx, Operand(eax)); |
| 1180 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); | 1180 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); |
| 1181 __ CallStub(&stub); | 1181 __ CallStub(&stub); |
| 1182 __ cmp(eax, 0); | 1182 if (cc_ == equal) { |
| 1183 __ test(eax, Operand(eax)); | |
| 1184 } else { | |
| 1185 __ cmp(eax, 0); | |
| 1186 } | |
| 1183 // "result" is returned in the flags | 1187 // "result" is returned in the flags |
| 1184 } | 1188 } |
| 1185 | 1189 |
| 1186 | 1190 |
| 1187 void CodeGenerator::SmiComparison(Condition cc, | 1191 void CodeGenerator::SmiComparison(Condition cc, |
| 1188 Handle<Object> value, | 1192 Handle<Object> value, |
| 1189 bool strict) { | 1193 bool strict) { |
| 1190 // Strict only makes sense for equality comparisons. | 1194 // Strict only makes sense for equality comparisons. |
| 1191 ASSERT(!strict || cc == equal); | 1195 ASSERT(!strict || cc == equal); |
| 1192 | 1196 |
| 1193 int int_value = Smi::cast(*value)->value(); | 1197 int int_value = Smi::cast(*value)->value(); |
| 1194 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); | 1198 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); |
| 1195 | 1199 |
| 1196 SmiComparisonDeferred* deferred = | 1200 SmiComparisonDeferred* deferred = |
| 1197 new SmiComparisonDeferred(this, cc, strict, int_value); | 1201 new SmiComparisonDeferred(this, cc, strict, int_value); |
| 1198 __ pop(eax); | 1202 __ pop(eax); |
| 1199 __ test(eax, Immediate(kSmiTagMask)); | 1203 __ test(eax, Immediate(kSmiTagMask)); |
| 1200 __ j(not_zero, deferred->enter(), not_taken); | 1204 __ j(not_zero, deferred->enter(), not_taken); |
| 1201 // Test smi equality by pointer comparison. | 1205 // Test smi equality by pointer comparison. |
| 1202 __ cmp(Operand(eax), Immediate(value)); | 1206 __ cmp(Operand(eax), Immediate(value)); |
| 1203 __ bind(deferred->exit()); | 1207 __ bind(deferred->exit()); |
| 1204 cc_reg_ = cc; | 1208 cc_reg_ = cc; |
| 1205 } | 1209 } |
| 1206 | 1210 |
| 1207 | 1211 |
| 1208 class CallFunctionStub: public CodeStub { | 1212 class CallFunctionStub: public CodeStub { |
| 1209 public: | 1213 public: |
| 1210 explicit CallFunctionStub(int argc) : argc_(argc) { } | 1214 explicit CallFunctionStub(int argc, bool call_constructor) |
| 1215 : argc_(argc), call_constructor_(call_constructor) { } | |
| 1211 | 1216 |
| 1212 void Generate(MacroAssembler* masm); | 1217 void Generate(MacroAssembler* masm); |
| 1213 | 1218 |
| 1214 private: | 1219 private: |
| 1215 int argc_; | 1220 int argc_; |
| 1221 bool call_constructor_; | |
| 1216 | 1222 |
| 1217 #ifdef DEBUG | 1223 #ifdef DEBUG |
| 1218 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } | 1224 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } |
| 1219 #endif | 1225 #endif |
| 1220 | 1226 |
| 1221 Major MajorKey() { return CallFunction; } | 1227 Major MajorKey() { return CallFunction; } |
| 1222 int MinorKey() { return argc_; } | 1228 int MinorKey() { return (argc_ << 1) | (call_constructor_ ? 1 : 0); } |
| 1223 }; | 1229 }; |
| 1224 | 1230 |
| 1225 | 1231 |
| 1226 // Call the function just below TOS on the stack with the given | 1232 // Call the function just below TOS on the stack with the given |
| 1227 // arguments. The receiver is the TOS. | 1233 // arguments. The receiver is the TOS. |
| 1228 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1234 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1229 int position) { | 1235 bool call_constructor, |
|
iposva
2008/10/10 13:56:18
Please change the bool parameter to an enum {FUNCT
| |
| 1236 int position) { | |
| 1230 // Push the arguments ("left-to-right") on the stack. | 1237 // Push the arguments ("left-to-right") on the stack. |
| 1231 for (int i = 0; i < args->length(); i++) { | 1238 for (int i = 0; i < args->length(); i++) { |
| 1232 Load(args->at(i)); | 1239 Load(args->at(i)); |
| 1233 } | 1240 } |
| 1234 | 1241 |
| 1235 // Record the position for debugging purposes. | 1242 // Record the position for debugging purposes. |
| 1236 __ RecordPosition(position); | 1243 __ RecordPosition(position); |
| 1237 | 1244 |
| 1238 // Use the shared code stub to call the function. | 1245 // Use the shared code stub to call the function. |
| 1239 CallFunctionStub call_function(args->length()); | 1246 CallFunctionStub call_function(args->length(), call_constructor); |
| 1240 __ CallStub(&call_function); | 1247 RelocInfo::Mode mode = call_constructor |
| 1248 ? RelocInfo::CONSTRUCT_CALL | |
| 1249 : RelocInfo::CODE_TARGET; | |
| 1250 __ CallStub(&call_function, mode); | |
| 1241 | 1251 |
| 1242 // Restore context and pop function from the stack. | 1252 // Restore context and pop function from the stack. |
| 1243 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1253 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 1244 __ mov(TOS, eax); | 1254 __ mov(TOS, eax); |
| 1245 } | 1255 } |
| 1246 | 1256 |
| 1247 | 1257 |
| 1248 void CodeGenerator::Branch(bool if_true, Label* L) { | 1258 void CodeGenerator::Branch(bool if_true, Label* L) { |
| 1249 ASSERT(has_cc()); | 1259 ASSERT(has_cc()); |
| 1250 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1260 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| (...skipping 1339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2590 __ push(Operand(esi)); | 2600 __ push(Operand(esi)); |
| 2591 __ push(Immediate(var->name())); | 2601 __ push(Immediate(var->name())); |
| 2592 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2602 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2593 // eax: slot value; edx: receiver | 2603 // eax: slot value; edx: receiver |
| 2594 | 2604 |
| 2595 // Load the receiver. | 2605 // Load the receiver. |
| 2596 __ push(eax); | 2606 __ push(eax); |
| 2597 __ push(edx); | 2607 __ push(edx); |
| 2598 | 2608 |
| 2599 // Call the function. | 2609 // Call the function. |
| 2600 CallWithArguments(args, node->position()); | 2610 CallWithArguments(args, false, node->position()); |
| 2601 | 2611 |
| 2602 } else if (property != NULL) { | 2612 } else if (property != NULL) { |
| 2603 // Check if the key is a literal string. | 2613 // Check if the key is a literal string. |
| 2604 Literal* literal = property->key()->AsLiteral(); | 2614 Literal* literal = property->key()->AsLiteral(); |
| 2605 | 2615 |
| 2606 if (literal != NULL && literal->handle()->IsSymbol()) { | 2616 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2607 // ------------------------------------------------------------------ | 2617 // ------------------------------------------------------------------ |
| 2608 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 2618 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 2609 // ------------------------------------------------------------------ | 2619 // ------------------------------------------------------------------ |
| 2610 | 2620 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2631 | 2641 |
| 2632 // Load the function to call from the property through a reference. | 2642 // Load the function to call from the property through a reference. |
| 2633 Reference ref(this, property); | 2643 Reference ref(this, property); |
| 2634 ref.GetValue(NOT_INSIDE_TYPEOF); | 2644 ref.GetValue(NOT_INSIDE_TYPEOF); |
| 2635 | 2645 |
| 2636 // Pass receiver to called function. | 2646 // Pass receiver to called function. |
| 2637 // The reference's size is non-negative. | 2647 // The reference's size is non-negative. |
| 2638 __ push(Operand(esp, ref.size() * kPointerSize)); | 2648 __ push(Operand(esp, ref.size() * kPointerSize)); |
| 2639 | 2649 |
| 2640 // Call the function. | 2650 // Call the function. |
| 2641 CallWithArguments(args, node->position()); | 2651 CallWithArguments(args, false, node->position()); |
| 2642 } | 2652 } |
| 2643 | 2653 |
| 2644 } else { | 2654 } else { |
| 2645 // ---------------------------------- | 2655 // ---------------------------------- |
| 2646 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 2656 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
| 2647 // ---------------------------------- | 2657 // ---------------------------------- |
| 2648 | 2658 |
| 2649 // Load the function. | 2659 // Load the function. |
| 2650 Load(function); | 2660 Load(function); |
| 2651 | 2661 |
| 2652 // Pass the global object as the receiver. | 2662 // Pass the global object as the receiver. |
| 2653 LoadGlobal(); | 2663 LoadGlobal(); |
| 2654 | 2664 |
| 2655 // Call the function. | 2665 // Call the function. |
| 2656 CallWithArguments(args, node->position()); | 2666 CallWithArguments(args, false, node->position()); |
| 2657 } | 2667 } |
| 2658 } | 2668 } |
| 2659 | 2669 |
| 2660 | 2670 |
| 2661 void CodeGenerator::VisitCallNew(CallNew* node) { | 2671 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 2662 Comment cmnt(masm_, "[ CallNew"); | 2672 Comment cmnt(masm_, "[ CallNew"); |
| 2663 | 2673 |
| 2664 // According to ECMA-262, section 11.2.2, page 44, the function | 2674 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2665 // expression in new calls must be evaluated before the | 2675 // expression in new calls must be evaluated before the |
| 2666 // arguments. This is different from ordinary calls, where the | 2676 // arguments. This is different from ordinary calls, where the |
| 2667 // actual function to call is resolved after the arguments have been | 2677 // actual function to call is resolved after the arguments have been |
| 2668 // evaluated. | 2678 // evaluated. |
| 2669 | 2679 |
| 2670 // Compute function to call and use the global object as the | 2680 // Compute function to call and use the global object as the |
| 2671 // receiver. | 2681 // receiver. |
| 2672 Load(node->expression()); | 2682 Load(node->expression()); |
| 2673 LoadGlobal(); | 2683 LoadGlobal(); |
| 2674 | 2684 |
| 2675 // Push the arguments ("left-to-right") on the stack. | 2685 CallWithArguments(node->arguments(), true, node->position()); |
|
iposva
2008/10/10 13:56:18
Nice refactoring!
| |
| 2676 ZoneList<Expression*>* args = node->arguments(); | |
| 2677 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | |
| 2678 | |
| 2679 // Constructors are called with the number of arguments in register | |
| 2680 // eax for now. Another option would be to have separate construct | |
| 2681 // call trampolines per different arguments counts encountered. | |
| 2682 __ Set(eax, Immediate(args->length())); | |
| 2683 | |
| 2684 // Load the function into temporary function slot as per calling | |
| 2685 // convention. | |
| 2686 __ mov(edi, Operand(esp, (args->length() + 1) * kPointerSize)); | |
| 2687 | |
| 2688 // Call the construct call builtin that handles allocation and | |
| 2689 // constructor invocation. | |
| 2690 __ RecordPosition(node->position()); | |
| 2691 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | |
| 2692 RelocInfo::CONSTRUCT_CALL); | |
| 2693 __ mov(TOS, eax); // discard the function and "push" the newly created object | |
| 2694 } | 2686 } |
| 2695 | 2687 |
| 2696 | 2688 |
| 2697 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2689 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2698 ASSERT(args->length() == 1); | 2690 ASSERT(args->length() == 1); |
| 2699 Load(args->at(0)); | 2691 Load(args->at(0)); |
| 2700 __ pop(eax); | 2692 __ pop(eax); |
| 2701 __ test(eax, Immediate(kSmiTagMask)); | 2693 __ test(eax, Immediate(kSmiTagMask)); |
| 2702 cc_reg_ = zero; | 2694 cc_reg_ = zero; |
| 2703 } | 2695 } |
| (...skipping 1942 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4646 // Check that the function really is a JavaScript function. | 4638 // Check that the function really is a JavaScript function. |
| 4647 __ test(edi, Immediate(kSmiTagMask)); | 4639 __ test(edi, Immediate(kSmiTagMask)); |
| 4648 __ j(zero, &slow, not_taken); | 4640 __ j(zero, &slow, not_taken); |
| 4649 // Get the map. | 4641 // Get the map. |
| 4650 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); | 4642 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); |
| 4651 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 4643 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 4652 __ cmp(ecx, JS_FUNCTION_TYPE); | 4644 __ cmp(ecx, JS_FUNCTION_TYPE); |
| 4653 __ j(not_equal, &slow, not_taken); | 4645 __ j(not_equal, &slow, not_taken); |
| 4654 | 4646 |
| 4655 // Fast-case: Just invoke the function. | 4647 // Fast-case: Just invoke the function. |
| 4656 ParameterCount actual(argc_); | 4648 if (call_constructor_) { |
| 4657 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 4649 __ Set(eax, Immediate(argc_)); |
| 4650 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
| 4651 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
| 4652 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kConstructorOffset)); | |
| 4653 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | |
| 4654 __ jmp(Operand(edx)); | |
| 4655 } else { | |
| 4656 ParameterCount actual(argc_); | |
| 4657 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | |
| 4658 } | |
| 4658 | 4659 |
| 4659 // Slow-case: Non-function called. | 4660 // Slow-case: Non-function called. |
| 4660 __ bind(&slow); | 4661 __ bind(&slow); |
| 4661 __ Set(eax, Immediate(argc_)); | 4662 if (call_constructor_) { |
| 4662 __ Set(ebx, Immediate(0)); | 4663 // Get rid of the arguments and the receiver and call the NewObject |
| 4663 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 4664 // runtime function to generate and throw an exception. |
| 4664 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 4665 __ pop(ecx); |
| 4665 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 4666 __ add(Operand(esp), Immediate((argc_ + 1) * kPointerSize)); |
| 4667 __ push(ecx); | |
| 4668 __ TailCallRuntime(ExternalReference(Runtime::kNewObject), 1); | |
| 4669 } else { | |
| 4670 __ Set(eax, Immediate(argc_)); | |
| 4671 __ Set(ebx, Immediate(0)); | |
| 4672 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | |
| 4673 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline) ); | |
| 4674 __ jmp(adaptor, RelocInfo::CODE_TARGET); | |
| 4675 } | |
| 4666 } | 4676 } |
| 4667 | 4677 |
| 4668 | 4678 |
| 4669 void RevertToNumberStub::Generate(MacroAssembler* masm) { | 4679 void RevertToNumberStub::Generate(MacroAssembler* masm) { |
| 4670 // Revert optimistic increment/decrement. | 4680 // Revert optimistic increment/decrement. |
| 4671 if (is_increment_) { | 4681 if (is_increment_) { |
| 4672 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); | 4682 __ sub(Operand(eax), Immediate(Smi::FromInt(1))); |
| 4673 } else { | 4683 } else { |
| 4674 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | 4684 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 4675 } | 4685 } |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5046 | 5056 |
| 5047 // Slow-case: Go through the JavaScript implementation. | 5057 // Slow-case: Go through the JavaScript implementation. |
| 5048 __ bind(&slow); | 5058 __ bind(&slow); |
| 5049 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5059 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5050 } | 5060 } |
| 5051 | 5061 |
| 5052 | 5062 |
| 5053 #undef __ | 5063 #undef __ |
| 5054 | 5064 |
| 5055 } } // namespace v8::internal | 5065 } } // namespace v8::internal |
| OLD | NEW |