Robert Fancsik 24817b27f9 Optimize property call opcodes (#2609)
In with contexts the object base value must be resolved before executing a call operation.
Since this happens rarely the base resolving code paths has been seperated to an other VM opcode
so these extra checks do not burden the general property call steps.

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
2018-11-29 09:00:22 +01:00

371 lines
14 KiB
C

/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef VM_H
#define VM_H
#include "ecma-globals.h"
#include "jrt.h"
#include "vm-defines.h"
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_executor Executor
* @{
*/
/**
* Each CBC opcode is transformed to three vm opcodes:
*
* - first opcode is a "get arguments" opcode which specifies
* the type (register, literal, stack, etc.) and number
* (from 0 to 2) of input arguments
* - second opcode is a "group" opcode which specifies
* the actual operation (add, increment, call, etc.)
* - third opcode is a "put result" opcode which specifies
* the destination where the result is stored (register,
* stack, etc.)
*/
/**
* If VM_OC_GET_ARGS_INDEX(opcode) == VM_OC_GET_BRANCH,
* this flag signals that the branch is a backward branch.
*/
#define VM_OC_BACKWARD_BRANCH 0x4000
/**
* Position of "get arguments" opcode.
*/
#define VM_OC_GET_ARGS_SHIFT 7
/**
* Mask of "get arguments" opcode.
*/
#define VM_OC_GET_ARGS_MASK 0x7
/**
* Generate the binary representation of a "get arguments" opcode.
*/
#define VM_OC_GET_ARGS_CREATE_INDEX(V) (((V) & VM_OC_GET_ARGS_MASK) << VM_OC_GET_ARGS_SHIFT)
/**
* Extract the "get arguments" opcode.
*/
#define VM_OC_GET_ARGS_INDEX(O) ((O) & (VM_OC_GET_ARGS_MASK << VM_OC_GET_ARGS_SHIFT))
/**
* Checks whether the result is stored somewhere.
*/
#define VM_OC_HAS_GET_ARGS(V) ((V) & (VM_OC_GET_ARGS_MASK << VM_OC_GET_ARGS_SHIFT))
/**
* Argument getters that are part of the opcodes.
*/
typedef enum
{
VM_OC_GET_NONE = VM_OC_GET_ARGS_CREATE_INDEX (0), /**< do nothing */
VM_OC_GET_BRANCH = VM_OC_GET_ARGS_CREATE_INDEX (1), /**< branch argument */
VM_OC_GET_STACK = VM_OC_GET_ARGS_CREATE_INDEX (2), /**< pop one element from the stack */
VM_OC_GET_STACK_STACK = VM_OC_GET_ARGS_CREATE_INDEX (3), /**< pop two elements from the stack */
VM_OC_GET_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (4), /**< resolve literal */
VM_OC_GET_LITERAL_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (5), /**< resolve two literals */
VM_OC_GET_STACK_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (6), /**< pop one element from the stack
* and resolve a literal */
VM_OC_GET_THIS_LITERAL = VM_OC_GET_ARGS_CREATE_INDEX (7), /**< get this and resolve a literal */
} vm_oc_get_types;
/**
* Mask of "group" opcode.
*/
#define VM_OC_GROUP_MASK 0x7f
/**
* Extract the "group" opcode.
*/
#define VM_OC_GROUP_GET_INDEX(O) ((O) & VM_OC_GROUP_MASK)
/**
* Opcodes.
*/
typedef enum
{
VM_OC_POP, /**< pop from stack */
VM_OC_POP_BLOCK, /**< pop block */
VM_OC_PUSH, /**< push one literal */
VM_OC_PUSH_TWO, /**< push two literals */
VM_OC_PUSH_THREE, /**< push three literals */
VM_OC_PUSH_UNDEFINED, /**< push undefined value */
VM_OC_PUSH_TRUE, /**< push true value */
VM_OC_PUSH_FALSE, /**< push false value */
VM_OC_PUSH_NULL, /**< push null value */
VM_OC_PUSH_THIS, /**< push this */
VM_OC_PUSH_0, /**< push number zero */
VM_OC_PUSH_POS_BYTE, /**< push number between 1 and 256 */
VM_OC_PUSH_NEG_BYTE, /**< push number between -1 and -256 */
VM_OC_PUSH_LIT_0, /**< push literal and number zero */
VM_OC_PUSH_LIT_POS_BYTE, /**< push literal and number between 1 and 256 */
VM_OC_PUSH_LIT_NEG_BYTE, /**< push literal and number between -1 and -256 */
VM_OC_PUSH_OBJECT, /**< push object */
VM_OC_SET_PROPERTY, /**< set property */
#ifndef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
VM_OC_SET_COMPUTED_PROPERTY, /**< set computed property */
#endif /* !CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
VM_OC_SET_GETTER, /**< set getter */
VM_OC_SET_SETTER, /**< set setter */
VM_OC_PUSH_UNDEFINED_BASE, /**< push undefined base */
VM_OC_PUSH_ARRAY, /**< push array */
VM_OC_PUSH_ELISON, /**< push elison */
VM_OC_APPEND_ARRAY, /**< append array */
VM_OC_IDENT_REFERENCE, /**< ident reference */
VM_OC_PROP_REFERENCE, /**< prop reference */
VM_OC_PROP_GET, /**< prop get */
/* These eight opcodes must be in this order. */
VM_OC_PROP_PRE_INCR, /**< prefix increment of a property */
VM_OC_PROP_PRE_DECR, /**< prop prefix decrement of a property */
VM_OC_PROP_POST_INCR, /**< prop postfix increment of a property */
VM_OC_PROP_POST_DECR, /**< prop postfix decrement of a property */
VM_OC_PRE_INCR, /**< prefix increment */
VM_OC_PRE_DECR, /**< prefix decrement */
VM_OC_POST_INCR, /**< postfix increment */
VM_OC_POST_DECR, /**< postfix decrement */
VM_OC_PROP_DELETE, /**< delete property */
VM_OC_DELETE, /**< delete */
VM_OC_ASSIGN, /**< assign */
VM_OC_ASSIGN_PROP, /**< assign property */
VM_OC_ASSIGN_PROP_THIS, /**< assign prop this */
VM_OC_RET, /**< return */
VM_OC_THROW, /**< throw */
VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */
VM_OC_EVAL, /**< eval */
VM_OC_CALL, /**< call */
VM_OC_NEW, /**< new */
VM_OC_RESOLVE_BASE_FOR_CALL, /**< resolve base value before call */
VM_OC_JUMP, /**< jump */
VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */
/* These four opcodes must be in this order. */
VM_OC_BRANCH_IF_TRUE, /**< branch if true */
VM_OC_BRANCH_IF_FALSE, /**< branch if false */
VM_OC_BRANCH_IF_LOGICAL_TRUE, /**< branch if logical true */
VM_OC_BRANCH_IF_LOGICAL_FALSE, /**< branch if logical false */
VM_OC_PLUS, /**< unary plus */
VM_OC_MINUS, /**< unary minus */
VM_OC_NOT, /**< not */
VM_OC_BIT_NOT, /**< bitwise not */
VM_OC_VOID, /**< void */
VM_OC_TYPEOF_IDENT, /**< typeof identifier */
VM_OC_TYPEOF, /**< typeof */
VM_OC_ADD, /**< binary add */
VM_OC_SUB, /**< binary sub */
VM_OC_MUL, /**< mul */
VM_OC_DIV, /**< div */
VM_OC_MOD, /**< mod */
VM_OC_EQUAL, /**< equal */
VM_OC_NOT_EQUAL, /**< not equal */
VM_OC_STRICT_EQUAL, /**< strict equal */
VM_OC_STRICT_NOT_EQUAL, /**< strict not equal */
VM_OC_LESS, /**< less */
VM_OC_GREATER, /**< greater */
VM_OC_LESS_EQUAL, /**< less equal */
VM_OC_GREATER_EQUAL, /**< greater equal */
VM_OC_IN, /**< in */
VM_OC_INSTANCEOF, /**< instanceof */
VM_OC_BIT_OR, /**< bitwise or */
VM_OC_BIT_XOR, /**< bitwise xor */
VM_OC_BIT_AND, /**< bitwise and */
VM_OC_LEFT_SHIFT, /**< left shift */
VM_OC_RIGHT_SHIFT, /**< right shift */
VM_OC_UNS_RIGHT_SHIFT, /**< unsigned right shift */
VM_OC_WITH, /**< with */
VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */
VM_OC_FOR_IN_GET_NEXT, /**< get next */
VM_OC_FOR_IN_HAS_NEXT, /**< has next */
VM_OC_TRY, /**< try */
VM_OC_CATCH, /**< catch */
VM_OC_FINALLY, /**< finally */
VM_OC_CONTEXT_END, /**< context end */
VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */
#ifndef CONFIG_DISABLE_ES2015_CLASS
VM_OC_CLASS_HERITAGE, /**< create a super class context */
VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */
VM_OC_PUSH_CLASS_CONSTRUCTOR, /**< push class constructor */
VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */
VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */
VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */
VM_OC_CLASS_EVAL, /**< eval inside a class */
VM_OC_SUPER_CALL, /**< call the 'super' constructor */
VM_OC_SUPER_PROP_REFERENCE, /**< resolve super property reference */
VM_OC_PUSH_SUPER, /**< push resolvable super reference */
VM_OC_PUSH_CONSTRUCTOR_SUPER, /**< push 'super' inside a class constructor */
VM_OC_PUSH_CONSTRUCTOR_THIS, /**< push 'this' inside a class constructor */
VM_OC_CONSTRUCTOR_RET, /**< explicit return from a class constructor */
#endif /* !CONFIG_DISABLE_ES2015 */
#ifdef JERRY_DEBUGGER
VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */
VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */
#endif /* JERRY_DEBUGGER */
#ifdef JERRY_ENABLE_LINE_INFO
VM_OC_RESOURCE_NAME, /**< resource name of the current function */
VM_OC_LINE, /**< line number of the next statement */
#endif /* JERRY_ENABLE_LINE_INFO */
VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
/**
* Unused opcodes, but required by byte-code types.
*/
typedef enum
{
#ifdef CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER
VM_OC_SET_COMPUTED_PROPERTY = VM_OC_NONE, /**< set computed property is unused */
#endif /* CONFIG_DISABLE_ES2015_OBJECT_INITIALIZER */
#ifndef JERRY_DEBUGGER
VM_OC_BREAKPOINT_ENABLED = VM_OC_NONE, /**< enabled breakpoint for debugger is unused */
VM_OC_BREAKPOINT_DISABLED = VM_OC_NONE, /**< disabled breakpoint for debugger is unused */
#endif /* !JERRY_DEBUGGER */
#ifndef JERRY_ENABLE_LINE_INFO
VM_OC_RESOURCE_NAME = VM_OC_NONE, /**< resource name of the current function is unused */
VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */
#endif /* !JERRY_ENABLE_LINE_INFO */
#ifdef CONFIG_DISABLE_ES2015_CLASS
VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */
VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */
VM_OC_PUSH_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< push class constructor */
VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */
VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */
VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */
VM_OC_CLASS_EVAL = VM_OC_NONE, /**< eval inside a class */
VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */
VM_OC_SUPER_PROP_REFERENCE = VM_OC_NONE, /**< resolve super property reference */
VM_OC_PUSH_SUPER = VM_OC_NONE, /**< push resolvable super reference */
VM_OC_PUSH_CONSTRUCTOR_SUPER = VM_OC_NONE, /**< push 'super' inside a class constructor */
VM_OC_PUSH_CONSTRUCTOR_THIS = VM_OC_NONE, /**< push 'this' inside a class constructor */
VM_OC_CONSTRUCTOR_RET = VM_OC_NONE, /**< explicit return from a class constructor */
#endif /* CONFIG_DISABLE_ES2015 */
VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */
} vm_oc_unused_types;
/**
* Decrement operator.
*/
#define VM_OC_DECREMENT_OPERATOR_FLAG 0x1
/**
* Postfix increment/decrement operator.
*/
#define VM_OC_POST_INCR_DECR_OPERATOR_FLAG 0x2
/**
* An named variable is updated by the increment/decrement operator.
*/
#define VM_OC_IDENT_INCR_DECR_OPERATOR_FLAG 0x4
/**
* Jump to target offset if input value is logical false.
*/
#define VM_OC_BRANCH_IF_FALSE_FLAG 0x1
/**
* Branch optimized for logical and/or opcodes.
*/
#define VM_OC_LOGICAL_BRANCH_FLAG 0x2
/**
* Bit index shift for non-static property initializers.
*/
#define VM_OC_NON_STATIC_SHIFT 14
/**
* This flag is set for static property initializers.
*/
#define VM_OC_NON_STATIC_FLAG (0x1 << VM_OC_NON_STATIC_SHIFT)
/**
* Position of "put result" opcode.
*/
#define VM_OC_PUT_RESULT_SHIFT 10
/**
* Mask of "put result" opcode.
*/
#define VM_OC_PUT_RESULT_MASK 0xf
/**
* Generate a "put result" opcode flag bit.
*/
#define VM_OC_PUT_RESULT_CREATE_FLAG(V) (((V) & VM_OC_PUT_RESULT_MASK) << VM_OC_PUT_RESULT_SHIFT)
/**
* Checks whether the result is stored somewhere.
*/
#define VM_OC_HAS_PUT_RESULT(V) ((V) & (VM_OC_PUT_RESULT_MASK << VM_OC_PUT_RESULT_SHIFT))
/**
* Specify where the result is stored
*/
typedef enum
{
VM_OC_PUT_IDENT = VM_OC_PUT_RESULT_CREATE_FLAG (0x1),
VM_OC_PUT_REFERENCE = VM_OC_PUT_RESULT_CREATE_FLAG (0x2),
VM_OC_PUT_STACK = VM_OC_PUT_RESULT_CREATE_FLAG (0x4),
VM_OC_PUT_BLOCK = VM_OC_PUT_RESULT_CREATE_FLAG (0x8),
} vm_oc_put_types;
/**
* Non-recursive vm_loop: the vm_loop can be suspended
* to execute a call /construct operation. These return
* types of the vm_loop tells whether a call operation
* is in progress or the vm_loop is finished.
*/
typedef enum
{
VM_NO_EXEC_OP, /**< do nothing */
VM_EXEC_CALL, /**< invoke a function */
VM_EXEC_SUPER_CALL, /**< invoke a function through 'super' keyword */
VM_EXEC_CONSTRUCT, /**< construct a new object */
} vm_call_operation;
ecma_value_t vm_run_global (const ecma_compiled_code_t *bytecode_p);
ecma_value_t vm_run_eval (ecma_compiled_code_t *bytecode_data_p, uint32_t parse_opts);
ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t this_binding_value,
ecma_object_t *lex_env_p, uint32_t parse_opts, const ecma_value_t *arg_list_p,
ecma_length_t arg_list_len);
bool vm_is_strict_mode (void);
bool vm_is_direct_eval_form_call (void);
ecma_value_t vm_get_backtrace (uint32_t max_depth);
/**
* @}
* @}
*/
#endif /* !VM_H */