[Interpreter] Add intrinsics called as stubs.

Adds support for intrinsics which can be called as stubs. Namely:
 - HasProperty
 - MathPow
 - NewObject
 - NumberToString
 - RegExpConstructResult
 - RegExpExec
 - Substring
 - ToString
 - ToName
 - ToLength
 - ToNumber
 - ToObject

Also adds interface descriptors for stub calls which have arguments
passed on the stack.

BUG=v8:4280
LOG=N

Review-Url: https://codereview.chromium.org/2051573002
Cr-Commit-Position: refs/heads/master@{#37185}
This commit is contained in:
rmcilroy 2016-06-22 05:22:30 -07:00 committed by Commit bot
parent 7a88ff3cc0
commit 485e77519f
10 changed files with 313 additions and 24 deletions

View File

@ -554,6 +554,12 @@ Callable CodeFactory::HasProperty(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::MathPow(Isolate* isolate) {
MathPowStub stub(isolate, MathPowStub::ON_STACK);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode) {

View File

@ -146,6 +146,8 @@ class CodeFactory final {
static Callable ConstructFunction(Isolate* isolate);
static Callable HasProperty(Isolate* isolate);
static Callable MathPow(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate);

View File

@ -434,6 +434,12 @@ class CodeStub BASE_EMBEDDED {
return NAME##Descriptor(isolate()); \
}
#define DEFINE_ON_STACK_CALL_INTERFACE_DESCRIPTOR(PARAMETER_COUNT) \
public: \
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
return OnStackArgsDescriptorBase::ForArgs(isolate(), PARAMETER_COUNT); \
}
// There are some code stubs we just can't describe right now with a
// CallInterfaceDescriptor. Isolate behavior for those cases with this macro.
// An attempt to retrieve a descriptor will fail.
@ -1328,14 +1334,18 @@ class MathPowStub: public PlatformCodeStub {
}
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override {
if (exponent_type() == TAGGED) {
if (exponent_type() == ON_STACK) {
return OnStackArgsDescriptorBase::ForArgs(isolate(), 2);
} else if (exponent_type() == TAGGED) {
return MathPowTaggedDescriptor(isolate());
} else if (exponent_type() == INTEGER) {
return MathPowIntegerDescriptor(isolate());
}
} else {
// A CallInterfaceDescriptor doesn't specify double registers (yet).
DCHECK_EQ(DOUBLE, exponent_type());
return ContextOnlyDescriptor(isolate());
}
}
private:
ExponentType exponent_type() const {
@ -2083,7 +2093,7 @@ class RegExpExecStub: public PlatformCodeStub {
public:
explicit RegExpExecStub(Isolate* isolate) : PlatformCodeStub(isolate) { }
DEFINE_CALL_INTERFACE_DESCRIPTOR(ContextOnly);
DEFINE_ON_STACK_CALL_INTERFACE_DESCRIPTOR(4);
DEFINE_PLATFORM_CODE_STUB(RegExpExec, PlatformCodeStub);
};
@ -3068,7 +3078,7 @@ class SubStringStub : public PlatformCodeStub {
public:
explicit SubStringStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(ContextOnly);
DEFINE_ON_STACK_CALL_INTERFACE_DESCRIPTOR(3);
DEFINE_PLATFORM_CODE_STUB(SubString, PlatformCodeStub);
};

View File

@ -415,6 +415,12 @@ Node* CodeAssembler::CallStub(Callable const& callable, Node* context,
result_size);
}
Node* CodeAssembler::CallStubN(Callable const& callable, Node** args,
size_t result_size) {
Node* target = HeapConstant(callable.code());
return CallStubN(callable.descriptor(), target, args, result_size);
}
Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1,
size_t result_size) {
@ -502,6 +508,16 @@ Node* CodeAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
return CallN(call_descriptor, target, args);
}
Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
Node* target, Node** args, size_t result_size) {
CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
CallDescriptor::kNoFlags, Operator::kNoProperties,
MachineType::AnyTagged(), result_size);
return CallN(call_descriptor, target, args);
}
Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
Node* arg1, Node* arg2, size_t result_size) {
Node* target = HeapConstant(callable.code());

View File

@ -311,6 +311,8 @@ class CodeAssembler {
Node* arg2, size_t result_size = 1);
Node* CallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, Node* arg3, size_t result_size = 1);
Node* CallStubN(Callable const& callable, Node** args,
size_t result_size = 1);
Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, size_t result_size = 1);
@ -325,6 +327,8 @@ class CodeAssembler {
Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, Node* arg2, Node* arg3, Node* arg4,
Node* arg5, size_t result_size = 1);
Node* CallStubN(const CallInterfaceDescriptor& descriptor, Node* target,
Node** args, size_t result_size = 1);
Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, size_t result_size = 1);

