diff options
author | isaacs <i@izs.me> | 2012-05-29 15:05:24 -0700 |
---|---|---|
committer | isaacs <i@izs.me> | 2012-06-01 22:31:04 -0700 |
commit | cbdf3393a21690178822c2d6ce2513270d70a02e (patch) | |
tree | ebbf375e5d7aa32bf5fe988d2b3fe5fe788b404d /deps/v8/src/arm | |
parent | 0262b6d2a563e8b96f02c3066b69fed66d956675 (diff) | |
download | node-new-cbdf3393a21690178822c2d6ce2513270d70a02e.tar.gz |
Upgrade v8 to 3.11.7
Diffstat (limited to 'deps/v8/src/arm')
-rw-r--r-- | deps/v8/src/arm/builtins-arm.cc | 9 | ||||
-rw-r--r-- | deps/v8/src/arm/code-stubs-arm.cc | 35 | ||||
-rw-r--r-- | deps/v8/src/arm/codegen-arm.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/arm/full-codegen-arm.cc | 105 | ||||
-rw-r--r-- | deps/v8/src/arm/ic-arm.cc | 14 | ||||
-rw-r--r-- | deps/v8/src/arm/lithium-arm.cc | 5 | ||||
-rw-r--r-- | deps/v8/src/arm/lithium-arm.h | 9 | ||||
-rw-r--r-- | deps/v8/src/arm/lithium-codegen-arm.cc | 104 | ||||
-rw-r--r-- | deps/v8/src/arm/macro-assembler-arm.cc | 86 | ||||
-rw-r--r-- | deps/v8/src/arm/macro-assembler-arm.h | 9 | ||||
-rw-r--r-- | deps/v8/src/arm/regexp-macro-assembler-arm.cc | 170 | ||||
-rw-r--r-- | deps/v8/src/arm/regexp-macro-assembler-arm.h | 13 | ||||
-rw-r--r-- | deps/v8/src/arm/simulator-arm.h | 12 | ||||
-rw-r--r-- | deps/v8/src/arm/stub-cache-arm.cc | 50 |
14 files changed, 339 insertions, 286 deletions
diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index c99e778a7f..578bd810d4 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -114,7 +114,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm, Label* gc_required) { const int initial_capacity = JSArray::kPreallocatedArrayElements; STATIC_ASSERT(initial_capacity >= 0); - __ LoadInitialArrayMap(array_function, scratch2, scratch1); + __ LoadInitialArrayMap(array_function, scratch2, scratch1, false); // Allocate the JSArray object together with space for a fixed array with the // requested elements. @@ -208,7 +208,8 @@ static void AllocateJSArray(MacroAssembler* masm, bool fill_with_hole, Label* gc_required) { // Load the initial map from the array function. - __ LoadInitialArrayMap(array_function, scratch2, elements_array_storage); + __ LoadInitialArrayMap(array_function, scratch2, + elements_array_storage, fill_with_hole); if (FLAG_debug_code) { // Assert that array size is not zero. __ tst(array_size, array_size); @@ -440,10 +441,10 @@ static void ArrayNativeCode(MacroAssembler* masm, __ b(call_generic_code); __ bind(¬_double); - // Transition FAST_SMI_ONLY_ELEMENTS to FAST_ELEMENTS. + // Transition FAST_SMI_ELEMENTS to FAST_ELEMENTS. // r3: JSArray __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); - __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, r2, r9, diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index ad2ab7e09d..2296490d9d 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -4824,27 +4824,32 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2); // Isolates: note we add an additional parameter here (isolate pointer). - const int kRegExpExecuteArguments = 8; + const int kRegExpExecuteArguments = 9; const int kParameterRegisters = 4; __ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters); // Stack pointer now points to cell where return address is to be written. // Arguments are before that on the stack or in registers. - // Argument 8 (sp[16]): Pass current isolate address. + // Argument 9 (sp[20]): Pass current isolate address. __ mov(r0, Operand(ExternalReference::isolate_address())); - __ str(r0, MemOperand(sp, 4 * kPointerSize)); + __ str(r0, MemOperand(sp, 5 * kPointerSize)); - // Argument 7 (sp[12]): Indicate that this is a direct call from JavaScript. + // Argument 8 (sp[16]): Indicate that this is a direct call from JavaScript. __ mov(r0, Operand(1)); - __ str(r0, MemOperand(sp, 3 * kPointerSize)); + __ str(r0, MemOperand(sp, 4 * kPointerSize)); - // Argument 6 (sp[8]): Start (high end) of backtracking stack memory area. + // Argument 7 (sp[12]): Start (high end) of backtracking stack memory area. __ mov(r0, Operand(address_of_regexp_stack_memory_address)); __ ldr(r0, MemOperand(r0, 0)); __ mov(r2, Operand(address_of_regexp_stack_memory_size)); __ ldr(r2, MemOperand(r2, 0)); __ add(r0, r0, Operand(r2)); + __ str(r0, MemOperand(sp, 3 * kPointerSize)); + + // Argument 6: Set the number of capture registers to zero to force global + // regexps to behave as non-global. This does not affect non-global regexps. + __ mov(r0, Operand(0)); __ str(r0, MemOperand(sp, 2 * kPointerSize)); // Argument 5 (sp[4]): static offsets vector buffer. @@ -4893,7 +4898,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Check the result. Label success; - __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); + __ cmp(r0, Operand(1)); + // We expect exactly one result since we force the called regexp to behave + // as non-global. __ b(eq, &success); Label failure; __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); @@ -7095,8 +7102,8 @@ static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { // KeyedStoreStubCompiler::GenerateStoreFastElement. { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET }, { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET }, - // ElementsTransitionGenerator::GenerateSmiOnlyToObject - // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble + // ElementsTransitionGenerator::GenerateMapChangeElementTransition + // and ElementsTransitionGenerator::GenerateSmiToDouble // and ElementsTransitionGenerator::GenerateDoubleToObject { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET }, { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET }, @@ -7359,9 +7366,9 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { Label fast_elements; __ CheckFastElements(r2, r5, &double_elements); - // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS + // FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS __ JumpIfSmi(r0, &smi_element); - __ CheckFastSmiOnlyElements(r2, r5, &fast_elements); + __ CheckFastSmiElements(r2, r5, &fast_elements); // Store into the array literal requires a elements transition. Call into // the runtime. @@ -7373,7 +7380,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { __ Push(r5, r4); __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); - // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. + // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object. __ bind(&fast_elements); __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); @@ -7384,8 +7391,8 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); __ Ret(); - // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or - // FAST_ELEMENTS, and value is Smi. + // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS, + // and value is Smi. __ bind(&smi_element); __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset)); __ add(r6, r5, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index befd8f2de7..e00afb9035 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -73,7 +73,7 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { // ------------------------------------------------------------------------- // Code generators -void ElementsTransitionGenerator::GenerateSmiOnlyToObject( +void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : value @@ -96,7 +96,7 @@ void ElementsTransitionGenerator::GenerateSmiOnlyToObject( } -void ElementsTransitionGenerator::GenerateSmiOnlyToDouble( +void ElementsTransitionGenerator::GenerateSmiToDouble( MacroAssembler* masm, Label* fail) { // ----------- S t a t e ------------- // -- r0 : value diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 9f448720cc..2a5887a953 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -1701,7 +1701,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ASSERT_EQ(2, constant_elements->length()); ElementsKind constant_elements_kind = static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); - bool has_fast_elements = constant_elements_kind == FAST_ELEMENTS; + bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind); Handle<FixedArrayBase> constant_elements_values( FixedArrayBase::cast(constant_elements->get(1))); @@ -1722,8 +1722,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); } else { - ASSERT(constant_elements_kind == FAST_ELEMENTS || - constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || + ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) || FLAG_smi_only_arrays); FastCloneShallowArrayStub::Mode mode = has_fast_elements ? FastCloneShallowArrayStub::CLONE_ELEMENTS @@ -1751,7 +1750,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } VisitForAccumulatorValue(subexpr); - if (constant_elements_kind == FAST_ELEMENTS) { + if (IsFastObjectElementsKind(constant_elements_kind)) { int offset = FixedArray::kHeaderSize + (i * kPointerSize); __ ldr(r6, MemOperand(sp)); // Copy of array literal. __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); @@ -3466,104 +3465,6 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { } -void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) { - ZoneList<Expression*>* args = expr->arguments(); - ASSERT(args->length() == 3); - VisitForStackValue(args->at(0)); - VisitForStackValue(args->at(1)); - VisitForStackValue(args->at(2)); - Label done; - Label slow_case; - Register object = r0; - Register index1 = r1; - Register index2 = r2; - Register elements = r3; - Register scratch1 = r4; - Register scratch2 = r5; - - __ ldr(object, MemOperand(sp, 2 * kPointerSize)); - // Fetch the map and check if array is in fast case. - // Check that object doesn't require security checks and - // has no indexed interceptor. - __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE); - __ b(ne, &slow_case); - // Map is now in scratch1. - - __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset)); - __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask)); - __ b(ne, &slow_case); - - // Check the object's elements are in fast case and writable. - __ ldr(elements, FieldMemOperand(object, JSObject::kElementsOffset)); - __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); - __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); - __ cmp(scratch1, ip); - __ b(ne, &slow_case); - - // Check that both indices are smis. - __ ldr(index1, MemOperand(sp, 1 * kPointerSize)); - __ ldr(index2, MemOperand(sp, 0)); - __ JumpIfNotBothSmi(index1, index2, &slow_case); - - // Check that both indices are valid. - __ ldr(scratch1, FieldMemOperand(object, JSArray::kLengthOffset)); - __ cmp(scratch1, index1); - __ cmp(scratch1, index2, hi); - __ b(ls, &slow_case); - - // Bring the address of the elements into index1 and index2. - __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(index1, - scratch1, - Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize)); - __ add(index2, - scratch1, - Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); - - // Swap elements. - __ ldr(scratch1, MemOperand(index1, 0)); - __ ldr(scratch2, MemOperand(index2, 0)); - __ str(scratch1, MemOperand(index2, 0)); - __ str(scratch2, MemOperand(index1, 0)); - - Label no_remembered_set; - __ CheckPageFlag(elements, - scratch1, - 1 << MemoryChunk::SCAN_ON_SCAVENGE, - ne, - &no_remembered_set); - // Possible optimization: do a check that both values are Smis - // (or them and test against Smi mask.) - - // We are swapping two objects in an array and the incremental marker never - // pauses in the middle of scanning a single object. Therefore the - // incremental marker is not disturbed, so we don't need to call the - // RecordWrite stub that notifies the incremental marker. - __ RememberedSetHelper(elements, - index1, - scratch2, - kDontSaveFPRegs, - MacroAssembler::kFallThroughAtEnd); - __ RememberedSetHelper(elements, - index2, - scratch2, - kDontSaveFPRegs, - MacroAssembler::kFallThroughAtEnd); - - __ bind(&no_remembered_set); - // We are done. Drop elements from the stack, and return undefined. - __ Drop(3); - __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); - __ jmp(&done); - - __ bind(&slow_case); - __ CallRuntime(Runtime::kSwapElements, 3); - - __ bind(&done); - context()->Plug(r0); -} - - void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { ZoneList<Expression*>* args = expr->arguments(); ASSERT_EQ(2, args->length()); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index c12c16754d..fd93480986 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -1249,7 +1249,7 @@ void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) { // Must return the modified receiver in r0. if (!FLAG_trace_elements_transitions) { Label fail; - ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, &fail); __ mov(r0, r2); __ Ret(); __ bind(&fail); @@ -1462,27 +1462,27 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex); __ b(ne, &non_double_value); - // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS -> + // Value is a double. Transition FAST_SMI_ELEMENTS -> // FAST_DOUBLE_ELEMENTS and complete the store. - __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, r4, &slow); ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 - ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow); + ElementsTransitionGenerator::GenerateSmiToDouble(masm, &slow); __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ jmp(&fast_double_without_map_check); __ bind(&non_double_value); - // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS - __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, + // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, receiver_map, r4, &slow); ASSERT(receiver_map.is(r3)); // Transition code expects map in r3 - ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm); + ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm); __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ jmp(&finish_object_store); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 5c60f5321c..c97831aa13 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -2082,8 +2082,9 @@ LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoTransitionElementsKind( HTransitionElementsKind* instr) { - if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS && - instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) { + ElementsKind from_kind = instr->original_map()->elements_kind(); + ElementsKind to_kind = instr->transitioned_map()->elements_kind(); + if (IsSimpleMapChangeTransition(from_kind, to_kind)) { LOperand* object = UseRegister(instr->object()); LOperand* new_map_reg = TempRegister(); LTransitionElementsKind* result = diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index ec8aac8036..dbae81310c 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -1236,6 +1236,7 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; @@ -1252,13 +1253,13 @@ class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { public: - LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, - LOperand* key) { + LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LOperand* key) { inputs_[0] = external_pointer; inputs_[1] = key; } @@ -1272,6 +1273,7 @@ class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; @@ -1740,6 +1742,7 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> { LOperand* object() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; @@ -1762,6 +1765,7 @@ class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } + uint32_t additional_index() const { return hydrogen()->index_offset(); } bool NeedsCanonicalization() { return hydrogen()->NeedsCanonicalization(); } }; @@ -1806,6 +1810,7 @@ class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + uint32_t additional_index() const { return hydrogen()->index_offset(); } }; diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index bf11ab9bea..fd4b3e8408 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -2696,8 +2696,10 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { __ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset)); __ ubfx(scratch, scratch, Map::kElementsKindShift, Map::kElementsKindBitCount); - __ cmp(scratch, Operand(FAST_ELEMENTS)); - __ b(eq, &done); + __ cmp(scratch, Operand(GetInitialFastElementsKind())); + __ b(lt, &fail); + __ cmp(scratch, Operand(TERMINAL_FAST_ELEMENTS_KIND)); + __ b(le, &done); __ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND)); __ b(lt, &fail); __ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND)); @@ -2744,7 +2746,9 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { // Load the result. __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); - __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize)); + uint32_t offset = FixedArray::kHeaderSize + + (instr->additional_index() << kPointerSizeLog2); + __ ldr(result, FieldMemOperand(scratch, offset)); // Check for the hole value. if (instr->hydrogen()->RequiresHoleCheck()) { @@ -2776,18 +2780,21 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( } Operand operand = key_is_constant - ? Operand(constant_key * (1 << shift_size) + + ? Operand(((constant_key + instr->additional_index()) << shift_size) + FixedDoubleArray::kHeaderSize - kHeapObjectTag) : Operand(key, LSL, shift_size); __ add(elements, elements, operand); if (!key_is_constant) { __ add(elements, elements, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) + + (instr->additional_index() << shift_size))); } - __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); - __ cmp(scratch, Operand(kHoleNanUpper32)); - DeoptimizeIf(eq, instr->environment()); + if (instr->hydrogen()->RequiresHoleCheck()) { + __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); + __ cmp(scratch, Operand(kHoleNanUpper32)); + DeoptimizeIf(eq, instr->environment()); + } __ vldr(result, elements, 0); } @@ -2809,26 +2816,33 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( key = ToRegister(instr->key()); } int shift_size = ElementsKindToShiftSize(elements_kind); + int additional_offset = instr->additional_index() << shift_size; if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { CpuFeatures::Scope scope(VFP3); DwVfpRegister result = ToDoubleRegister(instr->result()); Operand operand = key_is_constant - ? Operand(constant_key * (1 << shift_size)) + ? Operand(constant_key << shift_size) : Operand(key, LSL, shift_size); __ add(scratch0(), external_pointer, operand); if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - __ vldr(result.low(), scratch0(), 0); + __ vldr(result.low(), scratch0(), additional_offset); __ vcvt_f64_f32(result, result.low()); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS - __ vldr(result, scratch0(), 0); + __ vldr(result, scratch0(), additional_offset); } } else { Register result = ToRegister(instr->result()); + if (instr->additional_index() != 0 && !key_is_constant) { + __ add(scratch0(), key, Operand(instr->additional_index())); + } MemOperand mem_operand(key_is_constant - ? MemOperand(external_pointer, constant_key * (1 << shift_size)) - : MemOperand(external_pointer, key, LSL, shift_size)); + ? MemOperand(external_pointer, + (constant_key << shift_size) + additional_offset) + : (instr->additional_index() == 0 + ? MemOperand(external_pointer, key, LSL, shift_size) + : MemOperand(external_pointer, scratch0(), LSL, shift_size))); switch (elements_kind) { case EXTERNAL_BYTE_ELEMENTS: __ ldrsb(result, mem_operand); @@ -2856,9 +2870,12 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( break; case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3726,10 +3743,16 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); int offset = - ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; + (ToInteger32(const_operand) + instr->additional_index()) * kPointerSize + + FixedArray::kHeaderSize; __ str(value, FieldMemOperand(elements, offset)); } else { __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); + if (instr->additional_index() != 0) { + __ add(scratch, + scratch, + Operand(instr->additional_index() << kPointerSizeLog2)); + } __ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize)); } @@ -3771,7 +3794,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( } int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); Operand operand = key_is_constant - ? Operand(constant_key * (1 << shift_size) + + ? Operand((constant_key << shift_size) + FixedDoubleArray::kHeaderSize - kHeapObjectTag) : Operand(key, LSL, shift_size); __ add(scratch, elements, operand); @@ -3789,7 +3812,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( vs); } - __ vstr(value, scratch, 0); + __ vstr(value, scratch, instr->additional_index() << shift_size); } @@ -3810,25 +3833,33 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( key = ToRegister(instr->key()); } int shift_size = ElementsKindToShiftSize(elements_kind); + int additional_offset = instr->additional_index() << shift_size; if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { CpuFeatures::Scope scope(VFP3); DwVfpRegister value(ToDoubleRegister(instr->value())); - Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size)) + Operand operand(key_is_constant ? Operand(constant_key << shift_size) : Operand(key, LSL, shift_size)); __ add(scratch0(), external_pointer, operand); if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { __ vcvt_f32_f64(double_scratch0().low(), value); - __ vstr(double_scratch0().low(), scratch0(), 0); + __ vstr(double_scratch0().low(), scratch0(), additional_offset); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS - __ vstr(value, scratch0(), 0); + __ vstr(value, scratch0(), additional_offset); } } else { Register value(ToRegister(instr->value())); + if (instr->additional_index() != 0 && !key_is_constant) { + __ add(scratch0(), key, Operand(instr->additional_index())); + } MemOperand mem_operand(key_is_constant - ? MemOperand(external_pointer, constant_key * (1 << shift_size)) - : MemOperand(external_pointer, key, LSL, shift_size)); + ? MemOperand(external_pointer, + ((constant_key + instr->additional_index()) + << shift_size)) + : (instr->additional_index() == 0 + ? MemOperand(external_pointer, key, LSL, shift_size) + : MemOperand(external_pointer, scratch0(), LSL, shift_size))); switch (elements_kind) { case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: @@ -3847,7 +3878,10 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( case EXTERNAL_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3884,20 +3918,22 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ cmp(scratch, Operand(from_map)); __ b(ne, ¬_applicable); __ mov(new_map_reg, Operand(to_map)); - if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { + + if (IsSimpleMapChangeTransition(from_kind, to_kind)) { __ str(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); // Write barrier. __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, scratch, kLRHasBeenSaved, kDontSaveFPRegs); - } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && - to_kind == FAST_DOUBLE_ELEMENTS) { + } else if (IsFastSmiElementsKind(from_kind) && + IsFastDoubleElementsKind(to_kind)) { Register fixed_object_reg = ToRegister(instr->temp_reg()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); __ mov(fixed_object_reg, object_reg); CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), RelocInfo::CODE_TARGET, instr); - } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { + } else if (IsFastDoubleElementsKind(from_kind) && + IsFastObjectElementsKind(to_kind)) { Register fixed_object_reg = ToRegister(instr->temp_reg()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); @@ -4671,8 +4707,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { // Deopt if the array literal boilerplate ElementsKind is of a type different // than the expected one. The check isn't necessary if the boilerplate has - // already been converted to FAST_ELEMENTS. - if (boilerplate_elements_kind != FAST_ELEMENTS) { + // already been converted to TERMINAL_FAST_ELEMENTS_KIND. + if (CanTransitionToMoreGeneralFastElementsKind( + boilerplate_elements_kind, true)) { __ LoadHeapObject(r1, instr->hydrogen()->boilerplate_object()); // Load map into r2. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); @@ -4823,10 +4860,11 @@ void LCodeGen::DoFastLiteral(LFastLiteral* instr) { ElementsKind boilerplate_elements_kind = instr->hydrogen()->boilerplate()->GetElementsKind(); - // Deopt if the literal boilerplate ElementsKind is of a type different than - // the expected one. The check isn't necessary if the boilerplate has already - // been converted to FAST_ELEMENTS. - if (boilerplate_elements_kind != FAST_ELEMENTS) { + // Deopt if the array literal boilerplate ElementsKind is of a type different + // than the expected one. The check isn't necessary if the boilerplate has + // already been converted to TERMINAL_FAST_ELEMENTS_KIND. + if (CanTransitionToMoreGeneralFastElementsKind( + boilerplate_elements_kind, true)) { __ LoadHeapObject(r1, instr->hydrogen()->boilerplate()); // Load map into r2. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 4da2fece03..b4aec54555 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1868,10 +1868,12 @@ void MacroAssembler::CompareRoot(Register obj, void MacroAssembler::CheckFastElements(Register map, Register scratch, Label* fail) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); - STATIC_ASSERT(FAST_ELEMENTS == 1); + STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); + STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + STATIC_ASSERT(FAST_ELEMENTS == 2); + STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); - cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue)); + cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); b(hi, fail); } @@ -1879,22 +1881,25 @@ void MacroAssembler::CheckFastElements(Register map, void MacroAssembler::CheckFastObjectElements(Register map, Register scratch, Label* fail) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); - STATIC_ASSERT(FAST_ELEMENTS == 1); + STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); + STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + STATIC_ASSERT(FAST_ELEMENTS == 2); + STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); - cmp(scratch, Operand(Map::kMaximumBitField2FastSmiOnlyElementValue)); + cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); b(ls, fail); - cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue)); + cmp(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue)); b(hi, fail); } -void MacroAssembler::CheckFastSmiOnlyElements(Register map, - Register scratch, - Label* fail) { - STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0); +void MacroAssembler::CheckFastSmiElements(Register map, + Register scratch, + Label* fail) { + STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); + STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset)); - cmp(scratch, Operand(Map::kMaximumBitField2FastSmiOnlyElementValue)); + cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue)); b(hi, fail); } @@ -1997,22 +2002,17 @@ void MacroAssembler::CompareMap(Register obj, ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); cmp(scratch, Operand(map)); if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) { - Map* transitioned_fast_element_map( - map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL)); - ASSERT(transitioned_fast_element_map == NULL || - map->elements_kind() != FAST_ELEMENTS); - if (transitioned_fast_element_map != NULL) { - b(eq, early_success); - cmp(scratch, Operand(Handle<Map>(transitioned_fast_element_map))); - } - - Map* transitioned_double_map( - map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL)); - ASSERT(transitioned_double_map == NULL || - map->elements_kind() == FAST_SMI_ONLY_ELEMENTS); - if (transitioned_double_map != NULL) { - b(eq, early_success); - cmp(scratch, Operand(Handle<Map>(transitioned_double_map))); + ElementsKind kind = map->elements_kind(); + if (IsFastElementsKind(kind)) { + bool packed = IsFastPackedElementsKind(kind); + Map* current_map = *map; + while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) { + kind = GetNextMoreGeneralFastElementsKind(kind, packed); + current_map = current_map->LookupElementsTransitionMap(kind, NULL); + if (!current_map) break; + b(eq, early_success); + cmp(scratch, Operand(Handle<Map>(current_map))); + } } } } @@ -2865,28 +2865,38 @@ void MacroAssembler::LoadTransitionedArrayMapConditional( ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); // Check that the function's map is the same as the expected cached map. - int expected_index = - Context::GetContextMapIndexFromElementsKind(expected_kind); - ldr(ip, MemOperand(scratch, Context::SlotOffset(expected_index))); - cmp(map_in_out, ip); + ldr(scratch, + MemOperand(scratch, + Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX))); + size_t offset = expected_kind * kPointerSize + + FixedArrayBase::kHeaderSize; + cmp(map_in_out, scratch); b(ne, no_map_match); // Use the transitioned cached map. - int trans_index = - Context::GetContextMapIndexFromElementsKind(transitioned_kind); - ldr(map_in_out, MemOperand(scratch, Context::SlotOffset(trans_index))); + offset = transitioned_kind * kPointerSize + + FixedArrayBase::kHeaderSize; + ldr(map_in_out, FieldMemOperand(scratch, offset)); } void MacroAssembler::LoadInitialArrayMap( - Register function_in, Register scratch, Register map_out) { + Register function_in, Register scratch, + Register map_out, bool can_have_holes) { ASSERT(!function_in.is(map_out)); Label done; ldr(map_out, FieldMemOperand(function_in, JSFunction::kPrototypeOrInitialMapOffset)); if (!FLAG_smi_only_arrays) { - LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, - FAST_ELEMENTS, + ElementsKind kind = can_have_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; + LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + kind, + map_out, + scratch, + &done); + } else if (can_have_holes) { + LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, + FAST_HOLEY_SMI_ELEMENTS, map_out, scratch, &done); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 360f4c128c..b93aba1f51 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -512,7 +512,8 @@ class MacroAssembler: public Assembler { // Load the initial map for new Arrays from a JSFunction. void LoadInitialArrayMap(Register function_in, Register scratch, - Register map_out); + Register map_out, + bool can_have_holes); void LoadGlobalFunction(int index, Register function); @@ -802,9 +803,9 @@ class MacroAssembler: public Assembler { // Check if a map for a JSObject indicates that the object has fast smi only // elements. Jump to the specified label if it does not. - void CheckFastSmiOnlyElements(Register map, - Register scratch, - Label* fail); + void CheckFastSmiElements(Register map, + Register scratch, + Label* fail); // Check to see if maybe_number can be stored as a double in // FastDoubleElements. If it can, store it at the index specified by key in diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index a833624ceb..11790e5183 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -43,45 +43,49 @@ namespace internal { #ifndef V8_INTERPRETED_REGEXP /* * This assembler uses the following register assignment convention + * - r4 : Temporarily stores the index of capture start after a matching pass + * for a global regexp. * - r5 : Pointer to current code object (Code*) including heap object tag. * - r6 : Current position in input, as negative offset from end of string. * Please notice that this is the byte offset, not the character offset! * - r7 : Currently loaded character. Must be loaded using * LoadCurrentCharacter before using any of the dispatch methods. - * - r8 : points to tip of backtrack stack + * - r8 : Points to tip of backtrack stack * - r9 : Unused, might be used by C code and expected unchanged. * - r10 : End of input (points to byte after last character in input). * - r11 : Frame pointer. Used to access arguments, local variables and * RegExp registers. * - r12 : IP register, used by assembler. Very volatile. - * - r13/sp : points to tip of C stack. + * - r13/sp : Points to tip of C stack. * * The remaining registers are free for computations. * Each call to a public method should retain this convention. * * The stack will have the following structure: - * - fp[52] Isolate* isolate (Address of the current isolate) - * - fp[48] direct_call (if 1, direct call from JavaScript code, - * if 0, call through the runtime system). - * - fp[44] stack_area_base (High end of the memory area to use as - * backtracking stack). + * - fp[56] Isolate* isolate (address of the current isolate) + * - fp[52] direct_call (if 1, direct call from JavaScript code, + * if 0, call through the runtime system). + * - fp[48] stack_area_base (high end of the memory area to use as + * backtracking stack). + * - fp[44] capture array size (may fit multiple sets of matches) * - fp[40] int* capture_array (int[num_saved_registers_], for output). * - fp[36] secondary link/return address used by native call. * --- sp when called --- - * - fp[32] return address (lr). - * - fp[28] old frame pointer (r11). + * - fp[32] return address (lr). + * - fp[28] old frame pointer (r11). * - fp[0..24] backup of registers r4..r10. * --- frame pointer ---- - * - fp[-4] end of input (Address of end of string). - * - fp[-8] start of input (Address of first character in string). + * - fp[-4] end of input (address of end of string). + * - fp[-8] start of input (address of first character in string). * - fp[-12] start index (character index of start). * - fp[-16] void* input_string (location of a handle containing the string). - * - fp[-20] Offset of location before start of input (effectively character + * - fp[-20] success counter (only for global regexps to count matches). + * - fp[-24] Offset of location before start of input (effectively character * position -1). Used to initialize capture registers to a * non-position. - * - fp[-24] At start (if 1, we are starting at the start of the + * - fp[-28] At start (if 1, we are starting at the start of the * string, otherwise 0) - * - fp[-28] register 0 (Only positions must be stored in the first + * - fp[-32] register 0 (Only positions must be stored in the first * - register 1 num_saved_registers_ registers) * - ... * - register num_registers-1 @@ -197,9 +201,9 @@ void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) { void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) { Label not_at_start; // Did we start the match at the start of the string at all? - __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); + __ ldr(r0, MemOperand(frame_pointer(), kStartIndex)); __ cmp(r0, Operand(0, RelocInfo::NONE)); - BranchOrBacktrack(eq, ¬_at_start); + BranchOrBacktrack(ne, ¬_at_start); // If we did, are we still at the start of the input? __ ldr(r1, MemOperand(frame_pointer(), kInputStart)); @@ -212,9 +216,9 @@ void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) { void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) { // Did we start the match at the start of the string at all? - __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); + __ ldr(r0, MemOperand(frame_pointer(), kStartIndex)); __ cmp(r0, Operand(0, RelocInfo::NONE)); - BranchOrBacktrack(eq, on_not_at_start); + BranchOrBacktrack(ne, on_not_at_start); // If we did, are we still at the start of the input? __ ldr(r1, MemOperand(frame_pointer(), kInputStart)); __ add(r0, end_of_input_address(), Operand(current_input_offset())); @@ -655,6 +659,7 @@ void RegExpMacroAssemblerARM::Fail() { Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { + Label return_r0; // Finalize code - write the entry point code now we know how many // registers we need. @@ -678,8 +683,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { // Set frame pointer in space for it if this is not a direct call // from generated code. __ add(frame_pointer(), sp, Operand(4 * kPointerSize)); + __ mov(r0, Operand(0, RelocInfo::NONE)); + __ push(r0); // Make room for success counter and initialize it to 0. __ push(r0); // Make room for "position - 1" constant (value is irrelevant). - __ push(r0); // Make room for "at start" constant (value is irrelevant). // Check if we have space on the stack for registers. Label stack_limit_hit; Label stack_ok; @@ -698,13 +704,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { // Exit with OutOfMemory exception. There is not enough space on the stack // for our working registers. __ mov(r0, Operand(EXCEPTION)); - __ jmp(&exit_label_); + __ jmp(&return_r0); __ bind(&stack_limit_hit); CallCheckStackGuardState(r0); __ cmp(r0, Operand(0, RelocInfo::NONE)); // If returned value is non-zero, we exit with the returned value as result. - __ b(ne, &exit_label_); + __ b(ne, &return_r0); __ bind(&stack_ok); @@ -725,41 +731,45 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { // position registers. __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne)); - // Determine whether the start index is zero, that is at the start of the - // string, and store that value in a local variable. - __ cmp(r1, Operand(0)); - __ mov(r1, Operand(1), LeaveCC, eq); - __ mov(r1, Operand(0, RelocInfo::NONE), LeaveCC, ne); - __ str(r1, MemOperand(frame_pointer(), kAtStart)); + // Initialize code pointer register + __ mov(code_pointer(), Operand(masm_->CodeObject())); + + Label load_char_start_regexp, start_regexp; + // Load newline if index is at start, previous character otherwise. + __ cmp(r1, Operand(0, RelocInfo::NONE)); + __ b(ne, &load_char_start_regexp); + __ mov(current_character(), Operand('\n'), LeaveCC, eq); + __ jmp(&start_regexp); + + // Global regexp restarts matching here. + __ bind(&load_char_start_regexp); + // Load previous char as initial value of current character register. + LoadCurrentCharacterUnchecked(-1, 1); + __ bind(&start_regexp); + // Initialize on-stack registers. if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. // Fill saved registers with initial value = start offset - 1 - - // Address of register 0. - __ add(r1, frame_pointer(), Operand(kRegisterZero)); - __ mov(r2, Operand(num_saved_registers_)); - Label init_loop; - __ bind(&init_loop); - __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex)); - __ sub(r2, r2, Operand(1), SetCC); - __ b(ne, &init_loop); + if (num_saved_registers_ > 8) { + // Address of register 0. + __ add(r1, frame_pointer(), Operand(kRegisterZero)); + __ mov(r2, Operand(num_saved_registers_)); + Label init_loop; + __ bind(&init_loop); + __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex)); + __ sub(r2, r2, Operand(1), SetCC); + __ b(ne, &init_loop); + } else { + for (int i = 0; i < num_saved_registers_; i++) { + __ str(r0, register_location(i)); + } + } } // Initialize backtrack stack pointer. __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); - // Initialize code pointer register - __ mov(code_pointer(), Operand(masm_->CodeObject())); - // Load previous char as initial value of current character register. - Label at_start; - __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); - __ cmp(r0, Operand(0, RelocInfo::NONE)); - __ b(ne, &at_start); - LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. - __ jmp(&start_label_); - __ bind(&at_start); - __ mov(current_character(), Operand('\n')); - __ jmp(&start_label_); + __ jmp(&start_label_); // Exit code: if (success_label_.is_linked()) { @@ -786,6 +796,10 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { for (int i = 0; i < num_saved_registers_; i += 2) { __ ldr(r2, register_location(i)); __ ldr(r3, register_location(i + 1)); + if (global()) { + // Keep capture start in r4 for the zero-length check later. + __ mov(r4, r2); + } if (mode_ == UC16) { __ add(r2, r1, Operand(r2, ASR, 1)); __ add(r3, r1, Operand(r3, ASR, 1)); @@ -797,10 +811,54 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); } } - __ mov(r0, Operand(SUCCESS)); + + if (global()) { + // Restart matching if the regular expression is flagged as global. + __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures)); + __ ldr(r1, MemOperand(frame_pointer(), kNumOutputRegisters)); + __ ldr(r2, MemOperand(frame_pointer(), kRegisterOutput)); + // Increment success counter. + __ add(r0, r0, Operand(1)); + __ str(r0, MemOperand(frame_pointer(), kSuccessfulCaptures)); + // Capture results have been stored, so the number of remaining global + // output registers is reduced by the number of stored captures. + __ sub(r1, r1, Operand(num_saved_registers_)); + // Check whether we have enough room for another set of capture results. + __ cmp(r1, Operand(num_saved_registers_)); + __ b(lt, &return_r0); + + __ str(r1, MemOperand(frame_pointer(), kNumOutputRegisters)); + // Advance the location for output. + __ add(r2, r2, Operand(num_saved_registers_ * kPointerSize)); + __ str(r2, MemOperand(frame_pointer(), kRegisterOutput)); + + // Prepare r0 to initialize registers with its value in the next run. + __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne)); + // Special case for zero-length matches. + // r4: capture start index + __ cmp(current_input_offset(), r4); + // Not a zero-length match, restart. + __ b(ne, &load_char_start_regexp); + // Offset from the end is zero if we already reached the end. + __ cmp(current_input_offset(), Operand(0)); + __ b(eq, &exit_label_); + // Advance current position after a zero-length match. + __ add(current_input_offset(), + current_input_offset(), + Operand((mode_ == UC16) ? 2 : 1)); + __ b(&load_char_start_regexp); + } else { + __ mov(r0, Operand(SUCCESS)); + } } + // Exit and return r0 __ bind(&exit_label_); + if (global()) { + __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures)); + } + + __ bind(&return_r0); // Skip sp past regexp registers and local variables.. __ mov(sp, frame_pointer()); // Restore registers r4..r11 and return (restoring lr to pc). @@ -822,7 +880,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { __ cmp(r0, Operand(0, RelocInfo::NONE)); // If returning non-zero, we should end execution with the given // result as return value. - __ b(ne, &exit_label_); + __ b(ne, &return_r0); // String might have moved: Reload end of string from frame. __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); @@ -859,7 +917,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { __ bind(&exit_with_exception); // Exit with Result EXCEPTION(-1) to signal thrown exception. __ mov(r0, Operand(EXCEPTION)); - __ jmp(&exit_label_); + __ jmp(&return_r0); } CodeDesc code_desc; @@ -1014,8 +1072,9 @@ void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) { } -void RegExpMacroAssemblerARM::Succeed() { +bool RegExpMacroAssemblerARM::Succeed() { __ jmp(&success_label_); + return global(); } @@ -1307,8 +1366,9 @@ void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset, int characters) { Register offset = current_input_offset(); if (cp_offset != 0) { - __ add(r0, current_input_offset(), Operand(cp_offset * char_size())); - offset = r0; + // r4 is not being used to store the capture start index at this point. + __ add(r4, current_input_offset(), Operand(cp_offset * char_size())); + offset = r4; } // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU // and the operating system running on the target allow it. diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index 14f984f567..f2d5c55694 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -113,7 +113,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { virtual void ReadStackPointerFromRegister(int reg); virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); - virtual void Succeed(); + virtual bool Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void ClearRegisters(int reg_from, int reg_to); virtual void WriteStackPointerToRegister(int reg); @@ -137,7 +137,8 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { static const int kSecondaryReturnAddress = kReturnAddress + kPointerSize; // Stack parameters placed by caller. static const int kRegisterOutput = kSecondaryReturnAddress + kPointerSize; - static const int kStackHighEnd = kRegisterOutput + kPointerSize; + static const int kNumOutputRegisters = kRegisterOutput + kPointerSize; + static const int kStackHighEnd = kNumOutputRegisters + kPointerSize; static const int kDirectCall = kStackHighEnd + kPointerSize; static const int kIsolate = kDirectCall + kPointerSize; @@ -149,10 +150,10 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { static const int kInputString = kStartIndex - kPointerSize; // When adding local variables remember to push space for them in // the frame in GetCode. - static const int kInputStartMinusOne = kInputString - kPointerSize; - static const int kAtStart = kInputStartMinusOne - kPointerSize; + static const int kSuccessfulCaptures = kInputString - kPointerSize; + static const int kInputStartMinusOne = kSuccessfulCaptures - kPointerSize; // First register address. Following registers are below it on the stack. - static const int kRegisterZero = kAtStart - kPointerSize; + static const int kRegisterZero = kInputStartMinusOne - kPointerSize; // Initial size of code buffer. static const size_t kRegExpCodeSize = 1024; diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index 585f1e0176..d1cad15bd0 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -49,16 +49,16 @@ namespace internal { (entry(p0, p1, p2, p3, p4)) typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*, - void*, int*, Address, int, Isolate*); + void*, int*, int, Address, int, Isolate*); // Call the generated regexp code directly. The code at the entry address // should act as a function matching the type arm_regexp_matcher. // The fifth argument is a dummy that reserves the space used for // the return address added by the ExitFrame in native calls. -#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ (FUNCTION_CAST<arm_regexp_matcher>(entry)( \ - p0, p1, p2, p3, NULL, p4, p5, p6, p7)) + p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)) #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ reinterpret_cast<TryCatch*>(try_catch_address) @@ -401,9 +401,9 @@ class Simulator { reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \ FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) -#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ Simulator::current(Isolate::Current())->Call( \ - entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7) + entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8) #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ try_catch_address == NULL ? \ diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 49c0982301..a024d79800 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -1581,16 +1581,29 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall( __ jmp(&fast_object); // In case of fast smi-only, convert to fast object, otherwise bail out. __ bind(¬_fast_object); - __ CheckFastSmiOnlyElements(r3, r7, &call_builtin); + __ CheckFastSmiElements(r3, r7, &call_builtin); // edx: receiver // r3: map - __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS, + Label try_holey_map; + __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS, r3, r7, + &try_holey_map); + __ mov(r2, receiver); + ElementsTransitionGenerator:: + GenerateMapChangeElementsTransition(masm()); + __ jmp(&fast_object); + + __ bind(&try_holey_map); + __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS, + FAST_HOLEY_ELEMENTS, + r3, + r7, &call_builtin); __ mov(r2, receiver); - ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm()); + ElementsTransitionGenerator:: + GenerateMapChangeElementsTransition(masm()); __ bind(&fast_object); } else { __ CheckFastObjectElements(r3, r3, &call_builtin); @@ -3372,8 +3385,11 @@ static bool IsElementTypeSigned(ElementsKind elements_kind) { case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3497,8 +3513,11 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( } break; case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3838,8 +3857,11 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( } break; case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3902,8 +3924,11 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -4042,8 +4067,11 @@ void KeyedStoreStubCompiler::GenerateStoreExternalArray( case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -4225,7 +4253,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( // Check that the key is a smi or a heap number convertible to a smi. GenerateSmiKeyCheck(masm, key_reg, r4, r5, d1, &miss_force_generic); - if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { + if (IsFastSmiElementsKind(elements_kind)) { __ JumpIfNotSmi(value_reg, &transition_elements_kind); } @@ -4253,7 +4281,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( DONT_DO_SMI_CHECK); __ bind(&finish_store); - if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { + if (IsFastSmiElementsKind(elements_kind)) { __ add(scratch, elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); @@ -4263,7 +4291,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement( Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); __ str(value_reg, MemOperand(scratch)); } else { - ASSERT(elements_kind == FAST_ELEMENTS); + ASSERT(IsFastObjectElementsKind(elements_kind)); __ add(scratch, elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |