[stubs] Port LoadIndexedStringStub to CSA
BUG=v8:5269 Review-Url: https://codereview.chromium.org/2682153003 Cr-Commit-Position: refs/heads/master@{#43071}
This commit is contained in:
parent
1837cf4964
commit
63b980f996
@ -1169,39 +1169,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in lr.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = r5;
|
||||
Register result = r0;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadWithVectorDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1849,45 +1816,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ tst(code_, Operand(kSmiTagMask |
|
||||
((~String::kMaxOneByteCharCodeU) << kSmiTagSize)));
|
||||
__ b(ne, &slow_case_);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one-byte char code.
|
||||
__ add(result_, result_, Operand::PointerOffsetFromSmiKey(code_));
|
||||
__ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
|
||||
__ b(eq, &slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Move(result_, r0);
|
||||
call_helper.AfterCall(masm);
|
||||
__ jmp(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(
|
||||
MacroAssembler* masm, Register left, Register right, Register scratch1,
|
||||
Register scratch2, Register scratch3) {
|
||||
|
@ -1285,39 +1285,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in lr.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register result = x0;
|
||||
Register scratch = x10;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadWithVectorDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ Bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
#ifdef V8_INTERPRETED_REGEXP
|
||||
__ TailCallRuntime(Runtime::kRegExpExec);
|
||||
@ -2056,38 +2023,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
__ JumpIfNotSmi(code_, &slow_case_);
|
||||
__ Cmp(code_, Smi::FromInt(String::kMaxOneByteCharCode));
|
||||
__ B(hi, &slow_case_);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one-byte char code.
|
||||
__ Add(result_, result_, Operand::UntagSmiAndScale(code_, kPointerSizeLog2));
|
||||
__ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_);
|
||||
__ Bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ Bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ Push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Mov(result_, x0);
|
||||
call_helper.AfterCall(masm);
|
||||
__ B(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
|
||||
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
|
||||
// Inputs are in x0 (lhs) and x1 (rhs).
|
||||
DCHECK_EQ(CompareICState::BOOLEAN, state());
|
||||
|
@ -213,14 +213,10 @@ namespace internal {
|
||||
"Unexpected ElementsKind in array constructor") \
|
||||
V(kUnexpectedFallthroughFromCharCodeAtSlowCase, \
|
||||
"Unexpected fallthrough from CharCodeAt slow case") \
|
||||
V(kUnexpectedFallthroughFromCharFromCodeSlowCase, \
|
||||
"Unexpected fallthrough from CharFromCode slow case") \
|
||||
V(kUnexpectedFallThroughFromStringComparison, \
|
||||
"Unexpected fall-through from string comparison") \
|
||||
V(kUnexpectedFallthroughToCharCodeAtSlowCase, \
|
||||
"Unexpected fallthrough to CharCodeAt slow case") \
|
||||
V(kUnexpectedFallthroughToCharFromCodeSlowCase, \
|
||||
"Unexpected fallthrough to CharFromCode slow case") \
|
||||
V(kUnexpectedFPUStackDepthAfterInstruction, \
|
||||
"Unexpected FPU stack depth after instruction") \
|
||||
V(kUnexpectedInitialMapForArrayFunction1, \
|
||||
|
@ -12,6 +12,30 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
TF_BUILTIN(KeyedLoadIC_IndexedString, CodeStubAssembler) {
|
||||
typedef LoadWithVectorDescriptor Descriptor;
|
||||
|
||||
Node* receiver = Parameter(Descriptor::kReceiver);
|
||||
Node* index = Parameter(Descriptor::kName);
|
||||
Node* slot = Parameter(Descriptor::kSlot);
|
||||
Node* vector = Parameter(Descriptor::kVector);
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
|
||||
Label miss(this);
|
||||
|
||||
Node* index_intptr = TryToIntptr(index, &miss);
|
||||
Node* length = SmiUntag(LoadStringLength(receiver));
|
||||
GotoIf(UintPtrGreaterThanOrEqual(index_intptr, length), &miss);
|
||||
|
||||
Node* code = StringCharCodeAt(receiver, index_intptr, INTPTR_PARAMETERS);
|
||||
Node* result = StringFromCharCode(code);
|
||||
Return(result);
|
||||
|
||||
Bind(&miss);
|
||||
TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, index, slot,
|
||||
vector);
|
||||
}
|
||||
|
||||
TF_BUILTIN(KeyedLoadIC_Miss, CodeStubAssembler) {
|
||||
typedef LoadWithVectorDescriptor Descriptor;
|
||||
|
||||
|
@ -417,8 +417,7 @@ TF_BUILTIN(StringCharAt, CodeStubAssembler) {
|
||||
Node* position = Parameter(1);
|
||||
|
||||
// Load the character code at the {position} from the {receiver}.
|
||||
Node* code = StringCharCodeAt(receiver, position,
|
||||
CodeStubAssembler::INTPTR_PARAMETERS);
|
||||
Node* code = StringCharCodeAt(receiver, position, INTPTR_PARAMETERS);
|
||||
|
||||
// And return the single character string with only that {code}
|
||||
Node* result = StringFromCharCode(code);
|
||||
@ -430,8 +429,7 @@ TF_BUILTIN(StringCharCodeAt, CodeStubAssembler) {
|
||||
Node* position = Parameter(1);
|
||||
|
||||
// Load the character code at the {position} from the {receiver}.
|
||||
Node* code = StringCharCodeAt(receiver, position,
|
||||
CodeStubAssembler::INTPTR_PARAMETERS);
|
||||
Node* code = StringCharCodeAt(receiver, position, INTPTR_PARAMETERS);
|
||||
|
||||
// And return it as TaggedSigned value.
|
||||
// TODO(turbofan): Allow builtins to return values untagged.
|
||||
|
@ -233,6 +233,7 @@ class Isolate;
|
||||
TFS(KeyedLoadIC_Megamorphic, BUILTIN, kNoExtraICState, LoadWithVector, 1) \
|
||||
TFS(KeyedLoadIC_Miss, BUILTIN, kNoExtraICState, LoadWithVector, 1) \
|
||||
TFS(KeyedLoadIC_Slow, HANDLER, Code::LOAD_IC, LoadWithVector, 1) \
|
||||
TFS(KeyedLoadIC_IndexedString, HANDLER, Code::LOAD_IC, LoadWithVector, 1) \
|
||||
TFS(KeyedStoreIC_Megamorphic, BUILTIN, kNoExtraICState, StoreWithVector, 1) \
|
||||
TFS(KeyedStoreIC_Megamorphic_Strict, BUILTIN, kNoExtraICState, \
|
||||
StoreWithVector, 1) \
|
||||
|
109
src/code-stubs.h
109
src/code-stubs.h
@ -41,7 +41,6 @@ class Node;
|
||||
V(FunctionPrototype) \
|
||||
V(InternalArrayConstructor) \
|
||||
V(JSEntry) \
|
||||
V(LoadIndexedString) \
|
||||
V(MathPow) \
|
||||
V(ProfileEntryHook) \
|
||||
V(RecordWrite) \
|
||||
@ -893,19 +892,6 @@ class FunctionPrototypeStub : public PlatformCodeStub {
|
||||
DEFINE_PLATFORM_CODE_STUB(FunctionPrototype, PlatformCodeStub);
|
||||
};
|
||||
|
||||
|
||||
class LoadIndexedStringStub : public PlatformCodeStub {
|
||||
public:
|
||||
explicit LoadIndexedStringStub(Isolate* isolate)
|
||||
: PlatformCodeStub(isolate) {}
|
||||
|
||||
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
|
||||
ExtraICState GetExtraICState() const override { return Code::KEYED_LOAD_IC; }
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
|
||||
DEFINE_PLATFORM_CODE_STUB(LoadIndexedString, PlatformCodeStub);
|
||||
};
|
||||
|
||||
class KeyedLoadSloppyArgumentsStub : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate)
|
||||
@ -1383,13 +1369,6 @@ class StringCharCodeAtGenerator {
|
||||
void GenerateSlow(MacroAssembler* masm, EmbedMode embed_mode,
|
||||
const RuntimeCallHelper& call_helper);
|
||||
|
||||
// Skip handling slow case and directly jump to bailout.
|
||||
void SkipSlow(MacroAssembler* masm, Label* bailout) {
|
||||
masm->bind(&index_not_smi_);
|
||||
masm->bind(&call_runtime_);
|
||||
masm->jmp(bailout);
|
||||
}
|
||||
|
||||
private:
|
||||
Register object_;
|
||||
Register index_;
|
||||
@ -1409,94 +1388,6 @@ class StringCharCodeAtGenerator {
|
||||
DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator);
|
||||
};
|
||||
|
||||
|
||||
// Generates code for creating a one-char string from a char code.
|
||||
class StringCharFromCodeGenerator {
|
||||
public:
|
||||
StringCharFromCodeGenerator(Register code,
|
||||
Register result)
|
||||
: code_(code),
|
||||
result_(result) {
|
||||
DCHECK(!code_.is(result_));
|
||||
}
|
||||
|
||||
// Generates the fast case code. On the fallthrough path |result|
|
||||
// register contains the result.
|
||||
void GenerateFast(MacroAssembler* masm);
|
||||
|
||||
// Generates the slow case code. Must not be naturally
|
||||
// reachable. Expected to be put after a ret instruction (e.g., in
|
||||
// deferred code). Always jumps back to the fast case.
|
||||
void GenerateSlow(MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper);
|
||||
|
||||
// Skip handling slow case and directly jump to bailout.
|
||||
void SkipSlow(MacroAssembler* masm, Label* bailout) {
|
||||
masm->bind(&slow_case_);
|
||||
masm->jmp(bailout);
|
||||
}
|
||||
|
||||
private:
|
||||
Register code_;
|
||||
Register result_;
|
||||
|
||||
Label slow_case_;
|
||||
Label exit_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator);
|
||||
};
|
||||
|
||||
|
||||
// Generates code implementing String.prototype.charAt.
|
||||
//
|
||||
// Only supports the case when the receiver is a string and the index
|
||||
// is a number (smi or heap number) that is a valid index into the
|
||||
// string. Additional index constraints are specified by the
|
||||
// flags. Otherwise, bails out to the provided labels.
|
||||
//
|
||||
// Register usage: |object| may be changed to another string in a way
|
||||
// that doesn't affect charCodeAt/charAt semantics, |index| is
|
||||
// preserved, |scratch1|, |scratch2|, and |result| are clobbered.
|
||||
class StringCharAtGenerator {
|
||||
public:
|
||||
StringCharAtGenerator(Register object, Register index, Register scratch,
|
||||
Register result, Label* receiver_not_string,
|
||||
Label* index_not_number, Label* index_out_of_range,
|
||||
ReceiverCheckMode check_mode = RECEIVER_IS_UNKNOWN)
|
||||
: char_code_at_generator_(object, index, scratch, receiver_not_string,
|
||||
index_not_number, index_out_of_range,
|
||||
check_mode),
|
||||
char_from_code_generator_(scratch, result) {}
|
||||
|
||||
// Generates the fast case code. On the fallthrough path |result|
|
||||
// register contains the result.
|
||||
void GenerateFast(MacroAssembler* masm) {
|
||||
char_code_at_generator_.GenerateFast(masm);
|
||||
char_from_code_generator_.GenerateFast(masm);
|
||||
}
|
||||
|
||||
// Generates the slow case code. Must not be naturally
|
||||
// reachable. Expected to be put after a ret instruction (e.g., in
|
||||
// deferred code). Always jumps back to the fast case.
|
||||
void GenerateSlow(MacroAssembler* masm, EmbedMode embed_mode,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
char_code_at_generator_.GenerateSlow(masm, embed_mode, call_helper);
|
||||
char_from_code_generator_.GenerateSlow(masm, call_helper);
|
||||
}
|
||||
|
||||
// Skip handling slow case and directly jump to bailout.
|
||||
void SkipSlow(MacroAssembler* masm, Label* bailout) {
|
||||
char_code_at_generator_.SkipSlow(masm, bailout);
|
||||
char_from_code_generator_.SkipSlow(masm, bailout);
|
||||
}
|
||||
|
||||
private:
|
||||
StringCharCodeAtGenerator char_code_at_generator_;
|
||||
StringCharFromCodeGenerator char_from_code_generator_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator);
|
||||
};
|
||||
|
||||
class CallICTrampolineStub : public TurboFanCodeStub {
|
||||
public:
|
||||
CallICTrampolineStub(Isolate* isolate, ConvertReceiverMode convert_mode,
|
||||
|
@ -479,40 +479,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is on the stack.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = edi;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
Register result = eax;
|
||||
DCHECK(!result.is(scratch));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ ret(0);
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1781,52 +1747,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ test(code_, Immediate(kSmiTagMask |
|
||||
((~String::kMaxOneByteCharCodeU) << kSmiTagSize)));
|
||||
__ j(not_zero, &slow_case_);
|
||||
|
||||
Factory* factory = masm->isolate()->factory();
|
||||
__ Move(result_, Immediate(factory->single_character_string_cache()));
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
// At this point code register contains smi tagged one byte char code.
|
||||
__ mov(result_, FieldOperand(result_,
|
||||
code_, times_half_pointer_size,
|
||||
FixedArray::kHeaderSize));
|
||||
__ cmp(result_, factory->undefined_value());
|
||||
__ j(equal, &slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
if (!result_.is(eax)) {
|
||||
__ mov(result_, eax);
|
||||
}
|
||||
call_helper.AfterCall(masm);
|
||||
__ jmp(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
|
@ -352,7 +352,7 @@ Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
|
||||
}
|
||||
if (receiver_map->IsStringMap()) {
|
||||
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
|
||||
return LoadIndexedStringStub(isolate).GetCode();
|
||||
return isolate->builtins()->KeyedLoadIC_IndexedString();
|
||||
}
|
||||
InstanceType instance_type = receiver_map->instance_type();
|
||||
if (instance_type < FIRST_JS_RECEIVER_TYPE) {
|
||||
|
@ -1277,35 +1277,6 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
|
||||
__ Jump(ra);
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in ra.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = t1;
|
||||
Register result = v0;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()));
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
Label miss;
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
@ -1990,51 +1961,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
|
||||
DCHECK(!t0.is(result_));
|
||||
DCHECK(!t0.is(code_));
|
||||
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ And(t0, code_, Operand(kSmiTagMask |
|
||||
((~String::kMaxOneByteCharCodeU) << kSmiTagSize)));
|
||||
__ Branch(&slow_case_, ne, t0, Operand(zero_reg));
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one-byte char code.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ Lsa(result_, result_, code_, kPointerSizeLog2 - kSmiTagSize);
|
||||
__ lw(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(&slow_case_, eq, result_, Operand(t0));
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Move(result_, v0);
|
||||
|
||||
call_helper.AfterCall(masm);
|
||||
__ Branch(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(
|
||||
MacroAssembler* masm, Register left, Register right, Register scratch1,
|
||||
Register scratch2, Register scratch3) {
|
||||
|
@ -1272,35 +1272,6 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
|
||||
__ Jump(ra);
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in ra.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = a5;
|
||||
Register result = v0;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()));
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
Label miss;
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
@ -1998,44 +1969,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
__ JumpIfNotSmi(code_, &slow_case_);
|
||||
__ Branch(&slow_case_, hi, code_,
|
||||
Operand(Smi::FromInt(String::kMaxOneByteCharCode)));
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one_byte char code.
|
||||
__ SmiScale(at, code_, kPointerSizeLog2);
|
||||
__ Daddu(result_, result_, at);
|
||||
__ ld(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(&slow_case_, eq, result_, Operand(at));
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Move(result_, v0);
|
||||
|
||||
call_helper.AfterCall(masm);
|
||||
__ Branch(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(
|
||||
MacroAssembler* masm, Register left, Register right, Register scratch1,
|
||||
Register scratch2, Register scratch3) {
|
||||
|
@ -1236,39 +1236,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in lr.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = r8;
|
||||
Register result = r3;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadWithVectorDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1945,46 +1912,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ LoadSmiLiteral(r0, Smi::FromInt(~String::kMaxOneByteCharCodeU));
|
||||
__ ori(r0, r0, Operand(kSmiTagMask));
|
||||
__ and_(r0, code_, r0, SetRC);
|
||||
__ bne(&slow_case_, cr0);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one-byte char code.
|
||||
__ mr(r0, code_);
|
||||
__ SmiToPtrArrayOffset(code_, code_);
|
||||
__ add(result_, result_, code_);
|
||||
__ mr(code_, r0);
|
||||
__ LoadP(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
|
||||
__ beq(&slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Move(result_, r3);
|
||||
call_helper.AfterCall(masm);
|
||||
__ b(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
|
@ -1234,37 +1234,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is in lr.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = r7;
|
||||
Register result = r2;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadWithVectorDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ Ret();
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1945,44 +1914,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ LoadSmiLiteral(r0, Smi::FromInt(~String::kMaxOneByteCharCodeU));
|
||||
__ OrP(r0, r0, Operand(kSmiTagMask));
|
||||
__ AndP(r0, code_, r0);
|
||||
__ bne(&slow_case_);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged one-byte char code.
|
||||
__ LoadRR(r0, code_);
|
||||
__ SmiToPtrArrayOffset(code_, code_);
|
||||
__ AddP(result_, code_);
|
||||
__ LoadRR(code_, r0);
|
||||
__ LoadP(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
|
||||
__ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
|
||||
__ beq(&slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
__ Move(result_, r2);
|
||||
call_helper.AfterCall(masm);
|
||||
__ b(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
|
@ -360,39 +360,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is on the stack.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = rdi;
|
||||
Register result = rax;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ ret(0);
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1741,44 +1708,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
__ JumpIfNotSmi(code_, &slow_case_);
|
||||
__ SmiCompare(code_, Smi::FromInt(String::kMaxOneByteCharCode));
|
||||
__ j(above, &slow_case_);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2);
|
||||
__ movp(result_, FieldOperand(result_, index.reg, index.scale,
|
||||
FixedArray::kHeaderSize));
|
||||
__ CompareRoot(result_, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, &slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ Push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
if (!result_.is(rax)) {
|
||||
__ movp(result_, rax);
|
||||
}
|
||||
call_helper.AfterCall(masm);
|
||||
__ jmp(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
|
@ -299,41 +299,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
// Return address is on the stack.
|
||||
Label miss;
|
||||
|
||||
Register receiver = LoadDescriptor::ReceiverRegister();
|
||||
Register index = LoadDescriptor::NameRegister();
|
||||
Register scratch = edi;
|
||||
DCHECK(!scratch.is(receiver) && !scratch.is(index));
|
||||
Register result = eax;
|
||||
DCHECK(!result.is(scratch));
|
||||
DCHECK(!scratch.is(LoadWithVectorDescriptor::VectorRegister()) &&
|
||||
result.is(LoadDescriptor::SlotRegister()));
|
||||
|
||||
// StringCharAtGenerator doesn't use the result register until it's passed
|
||||
// the different miss possibilities. If it did, we would have a conflict
|
||||
// when FLAG_vector_ics is true.
|
||||
|
||||
StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
|
||||
&miss, // When not a string.
|
||||
&miss, // When not a number.
|
||||
&miss, // When index out of range.
|
||||
RECEIVER_IS_STRING);
|
||||
char_at_generator.GenerateFast(masm);
|
||||
__ ret(0);
|
||||
|
||||
StubRuntimeCallHelper call_helper;
|
||||
char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
|
||||
|
||||
__ bind(&miss);
|
||||
PropertyAccessCompiler::TailCallBuiltin(
|
||||
masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
|
||||
}
|
||||
|
||||
|
||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||
// time or if regexp entry in generated code is turned off runtime switch or
|
||||
@ -1829,52 +1794,6 @@ void StringCharCodeAtGenerator::GenerateSlow(
|
||||
__ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// StringCharFromCodeGenerator
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// Fast case of Heap::LookupSingleCharacterStringFromCode.
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1));
|
||||
__ test(code_, Immediate(kSmiTagMask |
|
||||
((~String::kMaxOneByteCharCodeU) << kSmiTagSize)));
|
||||
__ j(not_zero, &slow_case_);
|
||||
|
||||
Factory* factory = masm->isolate()->factory();
|
||||
__ Move(result_, Immediate(factory->single_character_string_cache()));
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiShiftSize == 0);
|
||||
// At this point code register contains smi tagged one byte char code.
|
||||
__ mov(result_, FieldOperand(result_,
|
||||
code_, times_half_pointer_size,
|
||||
FixedArray::kHeaderSize));
|
||||
__ cmp(result_, factory->undefined_value());
|
||||
__ j(equal, &slow_case_);
|
||||
__ bind(&exit_);
|
||||
}
|
||||
|
||||
|
||||
void StringCharFromCodeGenerator::GenerateSlow(
|
||||
MacroAssembler* masm,
|
||||
const RuntimeCallHelper& call_helper) {
|
||||
__ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
|
||||
|
||||
__ bind(&slow_case_);
|
||||
call_helper.BeforeCall(masm);
|
||||
__ push(code_);
|
||||
__ CallRuntime(Runtime::kStringCharFromCode);
|
||||
if (!result_.is(eax)) {
|
||||
__ mov(result_, eax);
|
||||
}
|
||||
call_helper.AfterCall(masm);
|
||||
__ jmp(&exit_);
|
||||
|
||||
__ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
|
||||
}
|
||||
|
||||
void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
|
Loading…
Reference in New Issue
Block a user