Commit f1ffd502 authored by kasperl@chromium.org's avatar kasperl@chromium.org

Optimize %ClassOf() on IA-32 and use it instead of the

custom %HasXXXClass() calls.
Review URL: http://codereview.chromium.org/151018

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2293 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4a30e3f5
......@@ -3180,6 +3180,15 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
}
void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0)); // Load the object.
frame_->CallRuntime(Runtime::kClassOf, 1);
frame_->EmitPush(r0);
}
void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
......
......@@ -340,7 +340,8 @@ class CodeGenerator: public AstVisitor {
void GenerateArgumentsLength(ZoneList<Expression*>* args);
void GenerateArgumentsAccess(ZoneList<Expression*>* args);
// Support for accessing the value field of an object (used by Date).
// Support for accessing the class and value fields of an object.
void GenerateClassOf(ZoneList<Expression*>* args);
void GenerateValueOf(ZoneList<Expression*>* args);
void GenerateSetValueOf(ZoneList<Expression*>* args);
......
......@@ -419,6 +419,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
{&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
{&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
{&CodeGenerator::GenerateClassOf, "_ClassOf"},
{&CodeGenerator::GenerateValueOf, "_ValueOf"},
{&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
......
......@@ -5022,6 +5022,70 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
JumpTarget leave, null, function, non_function_constructor;
Load(args->at(0)); // Load the object.
Result obj = frame_->Pop();
obj.ToRegister();
frame_->Spill(obj.reg());
// If the object is a smi, we return null.
__ test(obj.reg(), Immediate(kSmiTagMask));
null.Branch(zero);
// Check that the object is a JS object but take special care of JS
// functions to make sure they have 'Function' as their class.
{ Result tmp = allocator()->Allocate();
__ mov(obj.reg(), FieldOperand(obj.reg(), HeapObject::kMapOffset));
__ movzx_b(tmp.reg(), FieldOperand(obj.reg(), Map::kInstanceTypeOffset));
__ cmp(tmp.reg(), FIRST_JS_OBJECT_TYPE);
null.Branch(less);
// As long as JS_FUNCTION_TYPE is the last instance type and it is
// right after LAST_JS_OBJECT_TYPE, we can avoid checking for
// LAST_JS_OBJECT_TYPE.
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
__ cmp(tmp.reg(), JS_FUNCTION_TYPE);
function.Branch(equal);
}
// Check if the constructor in the map is a function.
{ Result tmp = allocator()->Allocate();
__ mov(obj.reg(), FieldOperand(obj.reg(), Map::kConstructorOffset));
__ CmpObjectType(obj.reg(), JS_FUNCTION_TYPE, tmp.reg());
non_function_constructor.Branch(not_equal);
}
// The map register now contains the constructor function. Grab the
// instance class name from there.
__ mov(obj.reg(),
FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset));
__ mov(obj.reg(),
FieldOperand(obj.reg(), SharedFunctionInfo::kInstanceClassNameOffset));
frame_->Push(&obj);
leave.Jump();
// Functions have class 'Function'.
function.Bind();
frame_->Push(Factory::function_class_symbol());
leave.Jump();
// Objects with a non-function constructor have class 'Object'.
non_function_constructor.Bind();
frame_->Push(Factory::Object_symbol());
leave.Jump();
// Non-JS objects have class null.
null.Bind();
frame_->Push(Factory::null_value());
// All done.
leave.Bind();
}
void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
JumpTarget leave;
......
......@@ -529,7 +529,8 @@ class CodeGenerator: public AstVisitor {
void GenerateArgumentsLength(ZoneList<Expression*>* args);
void GenerateArgumentsAccess(ZoneList<Expression*>* args);
// Support for accessing the value field of an object (used by Date).
// Support for accessing the class and value fields of an object.
void GenerateClassOf(ZoneList<Expression*>* args);
void GenerateValueOf(ZoneList<Expression*>* args);
void GenerateSetValueOf(ZoneList<Expression*>* args);
......
......@@ -82,13 +82,15 @@ macro IS_NUMBER(arg) = (typeof(arg) === 'number');
macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_OBJECT(arg) = (typeof(arg) === 'object');
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_REGEXP(arg) = %HasRegExpClass(arg);
macro IS_ARRAY(arg) = %HasArrayClass(arg);
macro IS_DATE(arg) = %HasDateClass(arg);
macro IS_NUMBER_WRAPPER(arg) = %HasNumberClass(arg);
macro IS_STRING_WRAPPER(arg) = %HasStringClass(arg);
macro IS_ERROR(arg) = (%ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%ClassOf(arg) === 'Script');
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp');
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments');
macro FLOOR(arg) = %Math_floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
......
......@@ -580,7 +580,7 @@ inherits(ObjectMirror, ValueMirror);
ObjectMirror.prototype.className = function() {
return %ClassOf(this.value_);
return %_ClassOf(this.value_);
};
......
......@@ -413,48 +413,6 @@ static Object* Runtime_ClassOf(Arguments args) {
}
static Object* Runtime_HasStringClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
}
static Object* Runtime_HasDateClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
}
static Object* Runtime_HasArrayClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
}
static Object* Runtime_HasFunctionClass(Arguments args) {
return Heap::ToBoolean(
args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
}
static Object* Runtime_HasNumberClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
}
static Object* Runtime_HasBooleanClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
}
static Object* Runtime_HasArgumentsClass(Arguments args) {
return Heap::ToBoolean(
args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
}
static Object* Runtime_HasRegExpClass(Arguments args) {
return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
}
static Object* Runtime_IsInPrototypeChain(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
......
......@@ -173,14 +173,6 @@ namespace internal {
F(GetScript, 1) \
\
F(ClassOf, 1) \
F(HasDateClass, 1) \
F(HasStringClass, 1) \
F(HasArrayClass, 1) \
F(HasFunctionClass, 1) \
F(HasNumberClass, 1) \
F(HasBooleanClass, 1) \
F(HasArgumentsClass, 1) \
F(HasRegExpClass, 1) \
F(SetCode, 2) \
\
F(CreateApiFunction, 1) \
......
......@@ -394,7 +394,7 @@ function APPLY_PREPARE(args) {
// First check whether length is a positive Smi and args is an
// array. This is the fast case. If this fails, we do the slow case
// that takes care of more eventualities.
if (%_IsArray(args)) {
if (IS_ARRAY(args)) {
length = args.length;
if (%_IsSmi(length) && length >= 0 && length < 0x800000 && IS_FUNCTION(this)) {
return length;
......@@ -415,9 +415,7 @@ function APPLY_PREPARE(args) {
}
// Make sure the arguments list has the right type.
if (args != null &&
!%HasArrayClass(args) &&
!%HasArgumentsClass(args)) {
if (args != null && !IS_ARRAY(args) && !IS_ARGUMENTS(args)) {
throw %MakeTypeError('apply_wrong_args', []);
}
......
......@@ -46,7 +46,7 @@
// ECMA-262 section 15.5.4.2
function StringToString() {
if (!IS_STRING(this) && !%HasStringClass(this))
if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
throw new $TypeError('String.prototype.toString is not generic');
return %_ValueOf(this);
}
......@@ -54,7 +54,7 @@ function StringToString() {
// ECMA-262 section 15.5.4.3
function StringValueOf() {
if (!IS_STRING(this) && !%HasStringClass(this))
if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
throw new $TypeError('String.prototype.valueOf is not generic');
return %_ValueOf(this);
}
......
......@@ -192,7 +192,7 @@ $Object.prototype.constructor = $Object;
// ECMA-262 - 15.2.4.2
function ObjectToString() {
var c = %ClassOf(this);
var c = %_ClassOf(this);
// Hide Arguments from the outside.
if (c === 'Arguments') c = 'Object';
return "[object " + c + "]";
......@@ -311,7 +311,7 @@ SetupObject();
function BooleanToString() {
// NOTE: Both Boolean objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
throw new $TypeError('Boolean.prototype.toString is not generic');
return ToString(%_ValueOf(this));
}
......@@ -320,7 +320,7 @@ function BooleanToString() {
function BooleanValueOf() {
// NOTE: Both Boolean objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
if (!IS_BOOLEAN(this) && !%HasBooleanClass(this))
if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
throw new $TypeError('Boolean.prototype.valueOf is not generic');
return %_ValueOf(this);
}
......@@ -365,7 +365,7 @@ function NumberToString(radix) {
// 'this'. This is not as dictated by ECMA-262.
var number = this;
if (!IS_NUMBER(this)) {
if (!%HasNumberClass(this))
if (!IS_NUMBER_WRAPPER(this))
throw new $TypeError('Number.prototype.toString is not generic');
// Get the value of this number in case it's an object.
number = %_ValueOf(this);
......@@ -395,7 +395,7 @@ function NumberToLocaleString() {
function NumberValueOf() {
// NOTE: Both Number objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
if (!IS_NUMBER(this) && !%HasNumberClass(this))
if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
throw new $TypeError('Number.prototype.valueOf is not generic');
return %_ValueOf(this);
}
......@@ -502,10 +502,9 @@ SetupNumber();
$Function.prototype.constructor = $Function;
function FunctionSourceString(func) {
// NOTE: Both Function objects and values can enter here as
// 'func'. This is not as dictated by ECMA-262.
if (!IS_FUNCTION(func) && !%HasFunctionClass(func))
if (!IS_FUNCTION(func)) {
throw new $TypeError('Function.prototype.toString is not generic');
}
var source = %FunctionGetSourceCode(func);
if (!IS_STRING(source)) {
......
......@@ -3430,6 +3430,15 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) {
// TODO(X64): Optimize this like it's done on IA-32.
ASSERT(args->length() == 1);
Load(args->at(0)); // Load the object.
Result result = frame_->CallRuntime(Runtime::kClassOf, 1);
frame_->Push(&result);
}
void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
JumpTarget leave;
......
......@@ -529,7 +529,8 @@ class CodeGenerator: public AstVisitor {
void GenerateArgumentsLength(ZoneList<Expression*>* args);
void GenerateArgumentsAccess(ZoneList<Expression*>* args);
// Support for accessing the value field of an object (used by Date).
// Support for accessing the class and value fields of an object.
void GenerateClassOf(ZoneList<Expression*>* args);
void GenerateValueOf(ZoneList<Expression*>* args);
void GenerateSetValueOf(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