[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:
parent
18551d7a32
commit
4f2d37da0c
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user