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 14 matching lines...) Expand all Loading... |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
32 #include "compiler.h" | 32 #include "compiler.h" |
33 #include "debug.h" | 33 #include "debug.h" |
34 #include "ic-inl.h" | 34 #include "ic-inl.h" |
| 35 #include "jsregexp.h" |
35 #include "parser.h" | 36 #include "parser.h" |
| 37 #include "regexp-macro-assembler.h" |
| 38 #include "regexp-stack.h" |
36 #include "register-allocator-inl.h" | 39 #include "register-allocator-inl.h" |
37 #include "runtime.h" | 40 #include "runtime.h" |
38 #include "scopes.h" | 41 #include "scopes.h" |
39 | 42 |
40 namespace v8 { | 43 namespace v8 { |
41 namespace internal { | 44 namespace internal { |
42 | 45 |
43 #define __ ACCESS_MASM(masm_) | 46 #define __ ACCESS_MASM(masm_) |
44 | 47 |
45 // ------------------------------------------------------------------------- | 48 // ------------------------------------------------------------------------- |
(...skipping 5229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5275 | 5278 |
5276 Load(args->at(0)); | 5279 Load(args->at(0)); |
5277 Load(args->at(1)); | 5280 Load(args->at(1)); |
5278 | 5281 |
5279 StringAddStub stub(NO_STRING_ADD_FLAGS); | 5282 StringAddStub stub(NO_STRING_ADD_FLAGS); |
5280 Result answer = frame_->CallStub(&stub, 2); | 5283 Result answer = frame_->CallStub(&stub, 2); |
5281 frame_->Push(&answer); | 5284 frame_->Push(&answer); |
5282 } | 5285 } |
5283 | 5286 |
5284 | 5287 |
| 5288 void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) { |
| 5289 ASSERT_EQ(args->length(), 4); |
| 5290 |
| 5291 // Load the arguments on the stack and call the stub. |
| 5292 Load(args->at(0)); |
| 5293 Load(args->at(1)); |
| 5294 Load(args->at(2)); |
| 5295 Load(args->at(3)); |
| 5296 RegExpExecStub stub; |
| 5297 Result result = frame_->CallStub(&stub, 4); |
| 5298 frame_->Push(&result); |
| 5299 } |
| 5300 |
| 5301 |
5285 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 5302 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
5286 if (CheckForInlineRuntimeCall(node)) { | 5303 if (CheckForInlineRuntimeCall(node)) { |
5287 return; | 5304 return; |
5288 } | 5305 } |
5289 | 5306 |
5290 ZoneList<Expression*>* args = node->arguments(); | 5307 ZoneList<Expression*>* args = node->arguments(); |
5291 Comment cmnt(masm_, "[ CallRuntime"); | 5308 Comment cmnt(masm_, "[ CallRuntime"); |
5292 Runtime::Function* function = node->function(); | 5309 Runtime::Function* function = node->function(); |
5293 | 5310 |
5294 if (function == NULL) { | 5311 if (function == NULL) { |
(...skipping 2607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7902 // Return and remove the on-stack parameters. | 7919 // Return and remove the on-stack parameters. |
7903 __ bind(&done); | 7920 __ bind(&done); |
7904 __ ret(3 * kPointerSize); | 7921 __ ret(3 * kPointerSize); |
7905 | 7922 |
7906 // Do the runtime call to allocate the arguments object. | 7923 // Do the runtime call to allocate the arguments object. |
7907 __ bind(&runtime); | 7924 __ bind(&runtime); |
7908 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); | 7925 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); |
7909 } | 7926 } |
7910 | 7927 |
7911 | 7928 |
| 7929 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 7930 // Just jump directly to runtime if regexp entry in generated code is turned |
| 7931 // off. |
| 7932 if (!FLAG_regexp_entry_native) { |
| 7933 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); |
| 7934 return; |
| 7935 } |
| 7936 |
| 7937 // Stack frame on entry. |
| 7938 // esp[0]: return address |
| 7939 // esp[4]: last_match_info (expected JSArray) |
| 7940 // esp[8]: previous index |
| 7941 // esp[12]: subject string |
| 7942 // esp[16]: JSRegExp object |
| 7943 |
| 7944 Label runtime; |
| 7945 |
| 7946 // Check that the first argument is a JSRegExp object. |
| 7947 __ mov(eax, Operand(esp, 4 * kPointerSize)); |
| 7948 ASSERT_EQ(0, kSmiTag); |
| 7949 __ test(eax, Immediate(kSmiTagMask)); |
| 7950 __ j(zero, &runtime); |
| 7951 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); |
| 7952 __ j(not_equal, &runtime); |
| 7953 // Check that the RegExp has been compiled (data contains a fixed array). |
| 7954 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
| 7955 #ifdef DEBUG |
| 7956 __ test(ecx, Immediate(kSmiTagMask)); |
| 7957 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); |
| 7958 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); |
| 7959 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); |
| 7960 #endif |
| 7961 |
| 7962 // ecx: RegExp data (FixedArray) |
| 7963 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
| 7964 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); |
| 7965 __ cmp(Operand(ebx), Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); |
| 7966 __ j(not_equal, &runtime); |
| 7967 |
| 7968 // ecx: RegExp data (FixedArray) |
| 7969 // Check that the number of captures fit in the static offsets vector buffer. |
| 7970 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 7971 // Calculate number of capture registers (number_of_captures + 1) * 2. This |
| 7972 // uses the asumption that smis are 2 * their untagged value. |
| 7973 ASSERT_EQ(0, kSmiTag); |
| 7974 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
| 7975 __ add(Operand(edx), Immediate(2)); // edx was a smi. |
| 7976 // Check that the static offsets vector buffer is large enough. |
| 7977 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); |
| 7978 __ j(above, &runtime); |
| 7979 |
| 7980 // ecx: RegExp data (FixedArray) |
| 7981 // edx: Number of capture registers |
| 7982 // Check that the second argument is a string. |
| 7983 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 7984 __ test(eax, Immediate(kSmiTagMask)); |
| 7985 __ j(zero, &runtime); |
| 7986 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); |
| 7987 __ j(NegateCondition(is_string), &runtime); |
| 7988 // Get the length of the string to ebx. |
| 7989 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
| 7990 |
| 7991 // ebx: Length of subject string |
| 7992 // ecx: RegExp data (FixedArray) |
| 7993 // edx: Number of capture registers |
| 7994 // Check that the third argument is a positive smi. |
| 7995 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| 7996 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 7997 __ j(not_zero, &runtime); |
| 7998 // Check that it is not greater than the subject string length. |
| 7999 __ SmiUntag(eax); |
| 8000 __ cmp(eax, Operand(ebx)); |
| 8001 __ j(greater, &runtime); |
| 8002 |
| 8003 // ecx: RegExp data (FixedArray) |
| 8004 // edx: Number of capture registers |
| 8005 // Check that the fourth object is a JSArray object. |
| 8006 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 8007 __ test(eax, Immediate(kSmiTagMask)); |
| 8008 __ j(zero, &runtime); |
| 8009 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
| 8010 __ j(not_equal, &runtime); |
| 8011 // Check that the JSArray is in fast case. |
| 8012 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
| 8013 __ cmp(eax, Factory::fixed_array_map()); |
| 8014 __ j(not_equal, &runtime); |
| 8015 // Check that the last match info has space for the capture registers and the |
| 8016 // additional information. |
| 8017 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); |
| 8018 __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); |
| 8019 __ cmp(edx, Operand(eax)); |
| 8020 __ j(greater, &runtime); |
| 8021 |
| 8022 // ecx: RegExp data (FixedArray) |
| 8023 // Check the representation and encoding of the subject string (only support |
| 8024 // flat ascii strings). |
| 8025 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 8026 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 8027 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 8028 __ and_(ebx, kStringRepresentationMask | kStringEncodingMask); |
| 8029 __ cmp(ebx, kSeqStringTag | kAsciiStringTag); |
| 8030 __ j(not_equal, &runtime); |
| 8031 |
| 8032 // ecx: RegExp data (FixedArray) |
| 8033 // Ensure that a RegExp stack is allocated. |
| 8034 ExternalReference address_of_regexp_stack_memory_address = |
| 8035 ExternalReference::address_of_regexp_stack_memory_address(); |
| 8036 ExternalReference address_of_regexp_stack_memory_size = |
| 8037 ExternalReference::address_of_regexp_stack_memory_size(); |
| 8038 __ mov(eax, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 8039 __ test(eax, Operand(eax)); |
| 8040 __ j(zero, &runtime, not_taken); |
| 8041 |
| 8042 // ecx: RegExp data (FixedArray) |
| 8043 // Check that the irregexp code has been generated for an ascii string. If |
| 8044 // it has the field contains a code object otherwise it contains the hole. |
| 8045 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); |
| 8046 __ CmpObjectType(edx, CODE_TYPE, ebx); |
| 8047 __ j(not_equal, &runtime); |
| 8048 |
| 8049 // Load used arguments before starting to push arguments for call to native |
| 8050 // RegExp code to avoid handling changing stack height. |
| 8051 __ mov(eax, Operand(esp, 3 * kPointerSize)); // Subject string. |
| 8052 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // Previous index. |
| 8053 __ mov(ecx, Operand(esp, 4 * kPointerSize)); // JSRegExp object. |
| 8054 __ SmiUntag(ebx); // Previous index from sim. |
| 8055 |
| 8056 // eax: subject string |
| 8057 // ebx: previous index |
| 8058 // edx: code |
| 8059 // All checks done. Now push arguments for native regexp code. |
| 8060 __ IncrementCounter(&Counters::regexp_entry_native, 1); |
| 8061 |
| 8062 // Argument 8: Indicate that this is a direct call from JavaScript. |
| 8063 __ push(Immediate(1)); |
| 8064 |
| 8065 // Argument 7: Start (high end) of backtracking stack memory area. |
| 8066 __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
| 8067 __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 8068 __ push(ecx); |
| 8069 |
| 8070 // Argument 6: At start of string? |
| 8071 __ xor_(Operand(ecx), ecx); // setcc only operated on cl (lower byte of ecx). |
| 8072 __ test(ebx, Operand(ebx)); |
| 8073 __ setcc(zero, ecx); // 1 if 0 (start of string), 0 if positive. |
| 8074 __ push(ecx); |
| 8075 |
| 8076 // Argument 5: static offsets vector buffer. |
| 8077 __ push(Immediate(ExternalReference::address_of_static_offsets_vector())); |
| 8078 |
| 8079 // Argument 4: End of string data. |
| 8080 __ mov(ecx, FieldOperand(eax, String::kLengthOffset)); |
| 8081 __ add(ecx, Operand(eax)); |
| 8082 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 8083 __ push(ecx); |
| 8084 |
| 8085 // Argument 3: Start of string data. |
| 8086 __ mov(ecx, ebx); |
| 8087 __ add(ebx, Operand(eax)); // String is ASCII. |
| 8088 __ add(Operand(ebx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 8089 __ push(ebx); |
| 8090 |
| 8091 // Argument 2: Previous index. |
| 8092 __ push(ecx); |
| 8093 |
| 8094 // Argument 1: Subject string. |
| 8095 __ push(eax); |
| 8096 |
| 8097 // Locate the code entry and call it. |
| 8098 __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 8099 __ call(Operand(edx)); |
| 8100 // Remove arguments. |
| 8101 __ add(Operand(esp), Immediate(8 * kPointerSize)); |
| 8102 |
| 8103 // Check the result. |
| 8104 Label success; |
| 8105 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); |
| 8106 __ j(equal, &success, taken); |
| 8107 Label failure; |
| 8108 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); |
| 8109 __ j(equal, &failure, taken); |
| 8110 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); |
| 8111 // If not exception it can only be retry. Handle that in the runtime system. |
| 8112 __ j(not_equal, &runtime); |
| 8113 // Result must now be exception. If there is no pending exception already a |
| 8114 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 8115 // haven't created the exception yet. Handle that in the runtime system. |
| 8116 ExternalReference pending_exception(Top::k_pending_exception_address); |
| 8117 __ mov(eax, |
| 8118 Operand::StaticVariable(ExternalReference::the_hole_value_location())); |
| 8119 __ cmp(eax, Operand::StaticVariable(pending_exception)); |
| 8120 __ j(equal, &runtime); |
| 8121 __ bind(&failure); |
| 8122 // For failure and exception return null. |
| 8123 __ mov(Operand(eax), Factory::null_value()); |
| 8124 __ ret(4 * kPointerSize); |
| 8125 |
| 8126 // Load RegExp data. |
| 8127 __ bind(&success); |
| 8128 __ mov(eax, Operand(esp, 4 * kPointerSize)); |
| 8129 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
| 8130 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 8131 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 8132 __ add(Operand(edx), Immediate(2)); // edx was a smi. |
| 8133 |
| 8134 // edx: Number of capture registers |
| 8135 // Load last_match_info which is still known to be a fast case JSArray. |
| 8136 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 8137 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
| 8138 |
| 8139 // ebx: last_match_info backing store (FixedArray) |
| 8140 // edx: number of capture registers |
| 8141 // Store the capture count. |
| 8142 __ SmiTag(edx); // Number of capture registers to smi. |
| 8143 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); |
| 8144 __ SmiUntag(edx); // Number of capture registers back from smi. |
| 8145 // Store last subject and last input. |
| 8146 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 8147 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); |
| 8148 __ mov(ecx, ebx); |
| 8149 __ RecordWrite(ecx, RegExpImpl::kLastSubjectOffset, eax, edi); |
| 8150 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 8151 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); |
| 8152 __ mov(ecx, ebx); |
| 8153 __ RecordWrite(ecx, RegExpImpl::kLastInputOffset, eax, edi); |
| 8154 |
| 8155 // Get the static offsets vector filled by the native regexp code. |
| 8156 ExternalReference address_of_static_offsets_vector = |
| 8157 ExternalReference::address_of_static_offsets_vector(); |
| 8158 __ mov(ecx, Immediate(address_of_static_offsets_vector)); |
| 8159 |
| 8160 // ebx: last_match_info backing store (FixedArray) |
| 8161 // ecx: offsets vector |
| 8162 // edx: number of capture registers |
| 8163 Label next_capture, done; |
| 8164 __ mov(eax, Operand(esp, 2 * kPointerSize)); // Read previous index. |
| 8165 // Capture register counter starts from number of capture registers and |
| 8166 // counts down until wraping after zero. |
| 8167 __ bind(&next_capture); |
| 8168 __ sub(Operand(edx), Immediate(1)); |
| 8169 __ j(negative, &done); |
| 8170 // Read the value from the static offsets vector buffer. |
| 8171 __ mov(edi, Operand(ecx, edx, times_pointer_size, 0)); |
| 8172 // Perform explicit shift |
| 8173 ASSERT_EQ(0, kSmiTag); |
| 8174 __ shl(edi, kSmiTagSize); |
| 8175 // Add previous index (from its stack slot) if value is not negative. |
| 8176 Label capture_negative; |
| 8177 // Carry flag set by shift above. |
| 8178 __ j(negative, &capture_negative, not_taken); |
| 8179 __ add(edi, Operand(eax)); // Add previous index (adding smi to smi). |
| 8180 __ bind(&capture_negative); |
| 8181 // Store the smi value in the last match info. |
| 8182 __ mov(FieldOperand(ebx, |
| 8183 edx, |
| 8184 times_pointer_size, |
| 8185 RegExpImpl::kFirstCaptureOffset), |
| 8186 edi); |
| 8187 __ jmp(&next_capture); |
| 8188 __ bind(&done); |
| 8189 |
| 8190 // Return last match info. |
| 8191 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 8192 __ ret(4 * kPointerSize); |
| 8193 |
| 8194 // Do the runtime call to execute the regexp. |
| 8195 __ bind(&runtime); |
| 8196 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); |
| 8197 } |
| 8198 |
| 8199 |
7912 void CompareStub::Generate(MacroAssembler* masm) { | 8200 void CompareStub::Generate(MacroAssembler* masm) { |
7913 Label call_builtin, done; | 8201 Label call_builtin, done; |
7914 | 8202 |
7915 // NOTICE! This code is only reached after a smi-fast-case check, so | 8203 // NOTICE! This code is only reached after a smi-fast-case check, so |
7916 // it is certain that at least one operand isn't a smi. | 8204 // it is certain that at least one operand isn't a smi. |
7917 | 8205 |
7918 if (cc_ == equal) { // Both strict and non-strict. | 8206 if (cc_ == equal) { // Both strict and non-strict. |
7919 Label slow; // Fallthrough label. | 8207 Label slow; // Fallthrough label. |
7920 // Equality is almost reflexive (everything but NaN), so start by testing | 8208 // Equality is almost reflexive (everything but NaN), so start by testing |
7921 // for "identity and not NaN". | 8209 // for "identity and not NaN". |
(...skipping 978 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8900 __ add(Operand(dest), Immediate(2)); | 9188 __ add(Operand(dest), Immediate(2)); |
8901 } | 9189 } |
8902 __ sub(Operand(count), Immediate(1)); | 9190 __ sub(Operand(count), Immediate(1)); |
8903 __ j(not_zero, &loop); | 9191 __ j(not_zero, &loop); |
8904 } | 9192 } |
8905 | 9193 |
8906 | 9194 |
8907 #undef __ | 9195 #undef __ |
8908 | 9196 |
8909 } } // namespace v8::internal | 9197 } } // namespace v8::internal |
OLD | NEW |