View File

@ -214,7 +214,6 @@ void MathPowTaggedDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void MathPowIntegerDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {exponent()};
@ -321,6 +320,48 @@ void ContextOnlyDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(0, nullptr);
}
CallInterfaceDescriptor OnStackArgsDescriptorBase::ForArgs(
Isolate* isolate, int parameter_count) {
switch (parameter_count) {
case 1:
return OnStackWith1ArgsDescriptor(isolate);
case 2:
return OnStackWith2ArgsDescriptor(isolate);
case 3:
return OnStackWith3ArgsDescriptor(isolate);
case 4:
return OnStackWith4ArgsDescriptor(isolate);
case 5:
return OnStackWith5ArgsDescriptor(isolate);
case 6:
return OnStackWith6ArgsDescriptor(isolate);
case 7:
return OnStackWith7ArgsDescriptor(isolate);
default:
UNREACHABLE();
return VoidDescriptor(isolate);
}
}
FunctionType*
OnStackArgsDescriptorBase::BuildCallInterfaceDescriptorFunctionTypeWithArg(
Isolate* isolate, int register_parameter_count, int parameter_count) {
DCHECK_EQ(0, register_parameter_count);
DCHECK_GT(parameter_count, 0);
Zone* zone = isolate->interface_descriptor_zone();
FunctionType* function =
Type::Function(AnyTagged(zone), AnyTagged(zone), parameter_count, zone)
->AsFunction();
for (int i = 0; i < parameter_count; i++) {
function->InitParameter(i, AnyTagged(zone));
}
return function;
}
void OnStackArgsDescriptorBase::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
data->InitializePlatformSpecific(0, nullptr);
}
void GrowArrayElementsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {

View File

@ -15,6 +15,14 @@ class PlatformInterfaceDescriptor;
#define INTERFACE_DESCRIPTOR_LIST(V) \
V(Void) \
V(ContextOnly) \
V(OnStackWith1Args) \
V(OnStackWith2Args) \
V(OnStackWith3Args) \
V(OnStackWith4Args) \
V(OnStackWith5Args) \
V(OnStackWith6Args) \
V(OnStackWith7Args) \
V(Load) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
@ -84,7 +92,6 @@ class PlatformInterfaceDescriptor;
V(StoreGlobalViaContext) \
V(MathPowTagged) \
V(MathPowInteger) \
V(ContextOnly) \
V(GrowArrayElements) \
V(InterpreterDispatch) \
V(InterpreterPushArgsAndCall) \
@ -278,6 +285,77 @@ class VoidDescriptor : public CallInterfaceDescriptor {
DECLARE_DESCRIPTOR(VoidDescriptor, CallInterfaceDescriptor)
};
class ContextOnlyDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor)
};
// The OnStackWith*ArgsDescriptors have a lot of boilerplate. The superclass
// OnStackArgsDescriptorBase is not meant to be instantiated directly and has no
// public constructors to ensure this is so.contains all the logic, and the
//
// Use OnStackArgsDescriptorBase::ForArgs(isolate, parameter_count) to
// instantiate a descriptor with the number of args.
class OnStackArgsDescriptorBase : public CallInterfaceDescriptor {
public:
static CallInterfaceDescriptor ForArgs(Isolate* isolate, int parameter_count);
protected:
OnStackArgsDescriptorBase(Isolate* isolate, CallDescriptors::Key key)
: CallInterfaceDescriptor(isolate, key) {}
void InitializePlatformSpecific(CallInterfaceDescriptorData* data) override;
FunctionType* BuildCallInterfaceDescriptorFunctionTypeWithArg(
Isolate* isolate, int register_parameter_count, int parameter_count);
};
class OnStackWith1ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith1ArgsDescriptor,
OnStackArgsDescriptorBase,
1)
};
class OnStackWith2ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith2ArgsDescriptor,
OnStackArgsDescriptorBase,
2)
};
class OnStackWith3ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith3ArgsDescriptor,
OnStackArgsDescriptorBase,
3)
};
class OnStackWith4ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith4ArgsDescriptor,
OnStackArgsDescriptorBase,
4)
};
class OnStackWith5ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith5ArgsDescriptor,
OnStackArgsDescriptorBase,
5)
};
class OnStackWith6ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith6ArgsDescriptor,
OnStackArgsDescriptorBase,
6)
};
class OnStackWith7ArgsDescriptor : public OnStackArgsDescriptorBase {
public:
DECLARE_DESCRIPTOR_WITH_BASE_AND_FUNCTION_TYPE_ARG(OnStackWith7ArgsDescriptor,
OnStackArgsDescriptorBase,
7)
};
// LoadDescriptor is used by all stubs that implement Load/KeyedLoad ICs.
class LoadDescriptor : public CallInterfaceDescriptor {
@ -774,7 +852,6 @@ class ApiGetterDescriptor : public CallInterfaceDescriptor {
static const Register CallbackRegister();
};
class MathPowTaggedDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(MathPowTaggedDescriptor, CallInterfaceDescriptor)
@ -782,7 +859,6 @@ class MathPowTaggedDescriptor : public CallInterfaceDescriptor {
static const Register exponent();
};
class MathPowIntegerDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(MathPowIntegerDescriptor, CallInterfaceDescriptor)
@ -790,12 +866,6 @@ class MathPowIntegerDescriptor : public CallInterfaceDescriptor {
static const Register exponent();
};
class ContextOnlyDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor)
};
class VarArgFunctionDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(VarArgFunctionDescriptor,

View File

@ -4,6 +4,8 @@
#include "src/interpreter/interpreter-intrinsics.h"
#include "src/code-factory.h"
namespace v8 {
namespace internal {
namespace interpreter {
@ -13,7 +15,9 @@ using compiler::Node;
#define __ assembler_->
IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler)
: assembler_(assembler) {}
: isolate_(assembler->isolate()),
zone_(assembler->zone()),
assembler_(assembler) {}
// static
bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) {
@ -227,6 +231,80 @@ Node* IntrinsicsHelper::IsSmi(Node* input, Node* arg_count, Node* context) {
return return_value.value();
}
Node* IntrinsicsHelper::IntrinsicAsStubCall(Node* args_reg, Node* context,
Callable const& callable) {
int param_count = callable.descriptor().GetParameterCount();
Node** args = zone()->NewArray<Node*>(param_count + 1); // 1 for context
for (int i = 0; i < param_count; i++) {
args[i] = __ LoadRegister(args_reg);
args_reg = __ NextRegister(args_reg);
}
args[param_count] = context;
return __ CallStubN(callable, args);
}
Node* IntrinsicsHelper::HasProperty(Node* input, Node* arg_count,
Node* context) {
return IntrinsicAsStubCall(input, context,
CodeFactory::HasProperty(isolate()));
}
Node* IntrinsicsHelper::MathPow(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::MathPow(isolate()));
}
Node* IntrinsicsHelper::NewObject(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context,
CodeFactory::FastNewObject(isolate()));
}
Node* IntrinsicsHelper::NumberToString(Node* input, Node* arg_count,
Node* context) {
return IntrinsicAsStubCall(input, context,
CodeFactory::NumberToString(isolate()));
}
Node* IntrinsicsHelper::RegExpConstructResult(Node* input, Node* arg_count,
Node* context) {
return IntrinsicAsStubCall(input, context,
CodeFactory::RegExpConstructResult(isolate()));
}
Node* IntrinsicsHelper::RegExpExec(Node* input, Node* arg_count,
Node* context) {
return IntrinsicAsStubCall(input, context,
CodeFactory::RegExpExec(isolate()));
}
Node* IntrinsicsHelper::SubString(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::SubString(isolate()));
}
Node* IntrinsicsHelper::ToString(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToString(isolate()));
}
Node* IntrinsicsHelper::ToName(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToName(isolate()));
}
Node* IntrinsicsHelper::ToLength(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToLength(isolate()));
}
Node* IntrinsicsHelper::ToInteger(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToInteger(isolate()));
}
Node* IntrinsicsHelper::ToNumber(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToNumber(isolate()));
}
Node* IntrinsicsHelper::ToObject(Node* input, Node* arg_count, Node* context) {
return IntrinsicAsStubCall(input, context, CodeFactory::ToObject(isolate()));
}
Node* IntrinsicsHelper::Call(Node* args_reg, Node* arg_count, Node* context) {
// First argument register contains the function target.
Node* function = __ LoadRegister(args_reg);

View File

@ -26,12 +26,25 @@ namespace interpreter {
// expected number of arguments (-1 denoting argument count is variable).
#define INTRINSICS_LIST(V) \
V(Call, call, -1) \
V(HasProperty, has_property, 2) \
V(IsArray, is_array, 1) \
V(IsJSProxy, is_js_proxy, 1) \
V(IsJSReceiver, is_js_receiver, 1) \
V(IsRegExp, is_regexp, 1) \
V(IsSmi, is_smi, 1) \
V(IsTypedArray, is_typed_array, 1)
V(IsTypedArray, is_typed_array, 1) \
V(MathPow, math_pow, 2) \
V(NewObject, new_object, 2) \
V(NumberToString, number_to_string, 1) \
V(RegExpConstructResult, reg_exp_construct_result, 3) \
V(RegExpExec, reg_exp_exec, 4) \
V(SubString, sub_string, 3) \
V(ToString, to_string, 1) \
V(ToName, to_name, 1) \
V(ToLength, to_length, 1) \
V(ToInteger, to_integer, 1) \
V(ToNumber, to_number, 1) \
V(ToObject, to_object, 1)
class IntrinsicsHelper {
public:
@ -63,6 +76,9 @@ class IntrinsicsHelper {
compiler::Node* IsInstanceType(compiler::Node* input, int type);
compiler::Node* CompareInstanceType(compiler::Node* map, int type,
InstanceTypeCompareMode mode);
compiler::Node* IntrinsicAsStubCall(compiler::Node* input,
compiler::Node* context,
Callable const& callable);
void AbortIfArgCountMismatch(int expected, compiler::Node* actual);
#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \
@ -71,6 +87,11 @@ class IntrinsicsHelper {
INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER)
#undef DECLARE_INTRINSIC_HELPER
Isolate* isolate() { return isolate_; }
Zone* zone() { return zone_; }
Isolate* isolate_;
Zone* zone_;
InterpreterAssembler* assembler_;
DISALLOW_COPY_AND_ASSIGN(IntrinsicsHelper);

View File

@ -212,6 +212,47 @@ TEST(Call) {
handle(Smi::FromInt(7), isolate), handle(Smi::FromInt(3), isolate)));
}
TEST(IntrinsicAsStubCall) {
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
Factory* factory = isolate->factory();
InvokeIntrinsicHelper to_number_helper(isolate, handles.main_zone(),
Runtime::kInlineToNumber);
CHECK_EQ(Smi::FromInt(46),
*to_number_helper.Invoke(to_number_helper.NewObject("'46'")));
InvokeIntrinsicHelper to_integer_helper(isolate, handles.main_zone(),
Runtime::kInlineToInteger);
CHECK_EQ(Smi::FromInt(502),
*to_integer_helper.Invoke(to_integer_helper.NewObject("502.67")));
InvokeIntrinsicHelper math_pow_helper(isolate, handles.main_zone(),
Runtime::kInlineMathPow);
CHECK(math_pow_helper
.Invoke(math_pow_helper.NewObject("3"),
math_pow_helper.NewObject("7"))
->SameValue(Smi::FromInt(2187)));
InvokeIntrinsicHelper has_property_helper(isolate, handles.main_zone(),
Runtime::kInlineHasProperty);
CHECK_EQ(*factory->true_value(),
*has_property_helper.Invoke(
has_property_helper.NewObject("'x'"),
has_property_helper.NewObject("({ x: 20 })")));
CHECK_EQ(*factory->false_value(),
*has_property_helper.Invoke(
has_property_helper.NewObject("'y'"),
has_property_helper.NewObject("({ x: 20 })")));
InvokeIntrinsicHelper sub_string_helper(isolate, handles.main_zone(),
Runtime::kInlineSubString);
CHECK(sub_string_helper
.Invoke(sub_string_helper.NewObject("'foobar'"),
sub_string_helper.NewObject("3"),
sub_string_helper.NewObject("6"))
->SameValue(*sub_string_helper.NewObject("'bar'")));
}
} // namespace interpreter
} // namespace internal
} // namespace v8