diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-08-29 15:29:35 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-08-29 15:47:16 -0700 |
commit | da00ff4999bd26e2c17df1f84d090d3b3296e043 (patch) | |
tree | 428c169695615d22c6726d545b72d059d3626aec /deps/v8/src/arm | |
parent | 59fa16f648aea51c880fac46abb1817e61d0675e (diff) | |
download | node-new-da00ff4999bd26e2c17df1f84d090d3b3296e043.tar.gz |
Upgrade V8 to 3.5.9.1
Diffstat (limited to 'deps/v8/src/arm')
-rw-r--r-- | deps/v8/src/arm/code-stubs-arm.cc | 93 | ||||
-rw-r--r-- | deps/v8/src/arm/full-codegen-arm.cc | 241 | ||||
-rw-r--r-- | deps/v8/src/arm/lithium-arm.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/arm/lithium-codegen-arm.cc | 102 | ||||
-rw-r--r-- | deps/v8/src/arm/regexp-macro-assembler-arm.cc | 28 |
5 files changed, 208 insertions, 260 deletions
diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index ba345e24ba..ffe32bc60a 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -4367,6 +4367,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ cmp(r2, Operand(r0, ASR, kSmiTagSize)); __ b(gt, &runtime); + // Reset offset for possibly sliced string. + __ mov(r9, Operand(0)); // subject: Subject string // regexp_data: RegExp data (FixedArray) // Check the representation and encoding of the subject string. @@ -4374,33 +4376,45 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); // First check for flat string. - __ tst(r0, Operand(kIsNotStringMask | kStringRepresentationMask)); + __ and_(r1, r0, Operand(kIsNotStringMask | kStringRepresentationMask), SetCC); STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); __ b(eq, &seq_string); // subject: Subject string // regexp_data: RegExp data (FixedArray) - // Check for flat cons string. + // Check for flat cons string or sliced string. // A flat cons string is a cons string where the second part is the empty // string. In that case the subject string is just the first part of the cons // string. Also in this case the first part of the cons string is known to be // a sequential string or an external string. - STATIC_ASSERT(kExternalStringTag !=0); - STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); - __ tst(r0, Operand(kIsNotStringMask | kExternalStringTag)); - __ b(ne, &runtime); + // In the case of a sliced string its offset has to be taken into account. + Label cons_string, check_encoding; + STATIC_ASSERT((kConsStringTag < kExternalStringTag)); + STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + __ cmp(r1, Operand(kExternalStringTag)); + __ b(lt, &cons_string); + __ b(eq, &runtime); + + // String is sliced. + __ ldr(r9, FieldMemOperand(subject, SlicedString::kOffsetOffset)); + __ mov(r9, Operand(r9, ASR, kSmiTagSize)); + __ ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset)); + // r9: offset of sliced string, smi-tagged. + __ jmp(&check_encoding); + // String is a cons string, check whether it is flat. + __ bind(&cons_string); __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); __ LoadRoot(r1, Heap::kEmptyStringRootIndex); __ cmp(r0, r1); __ b(ne, &runtime); __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); + // Is first part of cons or parent of slice a flat string? + __ bind(&check_encoding); __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); - // Is first part a flat string? STATIC_ASSERT(kSeqStringTag == 0); __ tst(r0, Operand(kStringRepresentationMask)); __ b(ne, &runtime); - __ bind(&seq_string); // subject: Subject string // regexp_data: RegExp data (FixedArray) @@ -4466,21 +4480,30 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // For arguments 4 and 3 get string length, calculate start of string data and // calculate the shift of the index (0 for ASCII and 1 for two byte). - __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); - __ mov(r0, Operand(r0, ASR, kSmiTagSize)); STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); - __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ add(r8, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); __ eor(r3, r3, Operand(1)); - // Argument 4 (r3): End of string data - // Argument 3 (r2): Start of string data + // Load the length from the original subject string from the previous stack + // frame. Therefore we have to use fp, which points exactly to two pointer + // sizes below the previous sp. (Because creating a new stack frame pushes + // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) + __ ldr(r0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); + // If slice offset is not 0, load the length from the original sliced string. + // Argument 4, r3: End of string data + // Argument 3, r2: Start of string data + // Prepare start and end index of the input. + __ add(r9, r8, Operand(r9, LSL, r3)); __ add(r2, r9, Operand(r1, LSL, r3)); - __ add(r3, r9, Operand(r0, LSL, r3)); + + __ ldr(r8, FieldMemOperand(r0, String::kLengthOffset)); + __ mov(r8, Operand(r8, ASR, kSmiTagSize)); + __ add(r3, r9, Operand(r8, LSL, r3)); // Argument 2 (r1): Previous index. // Already there // Argument 1 (r0): Subject string. - __ mov(r0, subject); + // Already there // Locate the code entry and call it. __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); @@ -4497,12 +4520,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { // Check the result. Label success; - __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS)); + __ cmp(subject, Operand(NativeRegExpMacroAssembler::SUCCESS)); __ b(eq, &success); Label failure; - __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); + __ cmp(subject, Operand(NativeRegExpMacroAssembler::FAILURE)); __ b(eq, &failure); - __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); + __ cmp(subject, Operand(NativeRegExpMacroAssembler::EXCEPTION)); // If not exception it can only be retry. Handle that in the runtime system. __ b(ne, &runtime); // Result must now be exception. If there is no pending exception already a @@ -4514,18 +4537,18 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address, isolate))); __ ldr(r0, MemOperand(r2, 0)); - __ cmp(r0, r1); + __ cmp(subject, r1); __ b(eq, &runtime); __ str(r1, MemOperand(r2, 0)); // Clear pending exception. // Check if the exception is a termination. If so, throw as uncatchable. __ LoadRoot(ip, Heap::kTerminationExceptionRootIndex); - __ cmp(r0, ip); + __ cmp(subject, ip); Label termination_exception; __ b(eq, &termination_exception); - __ Throw(r0); // Expects thrown value in r0. + __ Throw(subject); // Expects thrown value in r0. __ bind(&termination_exception); __ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0. @@ -4803,6 +4826,7 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { Label flat_string; Label ascii_string; Label got_char_code; + Label sliced_string; // If the receiver is a smi trigger the non-string case. __ JumpIfSmi(object_, receiver_not_string_); @@ -4832,7 +4856,11 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { __ b(eq, &flat_string); // Handle non-flat strings. - __ tst(result_, Operand(kIsConsStringMask)); + __ and_(result_, result_, Operand(kStringRepresentationMask)); + STATIC_ASSERT((kConsStringTag < kExternalStringTag)); + STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); + __ cmp(result_, Operand(kExternalStringTag)); + __ b(gt, &sliced_string); __ b(eq, &call_runtime_); // ConsString. @@ -4840,15 +4868,26 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { // this is really a flat string in a cons string). If that is not // the case we would rather go to the runtime system now to flatten // the string. + Label assure_seq_string; __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); __ LoadRoot(ip, Heap::kEmptyStringRootIndex); __ cmp(result_, Operand(ip)); __ b(ne, &call_runtime_); // Get the first of the two strings and load its instance type. __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); + __ jmp(&assure_seq_string); + + // SlicedString, unpack and add offset. + __ bind(&sliced_string); + __ ldr(result_, FieldMemOperand(object_, SlicedString::kOffsetOffset)); + __ add(scratch_, scratch_, result_); + __ ldr(object_, FieldMemOperand(object_, SlicedString::kParentOffset)); + + // Assure that we are dealing with a sequential string. Go to runtime if not. + __ bind(&assure_seq_string); __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); - // If the first cons component is also non-flat, then go to runtime. + // Check that parent is not an external string. Go to runtime otherwise. STATIC_ASSERT(kSeqStringTag == 0); __ tst(result_, Operand(kStringRepresentationMask)); __ b(ne, &call_runtime_); @@ -5428,10 +5467,17 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Check bounds and smi-ness. Register to = r6; Register from = r7; + + if (FLAG_string_slices) { + __ nop(0); // Jumping as first instruction would crash the code generation. + __ jmp(&runtime); + } + __ Ldrd(to, from, MemOperand(sp, kToOffset)); STATIC_ASSERT(kFromOffset == kToOffset + 4); STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); + // I.e., arithmetic shift right by one un-smi-tags. __ mov(r2, Operand(to, ASR, 1), SetCC); __ mov(r3, Operand(from, ASR, 1), SetCC, cc); @@ -5440,7 +5486,6 @@ void SubStringStub::Generate(MacroAssembler* masm) { __ b(mi, &runtime); // From is negative. // Both to and from are smis. - __ sub(r2, r2, Operand(r3), SetCC); __ b(mi, &runtime); // Fail if from > to. // Special handling of sub-strings of length 1 and 2. One character strings diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 97f7fea793..b58743de41 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -47,7 +47,6 @@ namespace internal { static unsigned GetPropertyId(Property* property) { - if (property->is_synthetic()) return AstNode::kNoNumber; return property->id(); } @@ -694,104 +693,73 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable, Comment cmnt(masm_, "[ Declaration"); ASSERT(variable != NULL); // Must have been resolved. Slot* slot = variable->AsSlot(); - Property* prop = variable->AsProperty(); - - if (slot != NULL) { - switch (slot->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - if (mode == Variable::CONST) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ str(ip, MemOperand(fp, SlotOffset(slot))); - } else if (function != NULL) { - VisitForAccumulatorValue(function); - __ str(result_register(), MemOperand(fp, SlotOffset(slot))); - } - break; - - case Slot::CONTEXT: - // We bypass the general EmitSlotSearch because we know more about - // this specific context. - - // The variable in the decl always resides in the current function - // context. - ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); - if (FLAG_debug_code) { - // Check that we're not inside a with or catch context. - __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); - __ CompareRoot(r1, Heap::kWithContextMapRootIndex); - __ Check(ne, "Declaration in with context."); - __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); - __ Check(ne, "Declaration in catch context."); - } - if (mode == Variable::CONST) { - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); - __ str(ip, ContextOperand(cp, slot->index())); - // No write barrier since the_hole_value is in old space. - } else if (function != NULL) { - VisitForAccumulatorValue(function); - __ str(result_register(), ContextOperand(cp, slot->index())); - int offset = Context::SlotOffset(slot->index()); - // We know that we have written a function, which is not a smi. - __ mov(r1, Operand(cp)); - __ RecordWrite(r1, Operand(offset), r2, result_register()); - } - break; - - case Slot::LOOKUP: { - __ mov(r2, Operand(variable->name())); - // Declaration nodes are always introduced in one of two modes. - ASSERT(mode == Variable::VAR || - mode == Variable::CONST || - mode == Variable::LET); - PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; - __ mov(r1, Operand(Smi::FromInt(attr))); - // Push initial value, if any. - // Note: For variables we must not push an initial value (such as - // 'undefined') because we may have a (legal) redeclaration and we - // must not destroy the current value. - if (mode == Variable::CONST) { - __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); - __ Push(cp, r2, r1, r0); - } else if (function != NULL) { - __ Push(cp, r2, r1); - // Push initial value for function declaration. - VisitForStackValue(function); - } else { - __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! - __ Push(cp, r2, r1, r0); - } - __ CallRuntime(Runtime::kDeclareContextSlot, 4); - break; + ASSERT(slot != NULL); + switch (slot->type()) { + case Slot::PARAMETER: + case Slot::LOCAL: + if (mode == Variable::CONST) { + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ str(ip, MemOperand(fp, SlotOffset(slot))); + } else if (function != NULL) { + VisitForAccumulatorValue(function); + __ str(result_register(), MemOperand(fp, SlotOffset(slot))); } - } + break; - } else if (prop != NULL) { - // A const declaration aliasing a parameter is an illegal redeclaration. - ASSERT(mode != Variable::CONST); - if (function != NULL) { - // We are declaring a function that rewrites to a property. - // Use (keyed) IC to set the initial value. We cannot visit the - // rewrite because it's shared and we risk recording duplicate AST - // IDs for bailouts from optimized code. - ASSERT(prop->obj()->AsVariableProxy() != NULL); - { AccumulatorValueContext for_object(this); - EmitVariableLoad(prop->obj()->AsVariableProxy()); + case Slot::CONTEXT: + // We bypass the general EmitSlotSearch because we know more about + // this specific context. + + // The variable in the decl always resides in the current function + // context. + ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); + if (FLAG_debug_code) { + // Check that we're not inside a with or catch context. + __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); + __ CompareRoot(r1, Heap::kWithContextMapRootIndex); + __ Check(ne, "Declaration in with context."); + __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); + __ Check(ne, "Declaration in catch context."); } + if (mode == Variable::CONST) { + __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); + __ str(ip, ContextOperand(cp, slot->index())); + // No write barrier since the_hole_value is in old space. + } else if (function != NULL) { + VisitForAccumulatorValue(function); + __ str(result_register(), ContextOperand(cp, slot->index())); + int offset = Context::SlotOffset(slot->index()); + // We know that we have written a function, which is not a smi. + __ mov(r1, Operand(cp)); + __ RecordWrite(r1, Operand(offset), r2, result_register()); + } + break; - __ push(r0); - VisitForAccumulatorValue(function); - __ pop(r2); - - ASSERT(prop->key()->AsLiteral() != NULL && - prop->key()->AsLiteral()->handle()->IsSmi()); - __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); - - Handle<Code> ic = is_strict_mode() - ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() - : isolate()->builtins()->KeyedStoreIC_Initialize(); - __ Call(ic); - // Value in r0 is ignored (declarations are statements). + case Slot::LOOKUP: { + __ mov(r2, Operand(variable->name())); + // Declaration nodes are always introduced in one of two modes. + ASSERT(mode == Variable::VAR || + mode == Variable::CONST || + mode == Variable::LET); + PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; + __ mov(r1, Operand(Smi::FromInt(attr))); + // Push initial value, if any. + // Note: For variables we must not push an initial value (such as + // 'undefined') because we may have a (legal) redeclaration and we + // must not destroy the current value. + if (mode == Variable::CONST) { + __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); + __ Push(cp, r2, r1, r0); + } else if (function != NULL) { + __ Push(cp, r2, r1); + // Push initial value for function declaration. + VisitForStackValue(function); + } else { + __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! + __ Push(cp, r2, r1, r0); + } + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; } } } @@ -2272,36 +2240,10 @@ void FullCodeGenerator::VisitCall(Call* expr) { EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { // Call to a keyed property. - // For a synthetic property use keyed load IC followed by function call, - // for a regular property use EmitKeyedCallWithIC. - if (prop->is_synthetic()) { - // Do not visit the object and key subexpressions (they are shared - // by all occurrences of the same rewritten parameter). - ASSERT(prop->obj()->AsVariableProxy() != NULL); - ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); - Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); - MemOperand operand = EmitSlotSearch(slot, r1); - __ ldr(r1, operand); - - ASSERT(prop->key()->AsLiteral() != NULL); - ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); - __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); - - // Record source code position for IC call. - SetSourcePosition(prop->position()); - - Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); - __ ldr(r1, GlobalObjectOperand()); - __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); - __ Push(r0, r1); // Function, receiver. - EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); - } else { - { PreservePositionScope scope(masm()->positions_recorder()); - VisitForStackValue(prop->obj()); - } - EmitKeyedCallWithIC(expr, prop->key()); + { PreservePositionScope scope(masm()->positions_recorder()); + VisitForStackValue(prop->obj()); } + EmitKeyedCallWithIC(expr, prop->key()); } } else { { PreservePositionScope scope(masm()->positions_recorder()); @@ -3580,39 +3522,6 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { } -void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) { - ASSERT(args->length() == 1); - - // Load the function into r0. - VisitForAccumulatorValue(args->at(0)); - - // Prepare for the test. - Label materialize_true, materialize_false; - Label* if_true = NULL; - Label* if_false = NULL; - Label* fall_through = NULL; - context()->PrepareTest(&materialize_true, &materialize_false, - &if_true, &if_false, &fall_through); - - // Test for strict mode function. - __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset)); - __ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + - kSmiTagSize))); - __ b(ne, if_true); - - // Test for native function. - __ tst(r1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); - __ b(ne, if_true); - - // Not native or strict-mode function. - __ b(if_false); - - PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); - context()->Plug(if_true, if_false); -} - - void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { Handle<String> name = expr->name(); if (name->length() > 0 && name->Get(0) == '_') { @@ -3664,18 +3573,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); if (prop != NULL) { - if (prop->is_synthetic()) { - // Result of deleting parameters is false, even when they rewrite - // to accesses on the arguments object. - context()->Plug(false); - } else { - VisitForStackValue(prop->obj()); - VisitForStackValue(prop->key()); - __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); - __ push(r1); - __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); - context()->Plug(r0); - } + VisitForStackValue(prop->obj()); + VisitForStackValue(prop->key()); + __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); + __ push(r1); + __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); + context()->Plug(r0); } else if (var != NULL) { // Delete of an unqualified identifier is disallowed in strict mode // but "delete this" is. diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 38f77cda4c..30d7a1c2cd 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -1999,8 +1999,8 @@ LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { - LOperand* string = UseRegister(instr->string()); - LOperand* index = UseRegisterOrConstant(instr->index()); + LOperand* string = UseTempRegister(instr->string()); + LOperand* index = UseTempRegister(instr->index()); LStringCharCodeAt* result = new LStringCharCodeAt(string, index); return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); } diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 3469bb63a8..65a6169252 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -3455,97 +3455,83 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { LStringCharCodeAt* instr_; }; - Register scratch = scratch0(); Register string = ToRegister(instr->string()); - Register index = no_reg; - int const_index = -1; - if (instr->index()->IsConstantOperand()) { - const_index = ToInteger32(LConstantOperand::cast(instr->index())); - STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); - if (!Smi::IsValid(const_index)) { - // Guaranteed to be out of bounds because of the assert above. - // So the bounds check that must dominate this instruction must - // have deoptimized already. - if (FLAG_debug_code) { - __ Abort("StringCharCodeAt: out of bounds index."); - } - // No code needs to be generated. - return; - } - } else { - index = ToRegister(instr->index()); - } + Register index = ToRegister(instr->index()); Register result = ToRegister(instr->result()); DeferredStringCharCodeAt* deferred = new DeferredStringCharCodeAt(this, instr); - Label flat_string, ascii_string, done; - // Fetch the instance type of the receiver into result register. __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); - // We need special handling for non-flat strings. - STATIC_ASSERT(kSeqStringTag == 0); - __ tst(result, Operand(kStringRepresentationMask)); - __ b(eq, &flat_string); - - // Handle non-flat strings. - __ tst(result, Operand(kIsConsStringMask)); - __ b(eq, deferred->entry()); - - // ConsString. + // We need special handling for indirect strings. + Label check_sequential; + __ tst(result, Operand(kIsIndirectStringMask)); + __ b(eq, &check_sequential); + + // Dispatch on the indirect string shape: slice or cons. + Label cons_string; + const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag; + ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0); + __ tst(result, Operand(kSlicedNotConsMask)); + __ b(eq, &cons_string); + + // Handle slices. + Label indirect_string_loaded; + __ ldr(result, FieldMemOperand(string, SlicedString::kOffsetOffset)); + __ add(index, index, Operand(result, ASR, kSmiTagSize)); + __ ldr(string, FieldMemOperand(string, SlicedString::kParentOffset)); + __ jmp(&indirect_string_loaded); + + // Handle conses. // Check whether the right hand side is the empty string (i.e. if // this is really a flat string in a cons string). If that is not // the case we would rather go to the runtime system now to flatten // the string. - __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset)); + __ bind(&cons_string); + __ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset)); __ LoadRoot(ip, Heap::kEmptyStringRootIndex); - __ cmp(scratch, ip); + __ cmp(result, ip); __ b(ne, deferred->entry()); // Get the first of the two strings and load its instance type. __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); + + __ bind(&indirect_string_loaded); __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); - // If the first cons component is also non-flat, then go to runtime. + + // Check whether the string is sequential. The only non-sequential + // shapes we support have just been unwrapped above. + __ bind(&check_sequential); STATIC_ASSERT(kSeqStringTag == 0); __ tst(result, Operand(kStringRepresentationMask)); __ b(ne, deferred->entry()); - // Check for 1-byte or 2-byte string. - __ bind(&flat_string); + // Dispatch on the encoding: ASCII or two-byte. + Label ascii_string; STATIC_ASSERT(kAsciiStringTag != 0); __ tst(result, Operand(kStringEncodingMask)); __ b(ne, &ascii_string); - // 2-byte string. - // Load the 2-byte character code into the result register. - STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); - if (instr->index()->IsConstantOperand()) { - __ ldrh(result, - FieldMemOperand(string, - SeqTwoByteString::kHeaderSize + 2 * const_index)); - } else { - __ add(scratch, - string, - Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - __ ldrh(result, MemOperand(scratch, index, LSL, 1)); - } + // Two-byte string. + // Load the two-byte character code into the result register. + Label done; + __ add(result, + string, + Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); + __ ldrh(result, MemOperand(result, index, LSL, 1)); __ jmp(&done); // ASCII string. // Load the byte into the result register. __ bind(&ascii_string); - if (instr->index()->IsConstantOperand()) { - __ ldrb(result, FieldMemOperand(string, - SeqAsciiString::kHeaderSize + const_index)); - } else { - __ add(scratch, - string, - Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); - __ ldrb(result, MemOperand(scratch, index)); - } + __ add(result, + string, + Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); + __ ldrb(result, MemOperand(result, index)); + __ bind(&done); __ bind(deferred->exit()); } diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 983a5286e0..81645c72ea 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -1034,12 +1034,13 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, } // Prepare for possible GC. - HandleScope handles; + HandleScope handles(isolate); Handle<Code> code_handle(re_code); Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); + // Current string. - bool is_ascii = subject->IsAsciiRepresentation(); + bool is_ascii = subject->IsAsciiRepresentationUnderneath(); ASSERT(re_code->instruction_start() <= *return_address); ASSERT(*return_address <= @@ -1057,8 +1058,20 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, return EXCEPTION; } + Handle<String> subject_tmp = subject; + int slice_offset = 0; + + // Extract the underlying string and the slice offset. + if (StringShape(*subject_tmp).IsCons()) { + subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first()); + } else if (StringShape(*subject_tmp).IsSliced()) { + SlicedString* slice = SlicedString::cast(*subject_tmp); + subject_tmp = Handle<String>(slice->parent()); + slice_offset = slice->offset(); + } + // String might have changed. - if (subject->IsAsciiRepresentation() != is_ascii) { + if (subject_tmp->IsAsciiRepresentation() != is_ascii) { // If we changed between an ASCII and an UC16 string, the specialized // code cannot be used, and we need to restart regexp matching from // scratch (including, potentially, compiling a new version of the code). @@ -1069,8 +1082,8 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, // be a sequential or external string with the same content. // Update the start and end pointers in the stack frame to the current // location (whether it has actually moved or not). - ASSERT(StringShape(*subject).IsSequential() || - StringShape(*subject).IsExternal()); + ASSERT(StringShape(*subject_tmp).IsSequential() || + StringShape(*subject_tmp).IsExternal()); // The original start address of the characters to match. const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart); @@ -1078,13 +1091,14 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, // Find the current start address of the same character at the current string // position. int start_index = frame_entry<int>(re_frame, kStartIndex); - const byte* new_address = StringCharacterPosition(*subject, start_index); + const byte* new_address = StringCharacterPosition(*subject_tmp, + start_index + slice_offset); if (start_address != new_address) { // If there is a difference, update the object pointer and start and end // addresses in the RegExp stack frame to match the new value. const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd); - int byte_length = end_address - start_address; + int byte_length = static_cast<int>(end_address - start_address); frame_entry<const String*>(re_frame, kInputString) = *subject; frame_entry<const byte*>(re_frame, kInputStart) = new_address; frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length; |