Skip to content

Support labelled statements #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 295 additions & 0 deletions jerry-core/parser/js/jsp-label.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/

#include "jsp-label.h"
#include "lexer.h"
#include "opcodes-dumper.h"

/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup labels Jump labels
* @{
*/

/**
* Stack, containing current label set
*/
jsp_label_t *label_set_p = NULL;

/**
* Initialize jumps labels mechanism
*/
void
jsp_label_init (void)
{
JERRY_ASSERT (label_set_p == NULL);
} /* jsp_label_init */

/**
* Finalize jumps labels mechanism
*/
void
jsp_label_finalize (void)
{
JERRY_ASSERT (label_set_p == NULL);
} /* jsp_label_finalize */

/**
* Add label to the current label set
*/
void
jsp_label_push (jsp_label_t *out_label_p, /**< out: place where label structure
* should be initialized and
* linked into label set stack */
jsp_label_type_flag_t type_mask, /**< label's type mask */
token id) /**< identifier of the label (TOK_NAME)
* if mask includes JSP_LABEL_TYPE_NAMED,
* or empty token - otherwise */
{
JERRY_ASSERT (out_label_p != NULL);

if (type_mask & JSP_LABEL_TYPE_NAMED)
{
JERRY_ASSERT (id.type == TOK_NAME);

JERRY_ASSERT (jsp_label_find (JSP_LABEL_TYPE_NAMED, id, NULL) == NULL);
}
else
{
JERRY_ASSERT (id.type == TOK_EMPTY);
}

out_label_p->type_mask = type_mask;
out_label_p->id = id;
out_label_p->continue_tgt_oc = MAX_OPCODES;
out_label_p->breaks_list_oc = MAX_OPCODES;
out_label_p->breaks_number = 0;
out_label_p->continues_list_oc = MAX_OPCODES;
out_label_p->continues_number = 0;
out_label_p->next_label_p = label_set_p;
out_label_p->is_nested_jumpable_border = false;

label_set_p = out_label_p;
} /* jsp_label_push */

/**
* Rewrite jumps to the label, if there any,
* and remove it from the current label set
*
* @return the label should be on top of label set stack
*/
void
jsp_label_rewrite_jumps_and_pop (jsp_label_t *label_p, /**< label to remove (should be on top of stack) */
opcode_counter_t break_tgt_oc) /**< target opcode counter
* for breaks on the label */
{
JERRY_ASSERT (label_p != NULL);
JERRY_ASSERT (break_tgt_oc != MAX_OPCODES);
JERRY_ASSERT (label_set_p == label_p);

/* Iterating jumps list, rewriting them */
while (label_p->breaks_number--)
{
JERRY_ASSERT (label_p->breaks_list_oc != MAX_OPCODES);

label_p->breaks_list_oc = rewrite_simple_or_nested_jump_and_get_next (label_p->breaks_list_oc,
break_tgt_oc);
}
while (label_p->continues_number--)
{
JERRY_ASSERT (label_p->continue_tgt_oc != MAX_OPCODES);
JERRY_ASSERT (label_p->continues_list_oc != MAX_OPCODES);

label_p->continues_list_oc = rewrite_simple_or_nested_jump_and_get_next (label_p->continues_list_oc,
label_p->continue_tgt_oc);
}

label_set_p = label_set_p->next_label_p;
} /* jsp_label_rewrite_jumps_and_pop */

/**
* Find label with specified identifier
*
* @return if found, pointer to label descriptor,
* otherwise - NULL.
*/
jsp_label_t*
jsp_label_find (jsp_label_type_flag_t type_mask, /**< types to search for */
token id, /**< identifier of the label (TOK_NAME)
* if mask equals to JSP_LABEL_TYPE_NAMED,
* or empty token - otherwise
* (if so, mask should not include JSP_LABEL_TYPE_NAMED) */
bool *out_is_simply_jumpable_p) /**< out: is the label currently
* accessible with a simple jump */
{
bool is_search_named = (type_mask == JSP_LABEL_TYPE_NAMED);

if (is_search_named)
{
JERRY_ASSERT (id.type == TOK_NAME);
}
else
{
JERRY_ASSERT (!(type_mask & JSP_LABEL_TYPE_NAMED));
JERRY_ASSERT (id.type == TOK_EMPTY);
}

bool is_simply_jumpable = true;
jsp_label_t *ret_label_p = NULL;

for (jsp_label_t *label_iter_p = label_set_p;
label_iter_p != NULL;
label_iter_p = label_iter_p->next_label_p)
{
if (label_iter_p->is_nested_jumpable_border)
{
is_simply_jumpable = false;
}

bool is_named_label = (label_iter_p->type_mask & JSP_LABEL_TYPE_NAMED);
if ((is_search_named
&& is_named_label
&& lexer_are_tokens_with_same_identifier (label_iter_p->id, id))
|| (!is_search_named
&& (type_mask & label_iter_p->type_mask)))
{
ret_label_p = label_iter_p;

break;
}
}

if (out_is_simply_jumpable_p != NULL)
{
*out_is_simply_jumpable_p = is_simply_jumpable;
}

return ret_label_p;
} /* jsp_label_find */

/**
* Dump jump and register it in the specified label to be rewritten later (see also: jsp_label_rewrite_jumps_and_pop)
*
* Warning:
* The dumped instruction should not be modified before it is rewritten, as its idx fields are used
* to link jump instructions related to the label into singly linked list.
*/
void
jsp_label_add_jump (jsp_label_t *label_p, /**< label to register jump for */
bool is_simply_jumpable, /**< is the label currently
* accessible with a simple jump */
bool is_break) /**< type of jump - 'break' (true) or 'continue' (false) */
{
JERRY_ASSERT (label_p != NULL);

if (is_break)
{
label_p->breaks_list_oc = dump_simple_or_nested_jump_for_rewrite (is_simply_jumpable,
label_p->breaks_list_oc);
label_p->breaks_number++;
}
else
{
label_p->continues_list_oc = dump_simple_or_nested_jump_for_rewrite (is_simply_jumpable,
label_p->continues_list_oc);
label_p->continues_number++;
}
} /* jsp_label_add_jump */

/**
* Setup target for 'continue' jumps,
* associated with the labels, from innermost
* to the specified label.
*/
void
jsp_label_setup_continue_target (jsp_label_t *outermost_label_p, /**< the outermost label to setup target for */
opcode_counter_t tgt_oc) /**< target */
{
/* There are no labels that could not be targeted with 'break' jumps */
JERRY_ASSERT (tgt_oc != MAX_OPCODES);
JERRY_ASSERT (outermost_label_p != NULL);

for (jsp_label_t *label_iter_p = label_set_p;
label_iter_p != outermost_label_p->next_label_p;
label_iter_p = label_iter_p->next_label_p)
{
JERRY_ASSERT (label_iter_p != NULL);
JERRY_ASSERT (label_iter_p->continue_tgt_oc == MAX_OPCODES);

label_iter_p->continue_tgt_oc = tgt_oc;
}
} /* jsp_label_setup_continue_target */

/**
* Mark current label, if any, as nested jumpable border
*/
void
jsp_label_raise_nested_jumpable_border (void)
{
if (label_set_p != NULL)
{
JERRY_ASSERT (!label_set_p->is_nested_jumpable_border);
label_set_p->is_nested_jumpable_border = true;
}
} /* jsp_label_raise_nested_jumpable_border */

/**
* Unmark current label, if any, as nested jumpable border
*/
void
jsp_label_remove_nested_jumpable_border (void)
{
if (label_set_p != NULL)
{
JERRY_ASSERT (label_set_p->is_nested_jumpable_border);
label_set_p->is_nested_jumpable_border = false;
}
} /* jsp_label_remove_nested_jumpable_border */

/**
* Mask current label set to restore it later, and start new label set
*
* @return pointer to masked label set's list of labels
*/
jsp_label_t*
jsp_label_mask_set (void)
{
jsp_label_t *ret_p = label_set_p;

label_set_p = NULL;

return ret_p;
} /* jsp_label_mask_set */

/**
* Restore previously masked label set
*
* Note:
* current label set should be empty
*/
void
jsp_label_restore_set (jsp_label_t *masked_label_set_list_p) /**< list of labels of
* a masked label set */
{
JERRY_ASSERT (label_set_p == NULL);

label_set_p = masked_label_set_list_p;
} /* jsp_label_restore_set */

/**
* @}
* @}
*/
89 changes: 89 additions & 0 deletions jerry-core/parser/js/jsp-label.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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 JSP_LABEL_H
#define JSP_LABEL_H

#include "lexer.h"
#include "opcodes.h"

/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup labels Jump labels
* @{
*/

/**
* Label types
*/
typedef enum
{
JSP_LABEL_TYPE_NAMED = (1 << 0), /**< label for breaks and continues with identifiers */
JSP_LABEL_TYPE_UNNAMED_BREAKS = (1 << 1), /**< label for breaks without identifiers */
JSP_LABEL_TYPE_UNNAMED_CONTINUES = (1 << 2) /**< label for continues without identifiers */
} jsp_label_type_flag_t;

/**
* Descriptor of a jump label (See also: ECMA-262 v5, 12.12, Labelled statements)
*
* Note:
* Jump instructions with target identified by some specific label,
* are linked into singly-linked list.
*
* Pointer to a next element of the list is represented with opcode counter.
* stored in instructions linked into the list.
*
*/
typedef struct jsp_label_t
{
jsp_label_type_flag_t type_mask; /**< label type mask */
token id; /**< label name (TOK_NAME), if type is LABEL_NAMED */
opcode_counter_t continue_tgt_oc; /**< target opcode counter for continues on the label */
opcode_counter_t breaks_list_oc; /**< opcode counter of first 'break' instruction in the list
* of instructions with the target identified by the label */
opcode_counter_t breaks_number; /**< number of 'break' instructions in the list */
opcode_counter_t continues_list_oc; /**< opcode counter of first 'continue' instruction in the list
* of instructions with the target identified by the label */
opcode_counter_t continues_number; /**< number of 'continue' instructions in the list */
jsp_label_t *next_label_p; /**< next label in current label set stack */
bool is_nested_jumpable_border : 1; /**< flag, indicating that this and outer labels
* are not currently accessible with simple jumps,
* and so should be targetted with nested jumps only */
} jsp_label_t;

extern void jsp_label_init (void);
extern void jsp_label_finalize (void);

extern void jsp_label_push (jsp_label_t *out_label_p, jsp_label_type_flag_t type_mask, token id);
extern void jsp_label_rewrite_jumps_and_pop (jsp_label_t *label_p, opcode_counter_t break_tgt_oc);

extern jsp_label_t *jsp_label_find (jsp_label_type_flag_t type_mask, token id, bool *out_is_simply_jumpable_p);

extern void jsp_label_add_jump (jsp_label_t *label_p, bool is_simply_jumpable, bool is_break);
extern void jsp_label_setup_continue_target (jsp_label_t *outermost_label_p, opcode_counter_t tgt_oc);

extern void jsp_label_raise_nested_jumpable_border (void);
extern void jsp_label_remove_nested_jumpable_border (void);

extern jsp_label_t *jsp_label_mask_set (void);
extern void jsp_label_restore_set (jsp_label_t *masked_label_set_list_p);

/**
* @}
* @}
*/

#endif /* !JSP_LABEL_H */
Loading