Revision: 6408
Author: [email protected]
Date: Wed Jan 19 12:05:22 2011
Log: Support StringCharCodeAt in hydrogen/lithium.
This patch adds H- and L-variants of StringCharCodeAt and StringLength.
StringCharCodeAt is used to inline a constant function call of
String.prototype.charCodeAt and to implement the corresponding inline
runtime function. It does not yet use the recently introduced extra IC
state. (We can specialize on string encoding and avoid deopts because
of out of bounds accesses.)
StringLength needs more work because the stub version of it also
supports strings wrappers and it matters in some cases. (We have to
separate the string only case.)
Review URL: http://codereview.chromium.org/6243008
http://code.google.com/p/v8/source/detail?r=6408
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects-printer.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/x64/lithium-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Wed Jan 19 06:53:38 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Wed Jan 19 12:05:22 2011
@@ -1722,6 +1722,18 @@
LInstruction* result = new LStoreNamedGeneric(obj, val);
return MarkAsCall(result, instr);
}
+
+
+LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
+ Abort("LStringCharCodeAt instruction not implemented on ARM");
+ return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
+ Abort("LStringLength instruction not implemented on ARM");
+ return NULL;
+}
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
=======================================
--- /branches/bleeding_edge/src/ast.cc Mon Jan 17 00:11:03 2011
+++ /branches/bleeding_edge/src/ast.cc Wed Jan 19 12:05:22 2011
@@ -32,7 +32,6 @@
#include "parser.h"
#include "scopes.h"
#include "string-stream.h"
-#include "stub-cache.h"
namespace v8 {
namespace internal {
@@ -560,20 +559,13 @@
}
-static bool CallWithoutIC(Handle<JSFunction> target, int arity) {
+static bool CanCallWithoutIC(Handle<JSFunction> target, int arity) {
SharedFunctionInfo* info = target->shared();
- if (target->NeedsArgumentsAdaption()) {
- // If the number of formal parameters of the target function
- // does not match the number of arguments we're passing, we
- // don't want to deal with it.
- return info->formal_parameter_count() == arity;
- } else {
- // If the target doesn't need arguments adaption, we can call
- // it directly, but we avoid to do so if it has a custom call
- // generator, because that is likely to generate better code.
- return !info->HasBuiltinFunctionId() ||
- !CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
- }
+ // If the number of formal parameters of the target function does
+ // not match the number of arguments we're passing, we don't want to
+ // deal with it. Otherwise, we can call it directly.
+ return !target->NeedsArgumentsAdaption() ||
+ info->formal_parameter_count() == arity;
}
@@ -589,7 +581,7 @@
type = Handle<Map>(holder()->map());
} else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) {
target_ =
Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
- return CallWithoutIC(target_, arguments()->length());
+ return CanCallWithoutIC(target_, arguments()->length());
} else {
return false;
}
@@ -609,8 +601,8 @@
Handle<JSFunction> candidate(JSFunction::cast(cell_->value()));
// If the function is in new space we assume it's more likely to
// change and thus prefer the general IC code.
- if (!Heap::InNewSpace(*candidate)
- && CallWithoutIC(candidate, arguments()->length())) {
+ if (!Heap::InNewSpace(*candidate) &&
+ CanCallWithoutIC(candidate, arguments()->length())) {
target_ = candidate;
return true;
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Tue Jan 18 05:43:48
2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Jan 19 12:05:22
2011
@@ -81,6 +81,7 @@
// HStoreNamed
// HStoreNamedField
// HStoreNamedGeneric
+// HStringCharCodeAt
// HBlockEntry
// HCall
// HCallConstantFunction
@@ -137,6 +138,7 @@
// HLoadNamedGeneric
// HLoadFunctionPrototype
// HPushArgument
+// HStringLength
// HTypeof
// HUnaryMathOperation
// HUnaryPredicate
@@ -248,6 +250,8 @@
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
+ V(StringCharCodeAt) \
+ V(StringLength) \
V(Sub) \
V(Throw) \
V(Typeof) \
@@ -1579,6 +1583,12 @@
ASSERT(first <= last);
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
+ if ((FIRST_STRING_TYPE < first && last <= LAST_STRING_TYPE) ||
+ (FIRST_STRING_TYPE <= first && last < LAST_STRING_TYPE)) {
+ // A particular string instance type can change because of GC or
+ // externalization, but the value still remains a string.
+ SetFlag(kDependsOnMaps);
+ }
}
virtual bool IsCheckInstruction() const { return true; }
@@ -2937,6 +2947,61 @@
};
+class HStringCharCodeAt: public HBinaryOperation {
+ public:
+ HStringCharCodeAt(HValue* string, HValue* index)
+ : HBinaryOperation(string, index) {
+ set_representation(Representation::Integer32());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ // The index is supposed to be Integer32.
+ return (index == 1) ? Representation::Integer32()
+ : Representation::Tagged();
+ }
+
+ virtual bool DataEquals(HValue* other) const { return true; }
+
+ HValue* string() const { return OperandAt(0); }
+ HValue* index() const { return OperandAt(1); }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string_char_code_at")
+
+ protected:
+ virtual Range* InferRange() {
+ return new Range(0, String::kMaxUC16CharCode);
+ }
+};
+
+
+class HStringLength: public HUnaryOperation {
+ public:
+ explicit HStringLength(HValue* string) : HUnaryOperation(string) {
+ set_representation(Representation::Tagged());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return Representation::Tagged();
+ }
+
+ virtual HType CalculateInferredType() const {
+ STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+ return HType::Smi();
+ }
+
+ virtual bool DataEquals(HValue* other) const { return true; }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringLength, "string_length")
+
+ protected:
+ virtual Range* InferRange() {
+ return new Range(0, String::kMaxLength);
+ }
+};
+
+
class HMaterializedLiteral: public HInstruction {
public:
HMaterializedLiteral(int index, int depth)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Tue Jan 18 05:43:48 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Wed Jan 19 12:05:22 2011
@@ -34,6 +34,7 @@
#include "lithium-allocator.h"
#include "parser.h"
#include "scopes.h"
+#include "stub-cache.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/lithium-codegen-ia32.h"
@@ -4146,12 +4147,29 @@
}
-bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
+bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
+ HValue* receiver,
+ Handle<Map> receiver_map,
+ CheckType check_type) {
+ ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
// Try to inline calls like Math.* as operations in the calling function.
- if (!expr->target()->shared()->IsBuiltinMathFunction()) return false;
+ if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
+ case kStringCharCodeAt:
+ if (argument_count == 2 && check_type == STRING_CHECK) {
+ HValue* index = Pop();
+ HValue* string = Pop();
+ ASSERT(!expr->holder().is_null());
+ AddInstruction(new HCheckPrototypeMaps(
+ oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
+ expr->holder()));
+ HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ ast_context()->ReturnInstruction(result, expr->id());
+ return true;
+ }
+ break;
case kMathRound:
case kMathFloor:
case kMathAbs:
@@ -4159,7 +4177,8 @@
case kMathLog:
case kMathSin:
case kMathCos:
- if (argument_count == 2) {
+ if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* argument = Pop();
Drop(1); // Receiver.
HUnaryMathOperation* op = new HUnaryMathOperation(argument, id);
@@ -4169,7 +4188,8 @@
}
break;
case kMathPow:
- if (argument_count == 3) {
+ if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* right = Pop();
HValue* left = Pop();
Pop(); // Pop receiver.
@@ -4179,8 +4199,6 @@
double exponent = HConstant::cast(right)->DoubleValue();
if (exponent == 0.5) {
result = new HUnaryMathOperation(left, kMathPowHalf);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
} else if (exponent == -0.5) {
HConstant* double_one =
new HConstant(Handle<Object>(Smi::FromInt(1)),
@@ -4193,22 +4211,18 @@
// an environment simulation here.
ASSERT(!square_root->HasSideEffects());
result = new HDiv(double_one, square_root);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
} else if (exponent == 2.0) {
result = new HMul(left, left);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
}
} else if (right->IsConstant() &&
- HConstant::cast(right)->HasInteger32Value() &&
- HConstant::cast(right)->Integer32Value() == 2) {
+ HConstant::cast(right)->HasInteger32Value() &&
+ HConstant::cast(right)->Integer32Value() == 2) {
result = new HMul(left, left);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
}
- result = new HPower(left, right);
+ if (result == NULL) {
+ result = new HPower(left, right);
+ }
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -4261,6 +4275,13 @@
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
+
+
+static bool HasCustomCallGenerator(Handle<JSFunction> function) {
+ SharedFunctionInfo* info = function->shared();
+ return info->HasBuiltinFunctionId() &&
+
CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
+}
void HGraphBuilder::VisitCall(Call* expr) {
@@ -4309,30 +4330,44 @@
expr->RecordTypeFeedback(oracle());
ZoneMapList* types = expr->GetReceiverTypes();
- if (expr->IsMonomorphic() && expr->check_type() == RECEIVER_MAP_CHECK)
{
- AddCheckConstantFunction(expr, receiver, types->first(), true);
-
- if (TryMathFunctionInline(expr)) {
+ if (expr->IsMonomorphic()) {
+ Handle<Map> receiver_map =
+ (types == NULL) ? Handle<Map>::null() : types->first();
+ if (TryInlineBuiltinFunction(expr,
+ receiver,
+ receiver_map,
+ expr->check_type())) {
return;
- } else if (TryInline(expr)) {
- if (subgraph()->HasExit()) {
- HValue* return_value = Pop();
- // If we inlined a function in a test context then we need to
emit
- // a simulate here to shadow the ones at the end of the
- // predecessor blocks. Those environments contain the return
- // value on top and do not correspond to any actual state of the
- // unoptimized code.
- if (ast_context()->IsEffect()) AddSimulate(expr->id());
- ast_context()->ReturnValue(return_value);
- }
- return;
- } else {
- // Check for bailout, as the TryInline call in the if condition
above
- // might return false due to bailout during hydrogen processing.
- CHECK_BAILOUT;
- call = new HCallConstantFunction(expr->target(), argument_count);
}
+ if (HasCustomCallGenerator(expr->target()) ||
+ expr->check_type() != RECEIVER_MAP_CHECK) {
+ // When the target has a custom call IC generator, use the IC,
+ // because it is likely to generate better code. Also use the
+ // IC when a primitive receiver check is required.
+ call = new HCallNamed(name, argument_count);
+ } else {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
+
+ if (TryInline(expr)) {
+ if (subgraph()->HasExit()) {
+ HValue* return_value = Pop();
+ // If we inlined a function in a test context then we need to
emit
+ // a simulate here to shadow the ones at the end of the
+ // predecessor blocks. Those environments contain the return
+ // value on top and do not correspond to any actual state of
the
+ // unoptimized code.
+ if (ast_context()->IsEffect()) AddSimulate(expr->id());
+ ast_context()->ReturnValue(return_value);
+ }
+ return;
+ } else {
+ // Check for bailout, as the TryInline call in the if condition
above
+ // might return false due to bailout during hydrogen processing.
+ CHECK_BAILOUT;
+ call = new HCallConstantFunction(expr->target(), argument_count);
+ }
+ }
} else if (types != NULL && types->length() > 1) {
ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
HandlePolymorphicCallNamed(expr, receiver, types, name);
@@ -4718,6 +4753,18 @@
BAILOUT("invalid lhs in count operation");
}
}
+
+
+HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string,
+ HValue* index) {
+ AddInstruction(new HCheckNonSmi(string));
+ AddInstruction(new HCheckInstanceType(
+ string, FIRST_STRING_TYPE, LAST_STRING_TYPE));
+ HStringLength* length = new HStringLength(string);
+ AddInstruction(length);
+ AddInstruction(new HBoundsCheck(index, length));
+ return new HStringCharCodeAt(string, index);
+}
HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
@@ -5129,7 +5176,11 @@
// Fast support for charCodeAt(n).
void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int
ast_id) {
- BAILOUT("inlined runtime function: StringCharCodeAt");
+ ASSERT(argument_count == 2);
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ ast_context()->ReturnInstruction(result, ast_id);
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Tue Jan 18 05:43:48 2011
+++ /branches/bleeding_edge/src/hydrogen.h Wed Jan 19 12:05:22 2011
@@ -748,7 +748,10 @@
bool TryArgumentsAccess(Property* expr);
bool TryCallApply(Call* expr);
bool TryInline(Call* expr);
- bool TryMathFunctionInline(Call* expr);
+ bool TryInlineBuiltinFunction(Call* expr,
+ HValue* receiver,
+ Handle<Map> receiver_map,
+ CheckType check_type);
void TraceInline(Handle<JSFunction> target, bool result);
void HandleGlobalVariableAssignment(Variable* var,
@@ -772,6 +775,8 @@
ZoneMapList* types,
Handle<String> name);
+ HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
+ HValue* index);
HInstruction* BuildBinaryOperation(BinaryOperation* expr,
HValue* left,
HValue* right);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jan 19
02:17:18 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jan 19
12:05:22 2011
@@ -2648,6 +2648,135 @@
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
+
+
+void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
+ class DeferredStringCharCodeAt: public LDeferredCode {
+ public:
+ DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
+ : LDeferredCode(codegen), instr_(instr) { }
+ virtual void Generate() {
codegen()->DoDeferredStringCharCodeAt(instr_); }
+ private:
+ LStringCharCodeAt* instr_;
+ };
+
+ DeferredStringCharCodeAt* deferred = new DeferredStringCharCodeAt(this,
+ instr);
+
+ Register string = ToRegister(instr->string());
+ Register index = no_reg;
+ int const_index = -1;
+ if (instr->index()->IsConstantOperand()) {
+ const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+ } else {
+ index = ToRegister(instr->index());
+ }
+ Register result = ToRegister(instr->result());
+
+ NearLabel flat_string, ascii_string, done;
+
+ // Fetch the instance type of the receiver into result register.
+ __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
+
+ // We need special handling for non-flat strings.
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ test(result, Immediate(kStringRepresentationMask));
+ __ j(zero, &flat_string);
+
+ // Handle non-flat strings.
+ __ test(result, Immediate(kIsConsStringMask));
+ __ j(zero, deferred->entry());
+
+ // ConsString.
+ // 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.
+ __ cmp(FieldOperand(string, ConsString::kSecondOffset),
+ Immediate(Factory::empty_string()));
+ __ j(not_equal, deferred->entry());
+ // Get the first of the two strings and load its instance type.
+ __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
+ __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
+ __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
+ // If the first cons component is also non-flat, then go to runtime.
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ test(result, Immediate(kStringRepresentationMask));
+ __ j(not_zero, deferred->entry());
+
+ // Check for 1-byte or 2-byte string.
+ __ bind(&flat_string);
+ STATIC_ASSERT(kAsciiStringTag != 0);
+ __ test(result, Immediate(kStringEncodingMask));
+ __ j(not_zero, &ascii_string);
+
+ // 2-byte string.
+ // Load the 2-byte character code into the result register.
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ if (index.is_valid()) {
+ __ movzx_w(result, FieldOperand(string,
+ index, times_2,
+ SeqTwoByteString::kHeaderSize));
+ } else {
+ __ movzx_w(result, FieldOperand(
+ string, SeqTwoByteString::kHeaderSize + 2 * const_index));
+ }
+ __ jmp(&done);
+
+ // ASCII string.
+ // Load the byte into the result register.
+ __ bind(&ascii_string);
+ if (index.is_valid()) {
+ __ movzx_b(result, FieldOperand(string,
+ index, times_1,
+ SeqAsciiString::kHeaderSize));
+ } else {
+ __ movzx_b(result, FieldOperand(string,
+ SeqAsciiString::kHeaderSize +
const_index));
+ }
+ __ bind(&done);
+ __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
+ Register string = ToRegister(instr->string());
+ Register result = ToRegister(instr->result());
+
+ // TODO(3095996): Get rid of this. For now, we need to make the
+ // result register contain a valid pointer because it is already
+ // contained in the register pointer map.
+ __ Set(result, Immediate(0));
+
+ __ PushSafepointRegisters();
+ __ push(string);
+ // Push the index as a smi.
+ if (instr->index()->IsConstantOperand()) {
+ int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+ __ push(Immediate(Smi::FromInt(const_index)));
+ } else {
+ Register index = ToRegister(instr->index());
+ __ SmiTag(index);
+ __ push(index);
+ }
+ __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(eax);
+ }
+ __ SmiUntag(eax);
+ __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax);
+ __ PopSafepointRegisters();
+}
+
+
+void LCodeGen::DoStringLength(LStringLength* instr) {
+ Register string = ToRegister(instr->string());
+ Register result = ToRegister(instr->result());
+ __ mov(result, FieldOperand(string, String::kLengthOffset));
+}
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
@@ -3076,13 +3205,19 @@
InstanceType last = instr->hydrogen()->last();
__ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
- __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
- static_cast<int8_t>(first));
// If there is only one type in the interval check for equality.
if (first == last) {
+ __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
+ static_cast<int8_t>(first));
DeoptimizeIf(not_equal, instr->environment());
- } else {
+ } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
+ // String has a dedicated bit in instance type.
+ __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset),
kIsNotStringMask);
+ DeoptimizeIf(not_zero, instr->environment());
+ } else {
+ __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
+ static_cast<int8_t>(first));
DeoptimizeIf(below, instr->environment());
// Omit check for the last type.
if (last != LAST_TYPE) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Mon Jan 17
03:25:36 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Wed Jan 19
12:05:22 2011
@@ -92,6 +92,7 @@
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
void DoDeferredStackCheck(LGoto* instr);
+ void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Jan 18 06:25:05
2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Wed Jan 19 12:05:22
2011
@@ -1739,6 +1739,20 @@
LStoreNamedGeneric* result = new LStoreNamedGeneric(obj, val);
return MarkAsCall(result, instr);
}
+
+
+LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
+ LOperand* string = UseRegister(instr->string());
+ LOperand* index = UseRegisterOrConstant(instr->index());
+ return AssignEnvironment(AssignPointerMap(DefineAsRegister(
+ new LStringCharCodeAt(string, index))));
+}
+
+
+LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
+ LOperand* string = UseRegisterAtStart(instr->value());
+ return DefineAsRegister(new LStringLength(string));
+}
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Tue Jan 18 06:25:05 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Wed Jan 19 12:05:22 2011
@@ -114,6 +114,7 @@
// LStoreNamed
// LStoreNamedField
// LStoreNamedGeneric
+// LStringCharCodeAt
// LBitNotI
// LCallNew
// LCheckFunction
@@ -141,6 +142,7 @@
// LReturn
// LSmiTag
// LStoreGlobal
+// LStringLength
// LTaggedToI
// LThrow
// LTypeof
@@ -253,6 +255,8 @@
V(StoreKeyedGeneric) \
V(StoreNamedField) \
V(StoreNamedGeneric) \
+ V(StringCharCodeAt) \
+ V(StringLength) \
V(SubI) \
V(TaggedToI) \
V(Throw) \
@@ -1590,6 +1594,34 @@
};
+class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LStringCharCodeAt(LOperand* string, LOperand* index) {
+ inputs_[0] = string;
+ inputs_[1] = index;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
+ DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
+
+ LOperand* string() { return inputs_[0]; }
+ LOperand* index() { return inputs_[1]; }
+};
+
+
+class LStringLength: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LStringLength(LOperand* string) {
+ inputs_[0] = string;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StringLength, "string-length")
+ DECLARE_HYDROGEN_ACCESSOR(StringLength)
+
+ LOperand* string() { return inputs_[0]; }
+};
+
+
class LCheckFunction: public LTemplateInstruction<0, 1> {
public:
explicit LCheckFunction(LOperand* value) {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue Jan 18 08:54:48 2011
+++ /branches/bleeding_edge/src/objects-inl.h Wed Jan 19 12:05:22 2011
@@ -3077,12 +3077,6 @@
bool SharedFunctionInfo::HasBuiltinFunctionId() {
return function_data()->IsSmi();
}
-
-
-bool SharedFunctionInfo::IsBuiltinMathFunction() {
- return HasBuiltinFunctionId() &&
- builtin_function_id() >= kFirstMathFunctionId;
-}
BuiltinFunctionId SharedFunctionInfo::builtin_function_id() {
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Wed Dec 22 05:04:47 2010
+++ /branches/bleeding_edge/src/objects-printer.cc Wed Jan 19 12:05:22 2011
@@ -395,6 +395,7 @@
case JS_BUILTINS_OBJECT_TYPE: return "JS_BUILTINS_OBJECT";
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
case PROXY_TYPE: return "PROXY";
+ case LAST_STRING_TYPE: return "LAST_STRING_TYPE";
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
=======================================
--- /branches/bleeding_edge/src/objects.h Wed Jan 19 02:17:18 2011
+++ /branches/bleeding_edge/src/objects.h Wed Jan 19 12:05:22 2011
@@ -455,6 +455,7 @@
enum InstanceType {
// String types.
+ // FIRST_STRING_TYPE
SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kSeqStringTag,
ASCII_SYMBOL_TYPE = kAsciiStringTag | kSymbolTag | kSeqStringTag,
CONS_SYMBOL_TYPE = kTwoByteStringTag | kSymbolTag | kConsStringTag,
@@ -471,6 +472,7 @@
EXTERNAL_STRING_TYPE = kTwoByteStringTag | kExternalStringTag,
EXTERNAL_STRING_WITH_ASCII_DATA_TYPE =
kTwoByteStringTag | kExternalStringTag | kAsciiDataHintTag,
+ // LAST_STRING_TYPE
EXTERNAL_ASCII_STRING_TYPE = kAsciiStringTag | kExternalStringTag,
PRIVATE_EXTERNAL_ASCII_STRING_TYPE = EXTERNAL_ASCII_STRING_TYPE,
@@ -533,6 +535,8 @@
LAST_TYPE = JS_FUNCTION_TYPE,
INVALID_TYPE = FIRST_TYPE - 1,
FIRST_NONSTRING_TYPE = MAP_TYPE,
+ FIRST_STRING_TYPE = FIRST_TYPE,
+ LAST_STRING_TYPE = FIRST_NONSTRING_TYPE - 1,
// Boundaries for testing for an external array.
FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_BYTE_ARRAY_TYPE,
LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_FLOAT_ARRAY_TYPE,
@@ -4070,7 +4074,6 @@
inline bool IsApiFunction();
inline FunctionTemplateInfo* get_api_func_data();
inline bool HasBuiltinFunctionId();
- inline bool IsBuiltinMathFunction();
inline BuiltinFunctionId builtin_function_id();
// [script info]: Script from which the function originates.
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Wed Jan 19 02:17:18 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Wed Jan 19 12:05:22 2011
@@ -1463,6 +1463,18 @@
Abort("Unimplemented: %s", "DoStoreNamedGeneric");
return NULL;
}
+
+
+LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
+ Abort("Unimplemented: %s", "DoStringCharCodeAt");
+ return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
+ Abort("Unimplemented: %s", "DoStringLength");
+ return NULL;
+}
LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev