Commit c03db758 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

Some string optimizations:

 * Inlined checks for strings and regexps.
 * Rewrote split for the non-regexp case.
 * Implemented one-char case for lastIndexOf.

Review URL: http://codereview.chromium.org/596122

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3917 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 24011207
......@@ -3420,6 +3420,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0));
JumpTarget answer;
// We need the CC bits to come out as not_equal in the case where the
// object is a smi. This can't be done with the usual test opcode so
// we use XOR to get the right CC bits.
frame_->EmitPop(r0);
__ and_(r1, r0, Operand(kSmiTagMask));
__ eor(r1, r1, Operand(kSmiTagMask), SetCC);
answer.Branch(ne);
// It is a heap object - get the map. Check if the object is a regexp.
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
answer.Bind();
cc_reg_ = eq;
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
......
......@@ -359,6 +359,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
......
......@@ -360,6 +360,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateIsSmi, "_IsSmi"},
{&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
{&CodeGenerator::GenerateIsArray, "_IsArray"},
{&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
{&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
{&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
{&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
......
......@@ -5422,6 +5422,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
__ test(value.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(equal);
// It is a heap object - get map.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, temp.reg());
value.Unuse();
temp.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
......@@ -6370,13 +6389,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
destination()->false_target()->Branch(not_zero);
__ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
__ movzx_b(temp.reg(),
FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
__ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
__ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg());
temp.Unuse();
answer.Unuse();
destination()->Split(less);
destination()->Split(below);
} else if (check->Equals(Heap::boolean_symbol())) {
__ cmp(answer.reg(), Factory::true_value());
......
......@@ -551,6 +551,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
......
......@@ -74,6 +74,10 @@ const kYearShift = 9;
const kMonthShift = 5;
# Type query macros.
#
# Note: We have special support for typeof(foo) === 'bar' in the compiler.
# It will *not* generate a runtime typeof call for the most important
# values of 'bar'.
macro IS_NULL(arg) = (arg === null);
macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
......@@ -83,7 +87,7 @@ macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp');
macro IS_REGEXP(arg) = (%_IsRegExp(arg));
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
......@@ -97,9 +101,11 @@ macro FLOOR(arg) = $floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
# Macros implemented in Python.
python macro CHAR_CODE(str) = ord(str[1]);
......
......@@ -305,6 +305,11 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
......@@ -365,6 +370,11 @@ void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
UNIMPLEMENTED_MIPS();
}
......@@ -498,4 +508,3 @@ int CompareStub::MinorKey() {
#undef __
} } // namespace v8::internal
......@@ -210,6 +210,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
......@@ -241,6 +242,8 @@ class CodeGenerator: public AstVisitor {
void GenerateSubString(ZoneList<Expression*>* args);
void GenerateStringCompare(ZoneList<Expression*>* args);
void GenerateRegExpExec(ZoneList<Expression*>* args);
void GenerateNumberToString(ZoneList<Expression*>* args);
// Fast support for Math.sin and Math.cos.
inline void GenerateMathSin(ZoneList<Expression*>* args);
......@@ -308,4 +311,3 @@ class CodeGenerator: public AstVisitor {
} } // namespace v8::internal
#endif // V8_MIPS_CODEGEN_MIPS_H_
......@@ -2276,6 +2276,20 @@ static int SingleCharIndexOf(Vector<const schar> string,
return -1;
}
template <typename schar>
static int SingleCharLastIndexOf(Vector<const schar> string,
schar pattern_char,
int start_index) {
for (int i = start_index; i >= 0; i--) {
if (pattern_char == string[i]) {
return i;
}
}
return -1;
}
// Trivial string search for shorter strings.
// On return, if "complete" is set to true, the return value is the
// final result of searching for the patter in the subject.
......@@ -2459,16 +2473,17 @@ static Object* Runtime_StringLastIndexOf(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
CONVERT_CHECKED(String, sub, args[0]);
CONVERT_CHECKED(String, pat, args[1]);
CONVERT_ARG_CHECKED(String, sub, 0);
CONVERT_ARG_CHECKED(String, pat, 1);
Object* index = args[2];
sub->TryFlattenIfNotFlat();
pat->TryFlattenIfNotFlat();
uint32_t start_index;
if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
if (!sub->IsFlat()) {
FlattenString(sub);
}
uint32_t pattern_length = pat->length();
uint32_t sub_length = sub->length();
......@@ -2476,6 +2491,25 @@ static Object* Runtime_StringLastIndexOf(Arguments args) {
start_index = sub_length - pattern_length;
}
if (pattern_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (sub->IsAsciiRepresentation()) {
uc16 pchar = pat->Get(0);
if (pchar > String::kMaxAsciiCharCode) {
return Smi::FromInt(-1);
}
return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
static_cast<char>(pat->Get(0)),
start_index));
} else {
return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
pat->Get(0),
start_index));
}
}
pat->TryFlattenIfNotFlat();
for (int i = start_index; i >= 0; i--) {
bool found = true;
for (uint32_t j = 0; j < pattern_length; j++) {
......
......@@ -529,6 +529,13 @@ function ToString(x) {
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
function NonStringToString(x) {
if (IS_NUMBER(x)) return %NumberToString(x);
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
if (IS_UNDEFINED(x)) return 'undefined';
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
// ECMA-262, section 9.9, page 36.
function ToObject(x) {
......
......@@ -34,7 +34,7 @@
// Set the String function and constructor.
%SetCode($String, function(x) {
var value = %_ArgumentsLength() == 0 ? '' : ToString(x);
var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
......@@ -64,7 +64,7 @@ function StringValueOf() {
function StringCharAt(pos) {
var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) {
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos);
if (index >= subject.length || index < 0) return "";
char_code = %StringCharCodeAt(subject, index);
......@@ -79,7 +79,7 @@ function StringCharCodeAt(pos) {
if (%_IsSmi(fast_answer)) {
return fast_answer;
}
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos);
return %StringCharCodeAt(subject, index);
}
......@@ -88,7 +88,7 @@ function StringCharCodeAt(pos) {
// ECMA-262, section 15.5.4.6
function StringConcat() {
var len = %_ArgumentsLength();
var this_as_string = IS_STRING(this) ? this : ToString(this);
var this_as_string = TO_STRING_INLINE(this);
if (len === 1) {
return this_as_string + %_Arguments(0);
}
......@@ -96,7 +96,7 @@ function StringConcat() {
parts[0] = this_as_string;
for (var i = 0; i < len; i++) {
var part = %_Arguments(i);
parts[i + 1] = IS_STRING(part) ? part : ToString(part);
parts[i + 1] = TO_STRING_INLINE(part);
}
return %StringBuilderConcat(parts, len + 1, "");
}
......@@ -107,8 +107,8 @@ function StringConcat() {
// ECMA-262 section 15.5.4.7
function StringIndexOf(searchString /* position */) { // length == 1
var subject_str = ToString(this);
var pattern_str = ToString(searchString);
var subject_str = TO_STRING_INLINE(this);
var pattern_str = TO_STRING_INLINE(searchString);
var subject_str_len = subject_str.length;
var pattern_str_len = pattern_str.length;
var index = 0;
......@@ -125,9 +125,9 @@ function StringIndexOf(searchString /* position */) { // length == 1
// ECMA-262 section 15.5.4.8
function StringLastIndexOf(searchString /* position */) { // length == 1
var sub = ToString(this);
var sub = TO_STRING_INLINE(this);
var subLength = sub.length;
var pat = ToString(searchString);
var pat = TO_STRING_INLINE(searchString);
var patLength = pat.length;
var index = subLength - patLength;
if (%_ArgumentsLength() > 1) {
......@@ -156,8 +156,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
function StringLocaleCompare(other) {
if (%_ArgumentsLength() === 0) return 0;
var this_str = ToString(this);
var other_str = ToString(other);
var this_str = TO_STRING_INLINE(this);
var other_str = TO_STRING_INLINE(other);
return %StringLocaleCompare(this_str, other_str);
}
......@@ -165,7 +165,7 @@ function StringLocaleCompare(other) {
// ECMA-262 section 15.5.4.10
function StringMatch(regexp) {
if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
if (!regexp.global) return regexp.exec(subject);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
......@@ -200,7 +200,7 @@ var reusableMatchInfo = [2, "", "", -1, -1];
// ECMA-262, section 15.5.4.11
function StringReplace(search, replace) {
var subject = IS_STRING(this) ? this : ToString(this);
var subject = TO_STRING_INLINE(this);
// Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) {
......@@ -213,7 +213,7 @@ function StringReplace(search, replace) {
}
// Convert the search argument to a string and search for it.
search = IS_STRING(search) ? search : ToString(search);
search = TO_STRING_INLINE(search);
var start = %StringIndexOf(subject, search, 0);
if (start < 0) return subject;
var end = start + search.length;
......@@ -228,7 +228,7 @@ function StringReplace(search, replace) {
} else {
reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end;
if (!IS_STRING(replace)) replace = ToString(replace);
replace = TO_STRING_INLINE(replace);
ExpandReplacement(replace, subject, reusableMatchInfo, builder);
}
......@@ -241,7 +241,7 @@ function StringReplace(search, replace) {
// Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) {
replace = ToString(replace);
replace = TO_STRING_INLINE(replace);
return %StringReplaceRegExpWithString(subject,
regexp,
replace,
......@@ -462,7 +462,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) {
// ECMA-262 section 15.5.4.12
function StringSearch(re) {
var regexp = new ORIGINAL_REGEXP(re);
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var last_idx = regexp.lastIndex; // keep old lastIndex
regexp.lastIndex = 0; // ignore re.global property
var result = regexp.exec(s);
......@@ -476,7 +476,7 @@ function StringSearch(re) {
// ECMA-262 section 15.5.4.13
function StringSlice(start, end) {
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var s_len = s.length;
var start_i = TO_INTEGER(start);
var end_i = s_len;
......@@ -511,7 +511,7 @@ function StringSlice(start, end) {
// ECMA-262 section 15.5.4.14
function StringSplit(separator, limit) {
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
if (limit === 0) return [];
......@@ -525,18 +525,35 @@ function StringSplit(separator, limit) {
}
var length = subject.length;
if (IS_REGEXP(separator)) {
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
} else {
separator = ToString(separator);
if (!IS_REGEXP(separator)) {
separator = TO_STRING_INLINE(separator);
var separator_length = separator.length;
// If the separator string is empty then return the elements in the subject.
if (separator.length == 0) {
if (separator_length === 0) {
var result = $Array(length);
for (var i = 0; i < length; i++) result[i] = subject[i];
return result;
}
var result = [];
var start_index = 0;
var index;
while (true) {
if (start_index + separator_length > length ||
(index = %StringIndexOf(subject, separator, start_index)) === -1) {
result.push(SubString(subject, start_index, length));
break;
}
if (result.push(SubString(subject, start_index, index)) === limit) break;
start_index = index + separator_length;
}
return result;
}
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) {
if (splitMatch(separator, subject, 0, 0) != null) return [];
return [subject];
......@@ -571,7 +588,8 @@ function StringSplit(separator, limit) {
result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
if (result.length === limit) return result;
for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) {
var num_captures = NUMBER_OF_CAPTURES(matchInfo);
for (var i = 2; i < num_captures; i += 2) {
var start = matchInfo[CAPTURE(i)];
var end = matchInfo[CAPTURE(i + 1)];
if (start != -1 && end != -1) {
......@@ -591,28 +609,18 @@ function StringSplit(separator, limit) {
// Helper function used by split. This version returns the matchInfo
// instead of allocating a new array with basically the same information.
function splitMatch(separator, subject, current_index, start_index) {
if (IS_REGEXP(separator)) {
var matchInfo = DoRegExpExec(separator, subject, start_index);
if (matchInfo == null) return null;
// Section 15.5.4.14 paragraph two says that we do not allow zero length
// matches at the end of the string.
if (matchInfo[CAPTURE0] === subject.length) return null;
return matchInfo;
}
var separatorIndex = subject.indexOf(separator, start_index);
if (separatorIndex === -1) return null;
reusableMatchInfo[CAPTURE0] = separatorIndex;
reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
return reusableMatchInfo;
};
var matchInfo = DoRegExpExec(separator, subject, start_index);
if (matchInfo == null) return null;
// Section 15.5.4.14 paragraph two says that we do not allow zero length
// matches at the end of the string.
if (matchInfo[CAPTURE0] === subject.length) return null;
return matchInfo;
}
// ECMA-262 section 15.5.4.15
function StringSubstring(start, end) {
var s = this;
if (!IS_STRING(s)) s = ToString(s);
var s = TO_STRING_INLINE(this);
var s_len = s.length;
var start_i = TO_INTEGER(start);
......@@ -643,7 +651,7 @@ function StringSubstring(start, end) {
// This is not a part of ECMA-262.
function StringSubstr(start, n) {
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var len;
// Correct n: If not given, set to string length; if explicitly
......@@ -681,38 +689,38 @@ function StringSubstr(start, n) {
// ECMA-262, 15.5.4.16
function StringToLowerCase() {
return %StringToLowerCase(ToString(this));
return %StringToLowerCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.17
function StringToLocaleLowerCase() {
return %StringToLowerCase(ToString(this));
return %StringToLowerCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.18
function StringToUpperCase() {
return %StringToUpperCase(ToString(this));
return %StringToUpperCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.19
function StringToLocaleUpperCase() {
return %StringToUpperCase(ToString(this));
return %StringToUpperCase(TO_STRING_INLINE(this));
}
// ES5, 15.5.4.20
function StringTrim() {
return %StringTrim(ToString(this), true, true);
return %StringTrim(TO_STRING_INLINE(this), true, true);
}
function StringTrimLeft() {
return %StringTrim(ToString(this), true, false);
return %StringTrim(TO_STRING_INLINE(this), true, false);
}
function StringTrimRight() {
return %StringTrim(ToString(this), false, true);
return %StringTrim(TO_STRING_INLINE(this), false, true);
}
// ECMA-262, section 15.5.3.2
......@@ -731,10 +739,10 @@ function StringFromCharCode(code) {
// Helper function for very basic XSS protection.
function HtmlEscape(str) {
return ToString(str).replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
return TO_STRING_INLINE(str).replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
};
......@@ -813,7 +821,7 @@ function ReplaceResultBuilder(str) {
ReplaceResultBuilder.prototype.add = function(str) {
if (!IS_STRING(str)) str = ToString(str);
str = TO_STRING_INLINE(str);
if (str.length > 0) {
var elements = this.elements;
elements[elements.length] = str;
......
......@@ -3627,6 +3627,22 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
Condition is_smi = masm_->CheckSmi(value.reg());
destination()->false_target()->Branch(is_smi);
// It is a heap object - get map.
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
value.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
......
......@@ -536,6 +536,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment