[Interpreter] Add ClassOf intrinsic.

BUG=v8:4280

Review-Url: https://codereview.chromium.org/2128233002
Cr-Commit-Position: refs/heads/master@{#37637}
This commit is contained in:
rmcilroy 2016-07-11 04:45:26 -07:00 committed by Commit bot
parent 18551d7a32
commit 4f2d37da0c
5 changed files with 106 additions and 2 deletions

View File

@ -638,6 +638,26 @@ Node* CodeStubAssembler::LoadMapInobjectProperties(Node* map) {
MachineType::Uint8());
}
Node* CodeStubAssembler::LoadMapConstructor(Node* map) {
Variable result(this, MachineRepresentation::kTagged);
result.Bind(LoadObjectField(map, Map::kConstructorOrBackPointerOffset));
Label done(this), loop(this, &result);
Goto(&loop);
Bind(&loop);
{
GotoIf(WordIsSmi(result.value()), &done);
Node* is_map_type =
Word32Equal(LoadInstanceType(result.value()), Int32Constant(MAP_TYPE));
GotoUnless(is_map_type, &done);
result.Bind(
LoadObjectField(result.value(), Map::kConstructorOrBackPointerOffset));
Goto(&loop);
}
Bind(&done);
return result.value();
}
Node* CodeStubAssembler::LoadNameHashField(Node* name) {
return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32());
}

View File

@ -159,6 +159,8 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadMapInstanceSize(compiler::Node* map);
// Load the inobject properties count of a Map (valid only for JSObjects).
compiler::Node* LoadMapInobjectProperties(compiler::Node* map);
// Load the constructor of a Map (equivalent to Map::GetConstructor()).
compiler::Node* LoadMapConstructor(compiler::Node* map);
// Load the hash field of a name.
compiler::Node* LoadNameHashField(compiler::Node* name);

View File

@ -103,11 +103,11 @@ Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context,
return result.value();
}
Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type,
Node* IntrinsicsHelper::CompareInstanceType(Node* object, int type,
InstanceTypeCompareMode mode) {
InterpreterAssembler::Variable return_value(assembler_,
MachineRepresentation::kTagged);
Node* instance_type = __ LoadInstanceType(map);
Node* instance_type = __ LoadInstanceType(object);
InterpreterAssembler::Label if_true(assembler_), if_false(assembler_),
end(assembler_);
@ -340,6 +340,66 @@ Node* IntrinsicsHelper::ValueOf(Node* args_reg, Node* arg_count,
return return_value.value();
}
Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count,
Node* context) {
InterpreterAssembler::Variable return_value(assembler_,
MachineRepresentation::kTagged);
InterpreterAssembler::Label done(assembler_), null(assembler_),
function(assembler_), non_function_constructor(assembler_);
Node* object = __ LoadRegister(args_reg);
// If the object is not a JSReceiver, we return null.
__ GotoIf(__ WordIsSmi(object), &null);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
Node* is_js_receiver = CompareInstanceType(object, FIRST_JS_RECEIVER_TYPE,
kInstanceTypeGreaterThanOrEqual);
__ GotoUnless(is_js_receiver, &null);
// Return 'Function' for JSFunction and JSBoundFunction objects.
Node* is_function = CompareInstanceType(object, FIRST_FUNCTION_TYPE,
kInstanceTypeGreaterThanOrEqual);
STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
__ GotoIf(is_function, &function);
// Check if the constructor in the map is a JS function.
Node* constructor = __ LoadMapConstructor(__ LoadMap(object));
Node* constructor_is_js_function =
CompareInstanceType(constructor, JS_FUNCTION_TYPE, kInstanceTypeEqual);
__ GotoUnless(constructor_is_js_function, &non_function_constructor);
// Grab the instance class name from the constructor function.
Node* shared =
__ LoadObjectField(constructor, JSFunction::kSharedFunctionInfoOffset);
return_value.Bind(
__ LoadObjectField(shared, SharedFunctionInfo::kInstanceClassNameOffset));
__ Goto(&done);
// Non-JS objects have class null.
__ Bind(&null);
{
return_value.Bind(__ LoadRoot(Heap::kNullValueRootIndex));
__ Goto(&done);
}
// Functions have class 'Function'.
__ Bind(&function);
{
return_value.Bind(__ LoadRoot(Heap::kFunction_stringRootIndex));
__ Goto(&done);
}
// Objects with a non-function constructor have class 'Object'.
__ Bind(&non_function_constructor);
{
return_value.Bind(__ LoadRoot(Heap::kObject_stringRootIndex));
__ Goto(&done);
}
__ Bind(&done);
return return_value.value();
}
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
InterpreterAssembler::Label match(assembler_);
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));

View File

@ -26,6 +26,7 @@ namespace interpreter {
// expected number of arguments (-1 denoting argument count is variable).
#define INTRINSICS_LIST(V) \
V(Call, call, -1) \
V(ClassOf, class_of, 1) \
V(HasProperty, has_property, 2) \
V(IsArray, is_array, 1) \
V(IsJSProxy, is_js_proxy, 1) \

View File

@ -267,6 +267,27 @@ TEST(ValueOf) {
->SameValue(*helper.NewObject("'foobar'")));
}
TEST(ClassOf) {
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
Factory* factory = isolate->factory();
InvokeIntrinsicHelper helper(handles.main_isolate(), handles.main_zone(),
Runtime::kInlineClassOf);
CHECK_EQ(*helper.Invoke(helper.NewObject("123")), *factory->null_value());
CHECK_EQ(*helper.Invoke(helper.NewObject("'true'")), *factory->null_value());
CHECK_EQ(*helper.Invoke(helper.NewObject("'foo'")), *factory->null_value());
CHECK(helper.Invoke(helper.NewObject("({a:1})"))
->SameValue(*helper.NewObject("'Object'")));
CHECK(helper.Invoke(helper.NewObject("(function foo() {})"))
->SameValue(*helper.NewObject("'Function'")));
CHECK(helper.Invoke(helper.NewObject("new Date()"))
->SameValue(*helper.NewObject("'Date'")));
CHECK(helper.Invoke(helper.NewObject("new Set"))
->SameValue(*helper.NewObject("'Set'")));
CHECK(helper.Invoke(helper.NewObject("/x/"))
->SameValue(*helper.NewObject("'RegExp'")));
}
} // namespace interpreter
} // namespace internal
} // namespace v8