blob: f9b5fde7ae3035e18651f59790b68ac004dcc7ac [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001349 if (is_function_declaration) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 }
1360 // Do not change DONT_DELETE to false from true.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1364
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001365 RETURN_IF_EMPTY_HANDLE(
1366 isolate,
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001370 RETURN_IF_EMPTY_HANDLE(
1371 isolate,
1372 JSReceiver::SetProperty(global, name, value,
1373 static_cast<PropertyAttributes>(attr),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001374 language_mode == CLASSIC_MODE
1375 ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 }
1377 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381}
1382
1383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001384RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001385 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 // Declarations are always made in a function or global context. In the
1389 // case of eval code, the context passed is the context of the caller,
1390 // which may be some nested context and not the declaration context.
1391 RUNTIME_ASSERT(args[0]->IsContext());
1392 Handle<Context> context(Context::cast(args[0])->declaration_context());
1393
ager@chromium.org7c537e22008-10-16 08:43:32 +00001394 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 int index;
1400 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001402 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001403 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001404 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405
1406 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
1415 // Initialize it if necessary.
1416 if (*initial_value != NULL) {
1417 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 ASSERT(holder.is_identical_to(context));
1419 if (((attributes & READ_ONLY) == 0) ||
1420 context->get(index)->IsTheHole()) {
1421 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Slow case: The property is in the context extension object of a
1425 // function context or the global object of a global context.
1426 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001427 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001429 JSReceiver::SetProperty(object, name, initial_value, mode,
1430 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 }
1432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001435 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 // "declared" in the function context's extension context or as a
1437 // property of the the global object.
1438 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001439 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 // Context extension objects are allocated lazily.
1443 ASSERT(context->IsFunctionContext());
1444 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449
ager@chromium.org7c537e22008-10-16 08:43:32 +00001450 // Declare the property by setting it to the initial value if provided,
1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1452 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001455 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 // Declaring a const context slot is a conflicting declaration if
1457 // there is a callback with that name in a prototype. It is
1458 // allowed to introduce const variables in
1459 // JSContextExtensionObjects. They are treated specially in
1460 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects.
1462 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001468 }
1469 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001470 RETURN_IF_EMPTY_HANDLE(
1471 isolate,
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001473 }
1474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001482 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
1497 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE;
1500
1501 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001502 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001505 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001506 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 while (object->IsJSObject() &&
1511 JSObject::cast(object)->map()->is_hidden_prototype()) {
1512 JSObject* raw_holder = JSObject::cast(object);
1513 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 HandleScope handle_scope(isolate);
1516 Handle<JSObject> holder(raw_holder);
1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1518 // Update the raw pointer in case it's changed due to GC.
1519 raw_holder = *holder;
1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1521 // Found an interceptor that's not read only.
1522 if (assign) {
1523 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001524 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 } else {
1526 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001527 }
1528 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001535 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001538 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539}
1540
1541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001542RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // All constants are declared with an initial value. The name
1544 // of the constant is the first argument and the initial value
1545 // is the second.
1546 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 Handle<Object> value = args.at<Object>(1);
1549
1550 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001551 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
1553 // According to ECMA-262, section 12.2, page 62, the property must
1554 // not be deletable. Since it's a const, it must be READ_ONLY too.
1555 PropertyAttributes attributes =
1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1557
1558 // Lookup the property locally in the global object. If it isn't
1559 // there, we add the property and take special precautions to always
1560 // add it as a local property even in case of callbacks in the
1561 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001562 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001563 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 global->LocalLookup(*name, &lookup);
1565 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001566 return global->SetLocalPropertyIgnoreAttributes(*name,
1567 *value,
1568 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 HandleScope handle_scope(isolate);
1575 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001577 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 // property through an interceptor and only do it if it's
1579 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001580 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001581 RETURN_IF_EMPTY_HANDLE(
1582 isolate,
1583 JSReceiver::SetProperty(global, name, value, attributes,
1584 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 return *value;
1586 }
1587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 // constant. For now, we determine this by checking if the
1590 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = global->properties();
1595 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1601 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001602 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 }
1604 } else {
1605 // Ignore re-initialization of constants that have already been
1606 // assigned a function value.
1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1608 }
1609
1610 // Use the set value as the result of the operation.
1611 return *value;
1612}
1613
1614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001615RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 ASSERT(args.length() == 3);
1618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001619 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001622 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 RUNTIME_ASSERT(args[1]->IsContext());
1624 Handle<Context> context(Context::cast(args[1])->declaration_context());
1625
1626 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
1628 int index;
1629 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001631 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001632 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001633 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 ASSERT(holder->IsContext());
1637 // Property was found in a context. Perform the assignment if we
1638 // found some non-constant or an uninitialized constant.
1639 Handle<Context> context = Handle<Context>::cast(holder);
1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1641 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 }
1643 return *value;
1644 }
1645
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001646 // The property could not be found, we introduce it as a property of the
1647 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 Handle<JSObject> global = Handle<JSObject>(
1650 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001651 // Strict mode not needed (const disallowed in strict mode).
1652 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 return *value;
1656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 // The property was present in some function's context extension object,
1659 // as a property on the subject of a with, or as a property of the global
1660 // object.
1661 //
1662 // In most situations, eval-introduced consts should still be present in
1663 // the context extension object. However, because declaration and
1664 // initialization are separate, the property might have been deleted
1665 // before we reach the initialization point.
1666 //
1667 // Example:
1668 //
1669 // function f() { eval("delete x; const x;"); }
1670 //
1671 // In that case, the initialization behaves like a normal assignment.
1672 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (*object == context->extension()) {
1675 // This is the property that was introduced by the const declaration.
1676 // Set it if it hasn't been set before. NOTE: We cannot use
1677 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001679 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001680 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1682
1683 PropertyType type = lookup.type();
1684 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 int index = lookup.GetFieldIndex();
1687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
1690 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
1699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001702 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001704 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 return *value;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001718 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001721 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001723 }
1724 return *object;
1725}
1726
1727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001737 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001738 RUNTIME_ASSERT(index >= 0);
1739 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001741 Handle<Object> result = RegExpImpl::Exec(regexp,
1742 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001744 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001745 if (result.is_null()) return Failure::Exception();
1746 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001747}
1748
1749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001750RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001752 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001753 if (elements_count < 0 ||
1754 elements_count > FixedArray::kMaxLength ||
1755 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001758 Object* new_object;
1759 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1762 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001763 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1767 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001768 {
1769 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001771 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001773 }
1774 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001776 array->set_elements(elements);
1777 array->set_length(Smi::FromInt(elements_count));
1778 // Write in-object properties after the length of the array.
1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1781 return array;
1782}
1783
1784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001785RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786 AssertNoAllocation no_alloc;
1787 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1789 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793
1794 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001796
1797 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799
1800 Map* map = regexp->map();
1801 Object* constructor = map->constructor();
1802 if (constructor->IsJSFunction() &&
1803 JSFunction::cast(constructor)->initial_map() == map) {
1804 // If we still have the original map, set in-object properties directly.
1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001806 // Both true and false are immovable immortal objects so no need for write
1807 // barrier.
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1815 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001816 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001817 return regexp;
1818 }
1819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 PropertyAttributes final =
1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1823 PropertyAttributes writable =
1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001825 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 source,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 global,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 ignoreCase,
1838 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001841 multiline,
1842 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001843 ASSERT(!result->IsFailure());
1844 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001846 Smi::FromInt(0),
1847 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 ASSERT(!result->IsFailure());
1849 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001850 return regexp;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001858 // This is necessary to enable fast checks for absence of elements
1859 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001861 return Smi::FromInt(0);
1862}
1863
1864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1866 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001868 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1871 Handle<JSFunction> optimized =
1872 isolate->factory()->NewFunction(key,
1873 JS_OBJECT_TYPE,
1874 JSObject::kHeaderSize,
1875 code,
1876 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001877 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879 return optimized;
1880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001887
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001895
1896 return *holder;
1897}
1898
1899
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001901 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001903
1904 if (!callable->IsJSFunction()) {
1905 HandleScope scope(isolate);
1906 bool threw = false;
1907 Handle<Object> delegate =
1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1909 if (threw) return Failure::Exception();
1910 callable = JSFunction::cast(*delegate);
1911 }
1912 JSFunction* function = JSFunction::cast(callable);
1913
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001914 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001915 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001916 return isolate->heap()->undefined_value();
1917 }
1918 // Returns undefined for strict or native functions, or
1919 // the associated global receiver for "normal" functions.
1920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001922 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001923 return global_context->global()->global_receiver();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001931 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 Handle<String> pattern = args.at<String>(2);
1933 Handle<String> flags = args.at<String>(3);
1934
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001935 // Get the RegExp function from the context in the literals array.
1936 // This is the RegExp function from the context in which the
1937 // function was created. We do not use the RegExp function from the
1938 // current global context because this might be the RegExp function
1939 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001940 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001941 Handle<JSFunction>(
1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 // Compute the regular expression literal.
1944 bool has_pending_exception;
1945 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1947 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 return Failure::Exception();
1951 }
1952 literals->set(index, *regexp);
1953 return *regexp;
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return f->shared()->name();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1971 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001972 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001974}
1975
1976
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 return isolate->heap()->ToBoolean(
1982 f->shared()->name_should_print_as_anonymous());
1983}
1984
1985
1986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001990 f->shared()->set_name_should_print_as_anonymous(true);
1991 return isolate->heap()->undefined_value();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001999 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 Object* obj = f->RemovePrototype();
2001 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002004}
2005
2006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 ASSERT(args.length() == 1);
2010
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002011 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2013 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014
2015 return *GetScriptWrapper(Handle<Script>::cast(script));
2016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 ASSERT(args.length() == 1);
2022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002024 Handle<SharedFunctionInfo> shared(f->shared());
2025 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 1);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 int pos = fun->shared()->start_position();
2035 return Smi::FromInt(pos);
2036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040 ASSERT(args.length() == 2);
2041
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002042 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2044
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2046
2047 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002049}
2050
2051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002052RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 NoHandleAllocation ha;
2054 ASSERT(args.length() == 2);
2055
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002056 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2057 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060}
2061
2062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002067 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2068 CONVERT_SMI_ARG_CHECKED(length, 1);
2069 fun->shared()->set_length(length);
2070 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071}
2072
2073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 ASSERT(args.length() == 2);
2077
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002078 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002079 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002080 Object* obj;
2081 { MaybeObject* maybe_obj =
2082 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 return args[0]; // return TOS
2086}
2087
2088
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2090 NoHandleAllocation ha;
2091 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002092 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002093
2094 MaybeObject* maybe_name =
2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2096 String* name;
2097 if (!maybe_name->To(&name)) return maybe_name;
2098
2099 if (function->HasFastProperties()) {
2100 // Construct a new field descriptor with updated attributes.
2101 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2102 int index = instance_desc->Search(name);
2103 ASSERT(index != DescriptorArray::kNotFound);
2104 PropertyDetails details(instance_desc->GetDetails(index));
2105 CallbacksDescriptor new_desc(name,
2106 instance_desc->GetValue(index),
2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2108 details.index());
2109 // Construct a new field descriptors array containing the new descriptor.
2110 Object* descriptors_unchecked;
2111 { MaybeObject* maybe_descriptors_unchecked =
2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2114 return maybe_descriptors_unchecked;
2115 }
2116 }
2117 DescriptorArray* new_descriptors =
2118 DescriptorArray::cast(descriptors_unchecked);
2119 // Create a new map featuring the new field descriptors array.
2120 Object* map_unchecked;
2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2123 return maybe_map_unchecked;
2124 }
2125 }
2126 Map* new_map = Map::cast(map_unchecked);
2127 new_map->set_instance_descriptors(new_descriptors);
2128 function->set_map(new_map);
2129 } else { // Dictionary properties.
2130 // Directly manipulate the property details.
2131 int entry = function->property_dictionary()->FindEntry(name);
2132 ASSERT(entry != StringDictionary::kNotFound);
2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2134 PropertyDetails new_details(
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.type(),
2137 details.index());
2138 function->property_dictionary()->DetailsAtPut(entry, new_details);
2139 }
2140 return function;
2141}
2142
2143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002150}
2151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002154 NoHandleAllocation ha;
2155 ASSERT(args.length() == 1);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002158 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002159}
2160
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002162RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 ASSERT(args.length() == 2);
2165
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 Handle<Object> code = args.at<Object>(1);
2168
2169 Handle<Context> context(target->context());
2170
2171 if (!code->IsNull()) {
2172 RUNTIME_ASSERT(code->IsJSFunction());
2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 return Failure::Exception();
2178 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002179 // Since we don't store the source for this we should never
2180 // optimize this.
2181 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 // Set the code, scope info, formal parameter count,
2183 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002184 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002185 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002186 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002187 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002189 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002190 // Set the source code of the target function to undefined.
2191 // SetCode is only used for built-in constructors like String,
2192 // Array, and Object, and some web code
2193 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002195 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002196 // Clear the optimization hints related to the compiled code as these are no
2197 // longer valid when the code is overwritten.
2198 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 context = Handle<Context>(fun->context());
2200
2201 // Make sure we get a fresh copy of the literal vector to avoid
2202 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 int number_of_literals = fun->NumberOfLiterals();
2204 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002207 // Insert the object, regexp and array functions in the literals
2208 // array prefix. These are the functions that will be used when
2209 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002210 literals->set(JSFunction::kLiteralGlobalContextIndex,
2211 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002213 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002215
2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2217 isolate->logger()->LogExistingFunction(
2218 shared, Handle<Code>(shared->code()));
2219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 }
2221
2222 target->set_context(*context);
2223 return *target;
2224}
2225
2226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002229 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002231 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002232 RUNTIME_ASSERT(num >= 0);
2233 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002235}
2236
2237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2239 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002241 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002242 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002244 }
2245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 2);
2253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002254 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258 uint32_t i = 0;
2259 if (index->IsSmi()) {
2260 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002262 i = value;
2263 } else {
2264 ASSERT(index->IsHeapNumber());
2265 double value = HeapNumber::cast(index)->value();
2266 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002267 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002268
2269 // Flatten the string. If someone wants to get a char at an index
2270 // in a cons string, it is likely that more indices will be
2271 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002272 Object* flat;
2273 { MaybeObject* maybe_flat = subject->TryFlatten();
2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2275 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 subject = String::cast(flat);
2277
2278 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002280 }
2281
2282 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002283}
2284
2285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002286RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287 NoHandleAllocation ha;
2288 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002290}
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292
2293class FixedArrayBuilder {
2294 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(initial_capacity > 0);
2302 }
2303
2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2305 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002306 length_(0),
2307 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 // Require a non-zero initial size. Ensures that doubling the size to
2309 // extend the array will work.
2310 ASSERT(backing_store->length() > 0);
2311 }
2312
2313 bool HasCapacity(int elements) {
2314 int length = array_->length();
2315 int required_length = length_ + elements;
2316 return (length >= required_length);
2317 }
2318
2319 void EnsureCapacity(int elements) {
2320 int length = array_->length();
2321 int required_length = length_ + elements;
2322 if (length < required_length) {
2323 int new_length = length;
2324 do {
2325 new_length *= 2;
2326 } while (new_length < required_length);
2327 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 array_->CopyTo(0, *extended_array, 0, length_);
2330 array_ = extended_array;
2331 }
2332 }
2333
2334 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002336 ASSERT(length_ < capacity());
2337 array_->set(length_, value);
2338 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002339 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 }
2341
2342 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002343 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 ASSERT(length_ < capacity());
2345 array_->set(length_, value);
2346 length_++;
2347 }
2348
2349 Handle<FixedArray> array() {
2350 return array_;
2351 }
2352
2353 int length() {
2354 return length_;
2355 }
2356
2357 int capacity() {
2358 return array_->length();
2359 }
2360
2361 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 result_array->set_length(Smi::FromInt(length_));
2364 return result_array;
2365 }
2366
2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002369 target_array->set_length(Smi::FromInt(length_));
2370 return target_array;
2371 }
2372
2373 private:
2374 Handle<FixedArray> array_;
2375 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377};
2378
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381const int kStringBuilderConcatHelperLengthBits = 11;
2382const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384template <typename schar>
2385static inline void StringBuilderConcatHelper(String*,
2386 schar*,
2387 FixedArray*,
2388 int);
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2391 StringBuilderSubstringLength;
2392typedef BitField<int,
2393 kStringBuilderConcatHelperLengthBits,
2394 kStringBuilderConcatHelperPositionBits>
2395 StringBuilderSubstringPosition;
2396
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397
2398class ReplacementStringBuilder {
2399 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002400 ReplacementStringBuilder(Heap* heap,
2401 Handle<String> subject,
2402 int estimated_part_count)
2403 : heap_(heap),
2404 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 // Require a non-zero initial size. Ensures that doubling the size to
2409 // extend the array will work.
2410 ASSERT(estimated_part_count > 0);
2411 }
2412
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2414 int from,
2415 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002416 ASSERT(from >= 0);
2417 int length = to - from;
2418 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 if (StringBuilderSubstringLength::is_valid(length) &&
2420 StringBuilderSubstringPosition::is_valid(from)) {
2421 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2422 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002423 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002425 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 builder->Add(Smi::FromInt(-length));
2427 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002429 }
2430
2431
2432 void EnsureCapacity(int elements) {
2433 array_builder_.EnsureCapacity(elements);
2434 }
2435
2436
2437 void AddSubjectSlice(int from, int to) {
2438 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002439 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442
2443 void AddString(Handle<String> string) {
2444 int length = string->length();
2445 ASSERT(length > 0);
2446 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002447 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 is_ascii_ = false;
2449 }
2450 IncrementCharacterCount(length);
2451 }
2452
2453
2454 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002456 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 }
2458
2459 Handle<String> joined_string;
2460 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 char* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 *array_builder_.array(),
2467 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 } else {
2470 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 uc16* char_buffer = seq->GetChars();
2474 StringBuilderConcatHelper(*subject_,
2475 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 *array_builder_.array(),
2477 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 }
2480 return joined_string;
2481 }
2482
2483
2484 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002485 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 V8::FatalProcessOutOfMemory("String.replace result too large.");
2487 }
2488 character_count_ += by;
2489 }
2490
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002494
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002496 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2497 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 }
2499
2500
ager@chromium.org04921a82011-06-27 13:21:41 +00002501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2502 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 }
2504
2505
2506 void AddElement(Object* element) {
2507 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002508 ASSERT(array_builder_.capacity() > array_builder_.length());
2509 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 }
2511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int character_count_;
2516 bool is_ascii_;
2517};
2518
2519
2520class CompiledReplacement {
2521 public:
2522 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524
2525 void Compile(Handle<String> replacement,
2526 int capture_count,
2527 int subject_length);
2528
2529 void Apply(ReplacementStringBuilder* builder,
2530 int match_from,
2531 int match_to,
2532 Handle<JSArray> last_match_info);
2533
2534 // Number of distinct parts of the replacement pattern.
2535 int parts() {
2536 return parts_.length();
2537 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002538
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002539 bool simple_hint() {
2540 return simple_hint_;
2541 }
2542
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002543 private:
2544 enum PartType {
2545 SUBJECT_PREFIX = 1,
2546 SUBJECT_SUFFIX,
2547 SUBJECT_CAPTURE,
2548 REPLACEMENT_SUBSTRING,
2549 REPLACEMENT_STRING,
2550
2551 NUMBER_OF_PART_TYPES
2552 };
2553
2554 struct ReplacementPart {
2555 static inline ReplacementPart SubjectMatch() {
2556 return ReplacementPart(SUBJECT_CAPTURE, 0);
2557 }
2558 static inline ReplacementPart SubjectCapture(int capture_index) {
2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2560 }
2561 static inline ReplacementPart SubjectPrefix() {
2562 return ReplacementPart(SUBJECT_PREFIX, 0);
2563 }
2564 static inline ReplacementPart SubjectSuffix(int subject_length) {
2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2566 }
2567 static inline ReplacementPart ReplacementString() {
2568 return ReplacementPart(REPLACEMENT_STRING, 0);
2569 }
2570 static inline ReplacementPart ReplacementSubString(int from, int to) {
2571 ASSERT(from >= 0);
2572 ASSERT(to > from);
2573 return ReplacementPart(-from, to);
2574 }
2575
2576 // If tag <= 0 then it is the negation of a start index of a substring of
2577 // the replacement pattern, otherwise it's a value from PartType.
2578 ReplacementPart(int tag, int data)
2579 : tag(tag), data(data) {
2580 // Must be non-positive or a PartType value.
2581 ASSERT(tag < NUMBER_OF_PART_TYPES);
2582 }
2583 // Either a value of PartType or a non-positive number that is
2584 // the negation of an index into the replacement string.
2585 int tag;
2586 // The data value's interpretation depends on the value of tag:
2587 // tag == SUBJECT_PREFIX ||
2588 // tag == SUBJECT_SUFFIX: data is unused.
2589 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2590 // tag == REPLACEMENT_SUBSTRING ||
2591 // tag == REPLACEMENT_STRING: data is index into array of substrings
2592 // of the replacement string.
2593 // tag <= 0: Temporary representation of the substring of the replacement
2594 // string ranging over -tag .. data.
2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2596 // substring objects.
2597 int data;
2598 };
2599
2600 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 Vector<Char> characters,
2603 int capture_count,
2604 int subject_length) {
2605 int length = characters.length();
2606 int last = 0;
2607 for (int i = 0; i < length; i++) {
2608 Char c = characters[i];
2609 if (c == '$') {
2610 int next_index = i + 1;
2611 if (next_index == length) { // No next character!
2612 break;
2613 }
2614 Char c2 = characters[next_index];
2615 switch (c2) {
2616 case '$':
2617 if (i > last) {
2618 // There is a substring before. Include the first "$".
2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2620 last = next_index + 1; // Continue after the second "$".
2621 } else {
2622 // Let the next substring start with the second "$".
2623 last = next_index;
2624 }
2625 i = next_index;
2626 break;
2627 case '`':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectPrefix());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '\'':
2636 if (i > last) {
2637 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2638 }
2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2640 i = next_index;
2641 last = i + 1;
2642 break;
2643 case '&':
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
2647 parts->Add(ReplacementPart::SubjectMatch());
2648 i = next_index;
2649 last = i + 1;
2650 break;
2651 case '0':
2652 case '1':
2653 case '2':
2654 case '3':
2655 case '4':
2656 case '5':
2657 case '6':
2658 case '7':
2659 case '8':
2660 case '9': {
2661 int capture_ref = c2 - '0';
2662 if (capture_ref > capture_count) {
2663 i = next_index;
2664 continue;
2665 }
2666 int second_digit_index = next_index + 1;
2667 if (second_digit_index < length) {
2668 // Peek ahead to see if we have two digits.
2669 Char c3 = characters[second_digit_index];
2670 if ('0' <= c3 && c3 <= '9') { // Double digits.
2671 int double_digit_ref = capture_ref * 10 + c3 - '0';
2672 if (double_digit_ref <= capture_count) {
2673 next_index = second_digit_index;
2674 capture_ref = double_digit_ref;
2675 }
2676 }
2677 }
2678 if (capture_ref > 0) {
2679 if (i > last) {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2681 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002682 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2684 last = next_index + 1;
2685 }
2686 i = next_index;
2687 break;
2688 }
2689 default:
2690 i = next_index;
2691 break;
2692 }
2693 }
2694 }
2695 if (length > last) {
2696 if (last == 0) {
2697 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002698 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 } else {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2701 }
2702 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705
2706 ZoneList<ReplacementPart> parts_;
2707 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002708 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709};
2710
2711
2712void CompiledReplacement::Compile(Handle<String> replacement,
2713 int capture_count,
2714 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 String::FlatContent content = replacement->GetFlatContent();
2718 ASSERT(content.IsFlat());
2719 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002720 simple_hint_ = ParseReplacementPattern(&parts_,
2721 content.ToAsciiVector(),
2722 capture_count,
2723 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002724 } else {
2725 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002726 simple_hint_ = ParseReplacementPattern(&parts_,
2727 content.ToUC16Vector(),
2728 capture_count,
2729 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002730 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002731 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002733 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int substring_index = 0;
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 int tag = parts_[i].tag;
2737 if (tag <= 0) { // A replacement string slice.
2738 int from = -tag;
2739 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 replacement_substrings_.Add(
2741 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 parts_[i].tag = REPLACEMENT_SUBSTRING;
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 } else if (tag == REPLACEMENT_STRING) {
2746 replacement_substrings_.Add(replacement);
2747 parts_[i].data = substring_index;
2748 substring_index++;
2749 }
2750 }
2751}
2752
2753
2754void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2755 int match_from,
2756 int match_to,
2757 Handle<JSArray> last_match_info) {
2758 for (int i = 0, n = parts_.length(); i < n; i++) {
2759 ReplacementPart part = parts_[i];
2760 switch (part.tag) {
2761 case SUBJECT_PREFIX:
2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2763 break;
2764 case SUBJECT_SUFFIX: {
2765 int subject_length = part.data;
2766 if (match_to < subject_length) {
2767 builder->AddSubjectSlice(match_to, subject_length);
2768 }
2769 break;
2770 }
2771 case SUBJECT_CAPTURE: {
2772 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002773 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2776 if (from >= 0 && to > from) {
2777 builder->AddSubjectSlice(from, to);
2778 }
2779 break;
2780 }
2781 case REPLACEMENT_SUBSTRING:
2782 case REPLACEMENT_STRING:
2783 builder->AddString(replacement_substrings_[part.data]);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002792void FindAsciiStringIndices(Vector<const char> subject,
2793 char pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject using memchr.
2798 // Stop after finding at most limit values.
2799 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2800 const char* subject_end = subject_start + subject.length();
2801 const char* pos = subject_start;
2802 while (limit > 0) {
2803 pos = reinterpret_cast<const char*>(
2804 memchr(pos, pattern, subject_end - pos));
2805 if (pos == NULL) return;
2806 indices->Add(static_cast<int>(pos - subject_start));
2807 pos++;
2808 limit--;
2809 }
2810}
2811
2812
2813template <typename SubjectChar, typename PatternChar>
2814void FindStringIndices(Isolate* isolate,
2815 Vector<const SubjectChar> subject,
2816 Vector<const PatternChar> pattern,
2817 ZoneList<int>* indices,
2818 unsigned int limit) {
2819 ASSERT(limit > 0);
2820 // Collect indices of pattern in subject.
2821 // Stop after finding at most limit values.
2822 int pattern_length = pattern.length();
2823 int index = 0;
2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2825 while (limit > 0) {
2826 index = search.Search(subject, index);
2827 if (index < 0) return;
2828 indices->Add(index);
2829 index += pattern_length;
2830 limit--;
2831 }
2832}
2833
2834
2835void FindStringIndicesDispatch(Isolate* isolate,
2836 String* subject,
2837 String* pattern,
2838 ZoneList<int>* indices,
2839 unsigned int limit) {
2840 {
2841 AssertNoAllocation no_gc;
2842 String::FlatContent subject_content = subject->GetFlatContent();
2843 String::FlatContent pattern_content = pattern->GetFlatContent();
2844 ASSERT(subject_content.IsFlat());
2845 ASSERT(pattern_content.IsFlat());
2846 if (subject_content.IsAscii()) {
2847 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2848 if (pattern_content.IsAscii()) {
2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2850 if (pattern_vector.length() == 1) {
2851 FindAsciiStringIndices(subject_vector,
2852 pattern_vector[0],
2853 indices,
2854 limit);
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_vector,
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 } else {
2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002872 FindStringIndices(isolate,
2873 subject_vector,
2874 pattern_content.ToAsciiVector(),
2875 indices,
2876 limit);
2877 } else {
2878 FindStringIndices(isolate,
2879 subject_vector,
2880 pattern_content.ToUC16Vector(),
2881 indices,
2882 limit);
2883 }
2884 }
2885 }
2886}
2887
2888
2889template<typename ResultSeqString>
2890MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2891 Isolate* isolate,
2892 Handle<String> subject,
2893 Handle<JSRegExp> pattern_regexp,
2894 Handle<String> replacement) {
2895 ASSERT(subject->IsFlat());
2896 ASSERT(replacement->IsFlat());
2897
2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2899 ZoneList<int> indices(8);
2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2901 String* pattern =
2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2903 int subject_len = subject->length();
2904 int pattern_len = pattern->length();
2905 int replacement_len = replacement->length();
2906
2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2908
2909 int matches = indices.length();
2910 if (matches == 0) return *subject;
2911
2912 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2913 int subject_pos = 0;
2914 int result_pos = 0;
2915
2916 Handle<ResultSeqString> result;
2917 if (ResultSeqString::kHasAsciiEncoding) {
2918 result = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawAsciiString(result_len));
2920 } else {
2921 result = Handle<ResultSeqString>::cast(
2922 isolate->factory()->NewRawTwoByteString(result_len));
2923 }
2924
2925 for (int i = 0; i < matches; i++) {
2926 // Copy non-matched subject content.
2927 if (subject_pos < indices.at(i)) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 indices.at(i));
2932 result_pos += indices.at(i) - subject_pos;
2933 }
2934
2935 // Replace match.
2936 if (replacement_len > 0) {
2937 String::WriteToFlat(*replacement,
2938 result->GetChars() + result_pos,
2939 0,
2940 replacement_len);
2941 result_pos += replacement_len;
2942 }
2943
2944 subject_pos = indices.at(i) + pattern_len;
2945 }
2946 // Add remaining subject content at the end.
2947 if (subject_pos < subject_len) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 subject_len);
2952 }
2953 return *result;
2954}
2955
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002956
lrn@chromium.org303ada72010-10-27 09:33:13 +00002957MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002958 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002959 String* subject,
2960 JSRegExp* regexp,
2961 String* replacement,
2962 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002963 ASSERT(subject->IsFlat());
2964 ASSERT(replacement->IsFlat());
2965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002967
2968 int length = subject->length();
2969 Handle<String> subject_handle(subject);
2970 Handle<JSRegExp> regexp_handle(regexp);
2971 Handle<String> replacement_handle(replacement);
2972 Handle<JSArray> last_match_info_handle(last_match_info);
2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2974 subject_handle,
2975 0,
2976 last_match_info_handle);
2977 if (match.is_null()) {
2978 return Failure::Exception();
2979 }
2980 if (match->IsNull()) {
2981 return *subject_handle;
2982 }
2983
2984 int capture_count = regexp_handle->CaptureCount();
2985
2986 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002987 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002988 CompiledReplacement compiled_replacement;
2989 compiled_replacement.Compile(replacement_handle,
2990 capture_count,
2991 length);
2992
2993 bool is_global = regexp_handle->GetFlags().is_global();
2994
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002995 // Shortcut for simple non-regexp global replacements
2996 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002997 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002998 compiled_replacement.simple_hint()) {
2999 if (subject_handle->HasOnlyAsciiChars() &&
3000 replacement_handle->HasOnlyAsciiChars()) {
3001 return StringReplaceStringWithString<SeqAsciiString>(
3002 isolate, subject_handle, regexp_handle, replacement_handle);
3003 } else {
3004 return StringReplaceStringWithString<SeqTwoByteString>(
3005 isolate, subject_handle, regexp_handle, replacement_handle);
3006 }
3007 }
3008
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 // Guessing the number of parts that the final result string is built
3010 // from. Global regexps can match any number of times, so we guess
3011 // conservatively.
3012 int expected_parts =
3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 ReplacementStringBuilder builder(isolate->heap(),
3015 subject_handle,
3016 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003017
3018 // Index of end of last match.
3019 int prev = 0;
3020
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003021 // Number of parts added by compiled replacement plus preceeding
3022 // string and possibly suffix after last match. It is possible for
3023 // all components to use two elements when encoded as two smis.
3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 bool matched = true;
3026 do {
3027 ASSERT(last_match_info_handle->HasFastElements());
3028 // Increase the capacity of the builder before entering local handle-scope,
3029 // so its internal buffer can safely allocate a new handle if it grows.
3030 builder.EnsureCapacity(parts_added_per_loop);
3031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003032 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int start, end;
3034 {
3035 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003036 FixedArray* match_info_array =
3037 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003038
3039 ASSERT_EQ(capture_count * 2 + 2,
3040 RegExpImpl::GetLastCaptureCount(match_info_array));
3041 start = RegExpImpl::GetCapture(match_info_array, 0);
3042 end = RegExpImpl::GetCapture(match_info_array, 1);
3043 }
3044
3045 if (prev < start) {
3046 builder.AddSubjectSlice(prev, start);
3047 }
3048 compiled_replacement.Apply(&builder,
3049 start,
3050 end,
3051 last_match_info_handle);
3052 prev = end;
3053
3054 // Only continue checking for global regexps.
3055 if (!is_global) break;
3056
3057 // Continue from where the match ended, unless it was an empty match.
3058 int next = end;
3059 if (start == end) {
3060 next = end + 1;
3061 if (next > length) break;
3062 }
3063
3064 match = RegExpImpl::Exec(regexp_handle,
3065 subject_handle,
3066 next,
3067 last_match_info_handle);
3068 if (match.is_null()) {
3069 return Failure::Exception();
3070 }
3071 matched = !match->IsNull();
3072 } while (matched);
3073
3074 if (prev < length) {
3075 builder.AddSubjectSlice(prev, length);
3076 }
3077
3078 return *(builder.ToString());
3079}
3080
3081
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003083MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003085 String* subject,
3086 JSRegExp* regexp,
3087 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 ASSERT(subject->IsFlat());
3089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091
3092 Handle<String> subject_handle(subject);
3093 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003094
3095 // Shortcut for simple non-regexp global replacements
3096 if (regexp_handle->GetFlags().is_global() &&
3097 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3098 Handle<String> empty_string_handle(HEAP->empty_string());
3099 if (subject_handle->HasOnlyAsciiChars()) {
3100 return StringReplaceStringWithString<SeqAsciiString>(
3101 isolate, subject_handle, regexp_handle, empty_string_handle);
3102 } else {
3103 return StringReplaceStringWithString<SeqTwoByteString>(
3104 isolate, subject_handle, regexp_handle, empty_string_handle);
3105 }
3106 }
3107
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 Handle<JSArray> last_match_info_handle(last_match_info);
3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3110 subject_handle,
3111 0,
3112 last_match_info_handle);
3113 if (match.is_null()) return Failure::Exception();
3114 if (match->IsNull()) return *subject_handle;
3115
3116 ASSERT(last_match_info_handle->HasFastElements());
3117
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003118 int start, end;
3119 {
3120 AssertNoAllocation match_info_array_is_not_in_a_handle;
3121 FixedArray* match_info_array =
3122 FixedArray::cast(last_match_info_handle->elements());
3123
3124 start = RegExpImpl::GetCapture(match_info_array, 0);
3125 end = RegExpImpl::GetCapture(match_info_array, 1);
3126 }
3127
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003128 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 int new_length = length - (end - start);
3130 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003132 }
3133 Handle<ResultSeqString> answer;
3134 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003135 answer = Handle<ResultSeqString>::cast(
3136 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003137 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 answer = Handle<ResultSeqString>::cast(
3139 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 }
3141
3142 // If the regexp isn't global, only match once.
3143 if (!regexp_handle->GetFlags().is_global()) {
3144 if (start > 0) {
3145 String::WriteToFlat(*subject_handle,
3146 answer->GetChars(),
3147 0,
3148 start);
3149 }
3150 if (end < length) {
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + start,
3153 end,
3154 length);
3155 }
3156 return *answer;
3157 }
3158
3159 int prev = 0; // Index of end of last match.
3160 int next = 0; // Start of next search (prev unless last match was empty).
3161 int position = 0;
3162
3163 do {
3164 if (prev < start) {
3165 // Add substring subject[prev;start] to answer string.
3166 String::WriteToFlat(*subject_handle,
3167 answer->GetChars() + position,
3168 prev,
3169 start);
3170 position += start - prev;
3171 }
3172 prev = end;
3173 next = end;
3174 // Continue from where the match ended, unless it was an empty match.
3175 if (start == end) {
3176 next++;
3177 if (next > length) break;
3178 }
3179 match = RegExpImpl::Exec(regexp_handle,
3180 subject_handle,
3181 next,
3182 last_match_info_handle);
3183 if (match.is_null()) return Failure::Exception();
3184 if (match->IsNull()) break;
3185
3186 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188 {
3189 AssertNoAllocation match_info_array_is_not_in_a_handle;
3190 FixedArray* match_info_array =
3191 FixedArray::cast(last_match_info_handle->elements());
3192 start = RegExpImpl::GetCapture(match_info_array, 0);
3193 end = RegExpImpl::GetCapture(match_info_array, 1);
3194 }
3195 } while (true);
3196
3197 if (prev < length) {
3198 // Add substring subject[prev;length] to answer string.
3199 String::WriteToFlat(*subject_handle,
3200 answer->GetChars() + position,
3201 prev,
3202 length);
3203 position += length - prev;
3204 }
3205
3206 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 }
3209
3210 // Shorten string and fill
3211 int string_size = ResultSeqString::SizeFor(position);
3212 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3213 int delta = allocated_string_size - string_size;
3214
3215 answer->set_length(position);
3216 if (delta == 0) return *answer;
3217
3218 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003222 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223
3224 return *answer;
3225}
3226
3227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003228RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 ASSERT(args.length() == 4);
3230
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003231 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003233 Object* flat_subject;
3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3235 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3236 return maybe_flat_subject;
3237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238 }
3239 subject = String::cast(flat_subject);
3240 }
3241
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003242 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003243 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244 Object* flat_replacement;
3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3247 return maybe_flat_replacement;
3248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 }
3250 replacement = String::cast(flat_replacement);
3251 }
3252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255
3256 ASSERT(last_match_info->HasFastElements());
3257
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 if (replacement->length() == 0) {
3259 if (subject->HasOnlyAsciiChars()) {
3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003262 } else {
3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003265 }
3266 }
3267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 return StringReplaceRegExpWithString(isolate,
3269 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003270 regexp,
3271 replacement,
3272 last_match_info);
3273}
3274
3275
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003276Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3277 Handle<String> subject,
3278 Handle<String> search,
3279 Handle<String> replace,
3280 bool* found,
3281 int recursion_limit) {
3282 if (recursion_limit == 0) return Handle<String>::null();
3283 if (subject->IsConsString()) {
3284 ConsString* cons = ConsString::cast(*subject);
3285 Handle<String> first = Handle<String>(cons->first());
3286 Handle<String> second = Handle<String>(cons->second());
3287 Handle<String> new_first =
3288 StringReplaceOneCharWithString(isolate,
3289 first,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(new_first, second);
3295 if (new_first.is_null()) return new_first;
3296
3297 Handle<String> new_second =
3298 StringReplaceOneCharWithString(isolate,
3299 second,
3300 search,
3301 replace,
3302 found,
3303 recursion_limit - 1);
3304 if (*found) return isolate->factory()->NewConsString(first, new_second);
3305 if (new_second.is_null()) return new_second;
3306
3307 return subject;
3308 } else {
3309 int index = StringMatch(isolate, subject, search, 0);
3310 if (index == -1) return subject;
3311 *found = true;
3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3314 Handle<String> second =
3315 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3316 return isolate->factory()->NewConsString(cons1, second);
3317 }
3318}
3319
3320
3321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3322 ASSERT(args.length() == 3);
3323 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003327
3328 // If the cons string tree is too deep, we simply abort the recursion and
3329 // retry with a flattened subject string.
3330 const int kRecursionLimit = 0x1000;
3331 bool found = false;
3332 Handle<String> result =
3333 Runtime::StringReplaceOneCharWithString(isolate,
3334 subject,
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339 if (!result.is_null()) return *result;
3340 return *Runtime::StringReplaceOneCharWithString(isolate,
3341 FlattenGetString(subject),
3342 search,
3343 replace,
3344 &found,
3345 kRecursionLimit);
3346}
3347
3348
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349// Perform string match of pattern on subject, starting at start index.
3350// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352int Runtime::StringMatch(Isolate* isolate,
3353 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 Handle<String> pat,
3355 int start_index) {
3356 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003359 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003360 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003362 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003363 if (start_index + pattern_length > subject_length) return -1;
3364
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003365 if (!sub->IsFlat()) FlattenString(sub);
3366 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003367
ager@chromium.org7c537e22008-10-16 08:43:32 +00003368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003369 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 String::FlatContent seq_sub = sub->GetFlatContent();
3371 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003372
ager@chromium.org7c537e22008-10-16 08:43:32 +00003373 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 if (seq_pat.IsAscii()) {
3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3376 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 pat_vector,
3385 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003386 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3388 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003390 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003391 pat_vector,
3392 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 pat_vector,
3397 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003398}
3399
3400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003401RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003403 ASSERT(args.length() == 3);
3404
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003407
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003408 Object* index = args[2];
3409 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003411
ager@chromium.org870a0b62008-11-04 11:43:05 +00003412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 int position =
3414 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003415 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416}
3417
3418
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003419template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003420static int StringMatchBackwards(Vector<const schar> subject,
3421 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 int pattern_length = pattern.length();
3424 ASSERT(pattern_length >= 1);
3425 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426
3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003428 for (int i = 0; i < pattern_length; i++) {
3429 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 if (c > String::kMaxAsciiCharCode) {
3431 return -1;
3432 }
3433 }
3434 }
3435
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003438 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003440 while (j < pattern_length) {
3441 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442 break;
3443 }
3444 j++;
3445 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003446 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 return i;
3448 }
3449 }
3450 return -1;
3451}
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 ASSERT(args.length() == 3);
3456
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003465 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467 if (start_index + pat_length > sub_length) {
3468 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 if (pat_length == 0) {
3472 return Smi::FromInt(start_index);
3473 }
3474
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003475 if (!sub->IsFlat()) FlattenString(sub);
3476 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003477
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003478 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3480
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 String::FlatContent sub_content = sub->GetFlatContent();
3482 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003484 if (pat_content.IsAscii()) {
3485 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3486 if (sub_content.IsAscii()) {
3487 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003491 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003492 pat_vector,
3493 start_index);
3494 }
3495 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3497 if (sub_content.IsAscii()) {
3498 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003499 pat_vector,
3500 start_index);
3501 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003502 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003503 pat_vector,
3504 start_index);
3505 }
3506 }
3507
3508 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509}
3510
3511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003512RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 NoHandleAllocation ha;
3514 ASSERT(args.length() == 2);
3515
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003516 CONVERT_ARG_CHECKED(String, str1, 0);
3517 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 int str1_length = str1->length();
3521 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522
3523 // Decide trivial cases without flattening.
3524 if (str1_length == 0) {
3525 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3526 return Smi::FromInt(-str2_length);
3527 } else {
3528 if (str2_length == 0) return Smi::FromInt(str1_length);
3529 }
3530
3531 int end = str1_length < str2_length ? str1_length : str2_length;
3532
3533 // No need to flatten if we are going to find the answer on the first
3534 // character. At this point we know there is at least one character
3535 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003536 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 if (d != 0) return Smi::FromInt(d);
3538
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003539 str1->TryFlatten();
3540 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 StringInputBuffer& buf1 =
3543 *isolate->runtime_state()->string_locale_compare_buf1();
3544 StringInputBuffer& buf2 =
3545 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546
3547 buf1.Reset(str1);
3548 buf2.Reset(str2);
3549
3550 for (int i = 0; i < end; i++) {
3551 uint16_t char1 = buf1.GetNext();
3552 uint16_t char2 = buf2.GetNext();
3553 if (char1 != char2) return Smi::FromInt(char1 - char2);
3554 }
3555
3556 return Smi::FromInt(str1_length - str2_length);
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 3);
3563
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003564 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003565 int start, end;
3566 // We have a fast integer-only case here to avoid a conversion to double in
3567 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003568 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3569 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3570 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3571 start = from_number;
3572 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003573 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003576 start = FastD2I(from_number);
3577 end = FastD2I(to_number);
3578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 RUNTIME_ASSERT(end >= start);
3580 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003581 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003583 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584}
3585
3586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003587RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003588 ASSERT_EQ(3, args.length());
3589
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 HandleScope handles;
3594
3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3596
3597 if (match.is_null()) {
3598 return Failure::Exception();
3599 }
3600 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 }
3603 int length = subject->length();
3604
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003605 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 int start;
3608 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003609 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003610 {
3611 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003612 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3615 }
3616 offsets.Add(start);
3617 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003618 if (start == end) if (++end > length) break;
3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 if (match.is_null()) {
3621 return Failure::Exception();
3622 }
3623 } while (!match->IsNull());
3624 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003626 Handle<String> substring = isolate->factory()->
3627 NewSubString(subject, offsets.at(0), offsets.at(1));
3628 elements->set(0, *substring);
3629 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003630 int from = offsets.at(i * 2);
3631 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003632 Handle<String> substring = isolate->factory()->
3633 NewProperSubString(subject, from, to);
3634 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003635 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003637 result->set_length(Smi::FromInt(matches));
3638 return *result;
3639}
3640
3641
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642// Two smis before and after the match, for very long strings.
3643const int kMaxBuilderEntriesPerRegExpMatch = 5;
3644
3645
3646static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3647 Handle<JSArray> last_match_info,
3648 int match_start,
3649 int match_end) {
3650 // Fill last_match_info with a single capture.
3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3652 AssertNoAllocation no_gc;
3653 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3654 RegExpImpl::SetLastCaptureCount(elements, 2);
3655 RegExpImpl::SetLastInput(elements, *subject);
3656 RegExpImpl::SetLastSubject(elements, *subject);
3657 RegExpImpl::SetCapture(elements, 0, match_start);
3658 RegExpImpl::SetCapture(elements, 1, match_end);
3659}
3660
3661
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663static bool SearchStringMultiple(Isolate* isolate,
3664 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 Vector<const PatternChar> pattern,
3666 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003667 FixedArrayBuilder* builder,
3668 int* match_pos) {
3669 int pos = *match_pos;
3670 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003671 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003674 while (pos <= max_search_start) {
3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3676 *match_pos = pos;
3677 return false;
3678 }
3679 // Position of end of previous match.
3680 int match_end = pos + pattern_length;
3681 int new_pos = search.Search(subject, match_end);
3682 if (new_pos >= 0) {
3683 // A match.
3684 if (new_pos > match_end) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003689 pos = new_pos;
3690 builder->Add(pattern_string);
3691 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003693 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003695
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 if (pos < max_search_start) {
3697 ReplacementStringBuilder::AddSubjectSlice(builder,
3698 pos + pattern_length,
3699 subject_length);
3700 }
3701 *match_pos = pos;
3702 return true;
3703}
3704
3705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706static bool SearchStringMultiple(Isolate* isolate,
3707 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003708 Handle<String> pattern,
3709 Handle<JSArray> last_match_info,
3710 FixedArrayBuilder* builder) {
3711 ASSERT(subject->IsFlat());
3712 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713
3714 // Treating as if a previous match was before first character.
3715 int match_pos = -pattern->length();
3716
3717 for (;;) { // Break when search complete.
3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3719 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003720 String::FlatContent subject_content = subject->GetFlatContent();
3721 String::FlatContent pattern_content = pattern->GetFlatContent();
3722 if (subject_content.IsAscii()) {
3723 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3724 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 }
3739 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3741 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003744 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003745 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746 builder,
3747 &match_pos)) break;
3748 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 if (SearchStringMultiple(isolate,
3750 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003751 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003752 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003753 builder,
3754 &match_pos)) break;
3755 }
3756 }
3757 }
3758
3759 if (match_pos >= 0) {
3760 SetLastMatchInfoNoCaptures(subject,
3761 last_match_info,
3762 match_pos,
3763 match_pos + pattern->length());
3764 return true;
3765 }
3766 return false; // No matches at all.
3767}
3768
3769
3770static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003772 Handle<String> subject,
3773 Handle<JSRegExp> regexp,
3774 Handle<JSArray> last_match_array,
3775 FixedArrayBuilder* builder) {
3776 ASSERT(subject->IsFlat());
3777 int match_start = -1;
3778 int match_end = 0;
3779 int pos = 0;
3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3782
ulan@chromium.org812308e2012-02-29 15:58:45 +00003783 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003784 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003786 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003787
3788 for (;;) { // Break on failure, return on exception.
3789 RegExpImpl::IrregexpResult result =
3790 RegExpImpl::IrregexpExecOnce(regexp,
3791 subject,
3792 pos,
3793 register_vector);
3794 if (result == RegExpImpl::RE_SUCCESS) {
3795 match_start = register_vector[0];
3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3797 if (match_end < match_start) {
3798 ReplacementStringBuilder::AddSubjectSlice(builder,
3799 match_end,
3800 match_start);
3801 }
3802 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 if (!first) {
3805 builder->Add(*isolate->factory()->NewProperSubString(subject,
3806 match_start,
3807 match_end));
3808 } else {
3809 builder->Add(*isolate->factory()->NewSubString(subject,
3810 match_start,
3811 match_end));
3812 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003813 if (match_start != match_end) {
3814 pos = match_end;
3815 } else {
3816 pos = match_end + 1;
3817 if (pos > subject_length) break;
3818 }
3819 } else if (result == RegExpImpl::RE_FAILURE) {
3820 break;
3821 } else {
3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3823 return result;
3824 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003825 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003826 }
3827
3828 if (match_start >= 0) {
3829 if (match_end < subject_length) {
3830 ReplacementStringBuilder::AddSubjectSlice(builder,
3831 match_end,
3832 subject_length);
3833 }
3834 SetLastMatchInfoNoCaptures(subject,
3835 last_match_array,
3836 match_start,
3837 match_end);
3838 return RegExpImpl::RE_SUCCESS;
3839 } else {
3840 return RegExpImpl::RE_FAILURE; // No matches at all.
3841 }
3842}
3843
3844
3845static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003847 Handle<String> subject,
3848 Handle<JSRegExp> regexp,
3849 Handle<JSArray> last_match_array,
3850 FixedArrayBuilder* builder) {
3851
3852 ASSERT(subject->IsFlat());
3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3855
ulan@chromium.org812308e2012-02-29 15:58:45 +00003856 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003857 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003858
3859 RegExpImpl::IrregexpResult result =
3860 RegExpImpl::IrregexpExecOnce(regexp,
3861 subject,
3862 0,
3863 register_vector);
3864
3865 int capture_count = regexp->CaptureCount();
3866 int subject_length = subject->length();
3867
3868 // Position to search from.
3869 int pos = 0;
3870 // End of previous match. Differs from pos if match was empty.
3871 int match_end = 0;
3872 if (result == RegExpImpl::RE_SUCCESS) {
3873 // Need to keep a copy of the previous match for creating last_match_info
3874 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003875 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003877 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 do {
3879 int match_start = register_vector[0];
3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3881 if (match_end < match_start) {
3882 ReplacementStringBuilder::AddSubjectSlice(builder,
3883 match_end,
3884 match_start);
3885 }
3886 match_end = register_vector[1];
3887
3888 {
3889 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 // Arguments array to replace function is match, captures, index and
3892 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 Handle<FixedArray> elements =
3894 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 Handle<String> match;
3896 if (!first) {
3897 match = isolate->factory()->NewProperSubString(subject,
3898 match_start,
3899 match_end);
3900 } else {
3901 match = isolate->factory()->NewSubString(subject,
3902 match_start,
3903 match_end);
3904 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 for (int i = 1; i <= capture_count; i++) {
3907 int start = register_vector[i * 2];
3908 if (start >= 0) {
3909 int end = register_vector[i * 2 + 1];
3910 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003911 Handle<String> substring;
3912 if (!first) {
3913 substring = isolate->factory()->NewProperSubString(subject,
3914 start,
3915 end);
3916 } else {
3917 substring = isolate->factory()->NewSubString(subject, start, end);
3918 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 elements->set(i, *substring);
3920 } else {
3921 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 }
3924 }
3925 elements->set(capture_count + 1, Smi::FromInt(match_start));
3926 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003928 }
3929 // Swap register vectors, so the last successful match is in
3930 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003931 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 prev_register_vector = register_vector;
3933 register_vector = tmp;
3934
3935 if (match_end > match_start) {
3936 pos = match_end;
3937 } else {
3938 pos = match_end + 1;
3939 if (pos > subject_length) {
3940 break;
3941 }
3942 }
3943
3944 result = RegExpImpl::IrregexpExecOnce(regexp,
3945 subject,
3946 pos,
3947 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003948 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003949 } while (result == RegExpImpl::RE_SUCCESS);
3950
3951 if (result != RegExpImpl::RE_EXCEPTION) {
3952 // Finished matching, with at least one match.
3953 if (match_end < subject_length) {
3954 ReplacementStringBuilder::AddSubjectSlice(builder,
3955 match_end,
3956 subject_length);
3957 }
3958
3959 int last_match_capture_count = (capture_count + 1) * 2;
3960 int last_match_array_size =
3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3962 last_match_array->EnsureSize(last_match_array_size);
3963 AssertNoAllocation no_gc;
3964 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3966 RegExpImpl::SetLastSubject(elements, *subject);
3967 RegExpImpl::SetLastInput(elements, *subject);
3968 for (int i = 0; i < last_match_capture_count; i++) {
3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3970 }
3971 return RegExpImpl::RE_SUCCESS;
3972 }
3973 }
3974 // No matches at all, return failure or exception result directly.
3975 return result;
3976}
3977
3978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003982
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003984 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988
3989 ASSERT(last_match_info->HasFastElements());
3990 ASSERT(regexp->GetFlags().is_global());
3991 Handle<FixedArray> result_elements;
3992 if (result_array->HasFastElements()) {
3993 result_elements =
3994 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003995 }
3996 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 }
3999 FixedArrayBuilder builder(result_elements);
4000
4001 if (regexp->TypeTag() == JSRegExp::ATOM) {
4002 Handle<String> pattern(
4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004004 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 if (SearchStringMultiple(isolate, subject, pattern,
4006 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004007 return *builder.ToJSArray(result_array);
4008 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011
4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4013
4014 RegExpImpl::IrregexpResult result;
4015 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004016 result = SearchRegExpNoCaptureMultiple(isolate,
4017 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 regexp,
4019 last_match_info,
4020 &builder);
4021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 result = SearchRegExpMultiple(isolate,
4023 subject,
4024 regexp,
4025 last_match_info,
4026 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004027 }
4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4031 return Failure::Exception();
4032}
4033
4034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 NoHandleAllocation ha;
4037 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004039 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004041 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004042 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004044 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004045 // Character array used for conversion.
4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return isolate->heap()->
4048 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004049 }
4050 }
4051
4052 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004053 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
4057 if (isinf(value)) {
4058 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 MaybeObject* result =
4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 DeleteArray(str);
4067 return result;
4068}
4069
4070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 NoHandleAllocation ha;
4073 ASSERT(args.length() == 2);
4074
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004075 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 }
4079 if (isinf(value)) {
4080 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 int f = FastD2I(f_number);
4087 RUNTIME_ASSERT(f >= 0);
4088 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 MaybeObject* res =
4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093}
4094
4095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 NoHandleAllocation ha;
4098 ASSERT(args.length() == 2);
4099
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004100 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104 if (isinf(value)) {
4105 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004106 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004108 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 int f = FastD2I(f_number);
4112 RUNTIME_ASSERT(f >= -1 && f <= 20);
4113 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 MaybeObject* res =
4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 NoHandleAllocation ha;
4123 ASSERT(args.length() == 2);
4124
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004125 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
4129 if (isinf(value)) {
4130 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004133 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 int f = FastD2I(f_number);
4137 RUNTIME_ASSERT(f >= 1 && f <= 21);
4138 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 MaybeObject* res =
4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
4146// Returns a single character string where first character equals
4147// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004150 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004151 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004152 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155}
4156
4157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4159 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 // Handle [] indexing on Strings
4162 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4164 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 }
4166
4167 // Handle [] indexing on String objects
4168 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4170 Handle<Object> result =
4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4172 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 }
4174
4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004176 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 return object->GetElement(index);
4180}
4181
4182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4184 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 isolate->factory()->NewTypeError("non_object_property_load",
4192 HandleVector(args, 2));
4193 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 }
4195
4196 // Check if the given key is an array index.
4197 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004198 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 }
4201
4202 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004203 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207 bool has_pending_exception = false;
4208 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004211 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 }
4213
ager@chromium.org32912102009-01-16 10:38:43 +00004214 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215 // the element if so.
4216 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004219 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 }
4221}
4222
4223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 NoHandleAllocation ha;
4226 ASSERT(args.length() == 2);
4227
4228 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004229 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232}
4233
4234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004235// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 2);
4239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004240 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004241 // itself.
4242 //
4243 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004244 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004245 // global proxy object never has properties. This is the case
4246 // because the global proxy object forwards everything to its hidden
4247 // prototype including local lookups.
4248 //
4249 // Additionally, we need to make sure that we do not cache results
4250 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004251 if (args[0]->IsJSObject()) {
4252 if (!args[0]->IsJSGlobalProxy() &&
4253 !args[0]->IsAccessCheckNeeded() &&
4254 args[1]->IsString()) {
4255 JSObject* receiver = JSObject::cast(args[0]);
4256 String* key = String::cast(args[1]);
4257 if (receiver->HasFastProperties()) {
4258 // Attempt to use lookup cache.
4259 Map* receiver_map = receiver->map();
4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4262 if (offset != -1) {
4263 Object* value = receiver->FastPropertyAt(offset);
4264 return value->IsTheHole()
4265 ? isolate->heap()->undefined_value()
4266 : value;
4267 }
4268 // Lookup cache miss. Perform lookup and update the cache if
4269 // appropriate.
4270 LookupResult result(isolate);
4271 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004272 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 int offset = result.GetFieldIndex();
4274 keyed_lookup_cache->Update(receiver_map, key, offset);
4275 return receiver->FastPropertyAt(offset);
4276 }
4277 } else {
4278 // Attempt dictionary lookup.
4279 StringDictionary* dictionary = receiver->property_dictionary();
4280 int entry = dictionary->FindEntry(key);
4281 if ((entry != StringDictionary::kNotFound) &&
4282 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4283 Object* value = dictionary->ValueAt(entry);
4284 if (!receiver->IsGlobalObject()) return value;
4285 value = JSGlobalPropertyCell::cast(value)->value();
4286 if (!value->IsTheHole()) return value;
4287 // If value is the hole do the general lookup.
4288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004289 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4291 // JSObject without a string key. If the key is a Smi, check for a
4292 // definite out-of-bounds access to elements, which is a strong indicator
4293 // that subsequent accesses will also call the runtime. Proactively
4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4295 // doubles for those future calls in the case that the elements would
4296 // become FAST_DOUBLE_ELEMENTS.
4297 Handle<JSObject> js_object(args.at<JSObject>(0));
4298 ElementsKind elements_kind = js_object->GetElementsKind();
4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4300 elements_kind == FAST_DOUBLE_ELEMENTS) {
4301 FixedArrayBase* elements = js_object->elements();
4302 if (args.at<Smi>(1)->value() >= elements->length()) {
4303 MaybeObject* maybe_object = TransitionElements(js_object,
4304 FAST_ELEMENTS,
4305 isolate);
4306 if (maybe_object->IsFailure()) return maybe_object;
4307 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004308 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004310 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4311 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004313 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004314 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004315 if (index >= 0 && index < str->length()) {
4316 Handle<Object> result = GetCharAt(str, index);
4317 return *result;
4318 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004319 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004320
4321 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 return Runtime::GetObjectProperty(isolate,
4323 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004324 args.at<Object>(1));
4325}
4326
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004327
4328static bool IsValidAccessor(Handle<Object> obj) {
4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4330}
4331
4332
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4b - define a new accessor property.
4336// Steps 9c & 12 - replace an existing data property with an accessor property.
4337// Step 12 - update an existing accessor property with an accessor or generic
4338// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004343 RUNTIME_ASSERT(!obj->IsNull());
4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4346 RUNTIME_ASSERT(IsValidAccessor(getter));
4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4348 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004349 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004352
danno@chromium.org88aa0582012-03-23 15:11:57 +00004353 bool fast = obj->HasFastProperties();
4354 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4355 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004356 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004357}
4358
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004359// Implements part of 8.12.9 DefineOwnProperty.
4360// There are 3 cases that lead here:
4361// Step 4a - define a new data property.
4362// Steps 9b & 12 - replace an existing accessor property with a data property.
4363// Step 12 - update an existing data property with a data or generic
4364// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004368 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4369 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004370 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004371 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004372 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004373 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4374
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004375 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004376 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004377
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004378 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004379 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004380 Object* callback = result.GetCallbackObject();
4381 // To be compatible with Safari we do not change the value on API objects
4382 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4383 // the value.
4384 if (callback->IsAccessorInfo()) {
4385 return isolate->heap()->undefined_value();
4386 }
4387 // Avoid redefining foreign callback as data property, just use the stored
4388 // setter to update the value instead.
4389 // TODO(mstarzinger): So far this only works if property attributes don't
4390 // change, this should be fixed once we cleanup the underlying code.
4391 if (callback->IsForeign() && result.GetAttributes() == attr) {
4392 return js_object->SetPropertyWithCallback(callback,
4393 *name,
4394 *obj_value,
4395 result.holder(),
4396 kStrictMode);
4397 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004398 }
4399
ager@chromium.org5c838252010-02-19 08:53:10 +00004400 // Take special care when attributes are different and there is already
4401 // a property. For simplicity we normalize the property which enables us
4402 // to not worry about changing the instance_descriptor and creating a new
4403 // map. The current version of SetObjectProperty does not handle attributes
4404 // correctly in the case where a property is a field and is reset with
4405 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004406 if (result.IsProperty() &&
4407 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004409 if (js_object->IsJSGlobalProxy()) {
4410 // Since the result is a property, the prototype will exist so
4411 // we don't have to check for null.
4412 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004413 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004414 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004415 // Use IgnoreAttributes version since a readonly property may be
4416 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004417 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4418 *obj_value,
4419 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 return Runtime::ForceSetObjectProperty(isolate,
4423 js_object,
4424 name,
4425 obj_value,
4426 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004427}
4428
4429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4431 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004432 Handle<Object> key,
4433 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004434 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004435 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004436 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004440 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004442 isolate->factory()->NewTypeError("non_object_property_store",
4443 HandleVector(args, 2));
4444 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
4446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004447 if (object->IsJSProxy()) {
4448 bool has_pending_exception = false;
4449 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4450 if (has_pending_exception) return Failure::Exception();
4451 return JSProxy::cast(*object)->SetProperty(
4452 String::cast(*name), *value, attr, strict_mode);
4453 }
4454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 // If the object isn't a JavaScript object, we ignore the store.
4456 if (!object->IsJSObject()) return *value;
4457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004458 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 // Check if the given key is an array index.
4461 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004462 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004474 Handle<Object> result = JSObject::SetElement(
4475 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004476 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 return *value;
4478 }
4479
4480 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481 Handle<Object> result;
4482 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004483 result = JSObject::SetElement(
4484 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004487 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004488 result = JSReceiver::SetProperty(
4489 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004491 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 return *value;
4493 }
4494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 bool has_pending_exception = false;
4497 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4498 if (has_pending_exception) return Failure::Exception();
4499 Handle<String> name = Handle<String>::cast(converted);
4500
4501 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004502 return js_object->SetElement(
4503 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004505 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 }
4507}
4508
4509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4511 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004512 Handle<Object> key,
4513 Handle<Object> value,
4514 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516
4517 // Check if the given key is an array index.
4518 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004519 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004520 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4521 // of a string using [] notation. We need to support this too in
4522 // JavaScript.
4523 // In the case of a String object we just need to redirect the assignment to
4524 // the underlying string if the index is in range. Since the underlying
4525 // string does nothing with the assignment then we can ignore such
4526 // assignments.
4527 if (js_object->IsStringObjectWithCharacterAt(index)) {
4528 return *value;
4529 }
4530
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004531 return js_object->SetElement(
4532 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 }
4534
4535 if (key->IsString()) {
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004537 return js_object->SetElement(
4538 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004539 } else {
4540 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004541 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004542 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4543 *value,
4544 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004545 }
4546 }
4547
4548 // Call-back into JavaScript to convert the key to a string.
4549 bool has_pending_exception = false;
4550 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4551 if (has_pending_exception) return Failure::Exception();
4552 Handle<String> name = Handle<String>::cast(converted);
4553
4554 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004555 return js_object->SetElement(
4556 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004557 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004558 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004559 }
4560}
4561
4562
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004563MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004564 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004567
4568 // Check if the given key is an array index.
4569 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004571 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4572 // characters of a string using [] notation. In the case of a
4573 // String object we just need to redirect the deletion to the
4574 // underlying string if the index is in range. Since the
4575 // underlying string does nothing with the deletion, we can ignore
4576 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004577 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004579 }
4580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004581 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004582 }
4583
4584 Handle<String> key_string;
4585 if (key->IsString()) {
4586 key_string = Handle<String>::cast(key);
4587 } else {
4588 // Call-back into JavaScript to convert the key to a string.
4589 bool has_pending_exception = false;
4590 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4591 if (has_pending_exception) return Failure::Exception();
4592 key_string = Handle<String>::cast(converted);
4593 }
4594
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004595 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004596 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597}
4598
4599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004600RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 Handle<Object> object = args.at<Object>(0);
4605 Handle<Object> key = args.at<Object>(1);
4606 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004607 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004608 RUNTIME_ASSERT(
4609 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004611 PropertyAttributes attributes =
4612 static_cast<PropertyAttributes>(unchecked_attributes);
4613
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004614 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004615 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004616 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004617 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 return Runtime::SetObjectProperty(isolate,
4621 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004622 key,
4623 value,
4624 attributes,
4625 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626}
4627
4628
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004629RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4630 NoHandleAllocation ha;
4631 RUNTIME_ASSERT(args.length() == 1);
4632 Handle<Object> object = args.at<Object>(0);
4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4634}
4635
4636
4637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_ELEMENTS, isolate);
4642}
4643
4644
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004645// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004646// This is used to decide if we should transform null and undefined
4647// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004649 NoHandleAllocation ha;
4650 RUNTIME_ASSERT(args.length() == 1);
4651
4652 Handle<Object> object = args.at<Object>(0);
4653
4654 if (object->IsJSFunction()) {
4655 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 }
4658 return isolate->heap()->undefined_value();
4659}
4660
4661
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004662RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4663 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004664 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004665 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4666 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004667 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004668 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4669 HandleScope scope;
4670
4671 Object* raw_boilerplate_object = literals->get(literal_index);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004672 Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673#if DEBUG
4674 ElementsKind elements_kind = object->GetElementsKind();
4675#endif
4676 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4677 // Smis should never trigger transitions.
4678 ASSERT(!value->IsSmi());
4679
4680 if (value->IsNumber()) {
4681 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004682 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004683 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4684 FAST_DOUBLE_ELEMENTS)) {
4685 JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
4686 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004687 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004688 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004689 HeapNumber* number = HeapNumber::cast(*value);
4690 double_array->set(store_index, number->Number());
4691 } else {
4692 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4693 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004694 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004695 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4696 FAST_ELEMENTS)) {
4697 JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
4698 }
4699 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004700 object_array->set(store_index, *value);
4701 }
4702 return *object;
4703}
4704
4705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706// Set a local property, even if it is READ_ONLY. If the property does not
4707// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004708RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004710 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004711 CONVERT_ARG_CHECKED(JSObject, object, 0);
4712 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004713 // Compute attributes.
4714 PropertyAttributes attributes = NONE;
4715 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004716 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004717 // Only attribute bits should be set.
4718 RUNTIME_ASSERT(
4719 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4720 attributes = static_cast<PropertyAttributes>(unchecked_value);
4721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004723 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004724 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725}
4726
4727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004728RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004730 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004732 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4733 CONVERT_ARG_CHECKED(String, key, 1);
4734 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004735 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004736 ? JSReceiver::STRICT_DELETION
4737 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004738}
4739
4740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004741static Object* HasLocalPropertyImplementation(Isolate* isolate,
4742 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004743 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004744 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004745 // Handle hidden prototypes. If there's a hidden prototype above this thing
4746 // then we have to check it for properties, because they are supposed to
4747 // look like they are on this object.
4748 Handle<Object> proto(object->GetPrototype());
4749 if (proto->IsJSObject() &&
4750 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004751 return HasLocalPropertyImplementation(isolate,
4752 Handle<JSObject>::cast(proto),
4753 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004754 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004756}
4757
4758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004759RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 NoHandleAllocation ha;
4761 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004762 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004764 uint32_t index;
4765 const bool key_is_array_index = key->AsArrayIndex(&index);
4766
ager@chromium.org9085a012009-05-11 19:22:57 +00004767 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004769 if (obj->IsJSObject()) {
4770 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 // Fast case: either the key is a real named property or it is not
4772 // an array index and there are no interceptors or hidden
4773 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004774 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004775 Map* map = object->map();
4776 if (!key_is_array_index &&
4777 !map->has_named_interceptor() &&
4778 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4779 return isolate->heap()->false_value();
4780 }
4781 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004782 HandleScope scope(isolate);
4783 return HasLocalPropertyImplementation(isolate,
4784 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004785 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004786 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004788 String* string = String::cast(obj);
4789 if (index < static_cast<uint32_t>(string->length())) {
4790 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 }
4792 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794}
4795
4796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004797RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 NoHandleAllocation na;
4799 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004800 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4801 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004803 bool result = receiver->HasProperty(key);
4804 if (isolate->has_pending_exception()) return Failure::Exception();
4805 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806}
4807
4808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004809RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 NoHandleAllocation na;
4811 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004812 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4813 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004815 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004816 if (isolate->has_pending_exception()) return Failure::Exception();
4817 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818}
4819
4820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004821RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 NoHandleAllocation ha;
4823 ASSERT(args.length() == 2);
4824
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004825 CONVERT_ARG_CHECKED(JSObject, object, 0);
4826 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
4828 uint32_t index;
4829 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004830 JSObject::LocalElementType type = object->HasLocalElement(index);
4831 switch (type) {
4832 case JSObject::UNDEFINED_ELEMENT:
4833 case JSObject::STRING_CHARACTER_ELEMENT:
4834 return isolate->heap()->false_value();
4835 case JSObject::INTERCEPTED_ELEMENT:
4836 case JSObject::FAST_ELEMENT:
4837 return isolate->heap()->true_value();
4838 case JSObject::DICTIONARY_ELEMENT: {
4839 if (object->IsJSGlobalProxy()) {
4840 Object* proto = object->GetPrototype();
4841 if (proto->IsNull()) {
4842 return isolate->heap()->false_value();
4843 }
4844 ASSERT(proto->IsJSGlobalObject());
4845 object = JSObject::cast(proto);
4846 }
4847 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004848 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004849 if (elements->map() ==
4850 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004851 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004852 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004853 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004854 }
4855 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004856 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 PropertyDetails details = dictionary->DetailsAt(entry);
4858 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4859 }
4860 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 }
4862
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865}
4866
4867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004868RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004871 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004872 bool threw = false;
4873 Handle<JSArray> result = GetKeysFor(object, &threw);
4874 if (threw) return Failure::Exception();
4875 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876}
4877
4878
4879// Returns either a FixedArray as Runtime_GetPropertyNames,
4880// or, if the given object has an enum cache that contains
4881// all enumerable properties of the object and its prototypes
4882// have none, the map of the object. This is used to speed up
4883// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004884RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 ASSERT(args.length() == 1);
4886
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004887 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
4889 if (raw_object->IsSimpleEnum()) return raw_object->map();
4890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004892 Handle<JSReceiver> object(raw_object);
4893 bool threw = false;
4894 Handle<FixedArray> content =
4895 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4896 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897
4898 // Test again, since cache may have been built by preceding call.
4899 if (object->IsSimpleEnum()) return object->map();
4900
4901 return *content;
4902}
4903
4904
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004905// Find the length of the prototype chain that is to to handled as one. If a
4906// prototype object is hidden it is to be viewed as part of the the object it
4907// is prototype for.
4908static int LocalPrototypeChainLength(JSObject* obj) {
4909 int count = 1;
4910 Object* proto = obj->GetPrototype();
4911 while (proto->IsJSObject() &&
4912 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4913 count++;
4914 proto = JSObject::cast(proto)->GetPrototype();
4915 }
4916 return count;
4917}
4918
4919
4920// Return the names of the local named properties.
4921// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924 ASSERT(args.length() == 1);
4925 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004926 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004927 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004928 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004929
4930 // Skip the global proxy as it has no properties and always delegates to the
4931 // real global object.
4932 if (obj->IsJSGlobalProxy()) {
4933 // Only collect names if access is permitted.
4934 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004935 !isolate->MayNamedAccess(*obj,
4936 isolate->heap()->undefined_value(),
4937 v8::ACCESS_KEYS)) {
4938 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4939 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004940 }
4941 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4942 }
4943
4944 // Find the number of objects making up this.
4945 int length = LocalPrototypeChainLength(*obj);
4946
4947 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004948 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 int total_property_count = 0;
4950 Handle<JSObject> jsproto = obj;
4951 for (int i = 0; i < length; i++) {
4952 // Only collect names if access is permitted.
4953 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 !isolate->MayNamedAccess(*jsproto,
4955 isolate->heap()->undefined_value(),
4956 v8::ACCESS_KEYS)) {
4957 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4958 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004959 }
4960 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004961 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004962 local_property_count[i] = n;
4963 total_property_count += n;
4964 if (i < length - 1) {
4965 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4966 }
4967 }
4968
4969 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 Handle<FixedArray> names =
4971 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004972
4973 // Get the property names.
4974 jsproto = obj;
4975 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004976 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004978 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4979 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004980 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 proto_with_hidden_properties++;
4982 }
4983 if (i < length - 1) {
4984 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4985 }
4986 }
4987
4988 // Filter out name of hidden propeties object.
4989 if (proto_with_hidden_properties > 0) {
4990 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992 names->length() - proto_with_hidden_properties);
4993 int dest_pos = 0;
4994 for (int i = 0; i < total_property_count; i++) {
4995 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997 continue;
4998 }
4999 names->set(dest_pos++, name);
5000 }
5001 }
5002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004}
5005
5006
5007// Return the names of the local indexed properties.
5008// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005010 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005011 ASSERT(args.length() == 1);
5012 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005013 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005014 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005015 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005016
5017 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005018 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005020 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005021}
5022
5023
5024// Return information on whether an object has a named or indexed interceptor.
5025// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005026RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005028 ASSERT(args.length() == 1);
5029 if (!args[0]->IsJSObject()) {
5030 return Smi::FromInt(0);
5031 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005032 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005033
5034 int result = 0;
5035 if (obj->HasNamedInterceptor()) result |= 2;
5036 if (obj->HasIndexedInterceptor()) result |= 1;
5037
5038 return Smi::FromInt(result);
5039}
5040
5041
5042// Return property names from named interceptor.
5043// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005044RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005047 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005048
5049 if (obj->HasNamedInterceptor()) {
5050 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5051 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005054}
5055
5056
5057// Return element names from indexed interceptor.
5058// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005059RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005061 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005062 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005063
5064 if (obj->HasIndexedInterceptor()) {
5065 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5066 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005069}
5070
5071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005072RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005073 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005074 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005076 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005077
5078 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005079 // Do access checks before going to the global object.
5080 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005082 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005083 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5084 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005085 }
5086
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005087 Handle<Object> proto(object->GetPrototype());
5088 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005090 object = Handle<JSObject>::cast(proto);
5091 }
5092
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005093 bool threw = false;
5094 Handle<FixedArray> contents =
5095 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5096 if (threw) return Failure::Exception();
5097
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005098 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5099 // property array and since the result is mutable we have to create
5100 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005101 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005103 for (int i = 0; i < length; i++) {
5104 Object* entry = contents->get(i);
5105 if (entry->IsString()) {
5106 copy->set(i, entry);
5107 } else {
5108 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 HandleScope scope(isolate);
5110 Handle<Object> entry_handle(entry, isolate);
5111 Handle<Object> entry_str =
5112 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005113 copy->set(i, *entry_str);
5114 }
5115 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005117}
5118
5119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005120RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005121 NoHandleAllocation ha;
5122 ASSERT(args.length() == 1);
5123
5124 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005125 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 it.AdvanceToArgumentsFrame();
5127 JavaScriptFrame* frame = it.frame();
5128
5129 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005130 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005131
5132 // Try to convert the key to an index. If successful and within
5133 // index return the the argument from the frame.
5134 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005135 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136 return frame->GetParameter(index);
5137 }
5138
5139 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141 bool exception = false;
5142 Handle<Object> converted =
5143 Execution::ToString(args.at<Object>(0), &exception);
5144 if (exception) return Failure::Exception();
5145 Handle<String> key = Handle<String>::cast(converted);
5146
5147 // Try to convert the string key into an array index.
5148 if (key->AsArrayIndex(&index)) {
5149 if (index < n) {
5150 return frame->GetParameter(index);
5151 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005152 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005153 }
5154 }
5155
5156 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005157 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5158 if (key->Equals(isolate->heap()->callee_symbol())) {
5159 Object* function = frame->function();
5160 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005161 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 return isolate->Throw(*isolate->factory()->NewTypeError(
5163 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5164 }
5165 return function;
5166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005167
5168 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170}
5171
5172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005173RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005174 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005175 Object* object = args[0];
5176 return (object->IsJSObject() && !object->IsGlobalObject())
5177 ? JSObject::cast(object)->TransformToFastProperties(0)
5178 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005179}
5180
5181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005182RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005183 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005184 Object* obj = args[0];
5185 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5186 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5187 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005188}
5189
5190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005191RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192 NoHandleAllocation ha;
5193 ASSERT(args.length() == 1);
5194
5195 return args[0]->ToBoolean();
5196}
5197
5198
5199// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5200// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005201RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 NoHandleAllocation ha;
5203
5204 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 HeapObject* heap_obj = HeapObject::cast(obj);
5207
5208 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 if (heap_obj->map()->is_undetectable()) {
5210 return isolate->heap()->undefined_symbol();
5211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212
5213 InstanceType instance_type = heap_obj->map()->instance_type();
5214 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 }
5217
5218 switch (instance_type) {
5219 case ODDBALL_TYPE:
5220 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222 }
5223 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005224 return FLAG_harmony_typeof
5225 ? isolate->heap()->null_symbol()
5226 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005227 }
5228 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005230 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005231 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 default:
5234 // For any kind of object not handled above, the spec rule for
5235 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 }
5238}
5239
5240
lrn@chromium.org25156de2010-04-06 13:10:27 +00005241static bool AreDigits(const char*s, int from, int to) {
5242 for (int i = from; i < to; i++) {
5243 if (s[i] < '0' || s[i] > '9') return false;
5244 }
5245
5246 return true;
5247}
5248
5249
5250static int ParseDecimalInteger(const char*s, int from, int to) {
5251 ASSERT(to - from < 10); // Overflow is not possible.
5252 ASSERT(from < to);
5253 int d = s[from] - '0';
5254
5255 for (int i = from + 1; i < to; i++) {
5256 d = 10 * d + (s[i] - '0');
5257 }
5258
5259 return d;
5260}
5261
5262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005263RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 NoHandleAllocation ha;
5265 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005266 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005267 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005268
5269 // Fast case: short integer or some sorts of junk values.
5270 int len = subject->length();
5271 if (subject->IsSeqAsciiString()) {
5272 if (len == 0) return Smi::FromInt(0);
5273
5274 char const* data = SeqAsciiString::cast(subject)->GetChars();
5275 bool minus = (data[0] == '-');
5276 int start_pos = (minus ? 1 : 0);
5277
5278 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005280 } else if (data[start_pos] > '9') {
5281 // Fast check for a junk value. A valid string may start from a
5282 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5283 // the 'I' character ('Infinity'). All of that have codes not greater than
5284 // '9' except 'I'.
5285 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005287 }
5288 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5289 // The maximal/minimal smi has 10 digits. If the string has less digits we
5290 // know it will fit into the smi-data type.
5291 int d = ParseDecimalInteger(data, start_pos, len);
5292 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005294 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005295 } else if (!subject->HasHashCode() &&
5296 len <= String::kMaxArrayIndexSize &&
5297 (len == 1 || data[0] != '0')) {
5298 // String hash is not calculated yet but all the data are present.
5299 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005300 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005301#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005302 subject->Hash(); // Force hash calculation.
5303 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5304 static_cast<int>(hash));
5305#endif
5306 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005307 }
5308 return Smi::FromInt(d);
5309 }
5310 }
5311
5312 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005313 return isolate->heap()->NumberFromDouble(
5314 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315}
5316
5317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005318RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 NoHandleAllocation ha;
5320 ASSERT(args.length() == 1);
5321
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005322 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 int length = Smi::cast(codes->length())->value();
5324
5325 // Check if the string can be ASCII.
5326 int i;
5327 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005328 Object* element;
5329 { MaybeObject* maybe_element = codes->GetElement(i);
5330 // We probably can't get an exception here, but just in order to enforce
5331 // the checking of inputs in the runtime calls we check here.
5332 if (!maybe_element->ToObject(&element)) return maybe_element;
5333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005334 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5335 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5336 break;
5337 }
5338
lrn@chromium.org303ada72010-10-27 09:33:13 +00005339 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005343 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 }
5345
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346 Object* object = NULL;
5347 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005348 String* result = String::cast(object);
5349 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005350 Object* element;
5351 { MaybeObject* maybe_element = codes->GetElement(i);
5352 if (!maybe_element->ToObject(&element)) return maybe_element;
5353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005354 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005355 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005356 }
5357 return result;
5358}
5359
5360
5361// kNotEscaped is generated by the following:
5362//
5363// #!/bin/perl
5364// for (my $i = 0; $i < 256; $i++) {
5365// print "\n" if $i % 16 == 0;
5366// my $c = chr($i);
5367// my $escaped = 1;
5368// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5369// print $escaped ? "0, " : "1, ";
5370// }
5371
5372
5373static bool IsNotEscaped(uint16_t character) {
5374 // Only for 8 bit characters, the rest are always escaped (in a different way)
5375 ASSERT(character < 256);
5376 static const char kNotEscaped[256] = {
5377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5383 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5393 };
5394 return kNotEscaped[character] != 0;
5395}
5396
5397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005398RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 const char hex_chars[] = "0123456789ABCDEF";
5400 NoHandleAllocation ha;
5401 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005402 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005404 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405
5406 int escaped_length = 0;
5407 int length = source->length();
5408 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409 Access<StringInputBuffer> buffer(
5410 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 buffer->Reset(source);
5412 while (buffer->has_more()) {
5413 uint16_t character = buffer->GetNext();
5414 if (character >= 256) {
5415 escaped_length += 6;
5416 } else if (IsNotEscaped(character)) {
5417 escaped_length++;
5418 } else {
5419 escaped_length += 3;
5420 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005421 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005422 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005423 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005424 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 return Failure::OutOfMemoryException();
5426 }
5427 }
5428 }
5429 // No length change implies no change. Return original string if no change.
5430 if (escaped_length == length) {
5431 return source;
5432 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005433 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 { MaybeObject* maybe_o =
5435 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005436 if (!maybe_o->ToObject(&o)) return maybe_o;
5437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005438 String* destination = String::cast(o);
5439 int dest_position = 0;
5440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005441 Access<StringInputBuffer> buffer(
5442 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443 buffer->Rewind();
5444 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005445 uint16_t chr = buffer->GetNext();
5446 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005447 destination->Set(dest_position, '%');
5448 destination->Set(dest_position+1, 'u');
5449 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5450 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5451 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5452 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005454 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005455 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 dest_position++;
5457 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 destination->Set(dest_position, '%');
5459 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5460 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 dest_position += 3;
5462 }
5463 }
5464 return destination;
5465}
5466
5467
5468static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5469 static const signed char kHexValue['g'] = {
5470 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5472 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5473 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5474 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5475 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5476 -1, 10, 11, 12, 13, 14, 15 };
5477
5478 if (character1 > 'f') return -1;
5479 int hi = kHexValue[character1];
5480 if (hi == -1) return -1;
5481 if (character2 > 'f') return -1;
5482 int lo = kHexValue[character2];
5483 if (lo == -1) return -1;
5484 return (hi << 4) + lo;
5485}
5486
5487
ager@chromium.org870a0b62008-11-04 11:43:05 +00005488static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 int i,
5490 int length,
5491 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005492 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005493 int32_t hi = 0;
5494 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 if (character == '%' &&
5496 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005497 source->Get(i + 1) == 'u' &&
5498 (hi = TwoDigitHex(source->Get(i + 2),
5499 source->Get(i + 3))) != -1 &&
5500 (lo = TwoDigitHex(source->Get(i + 4),
5501 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 *step = 6;
5503 return (hi << 8) + lo;
5504 } else if (character == '%' &&
5505 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 (lo = TwoDigitHex(source->Get(i + 1),
5507 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 *step = 3;
5509 return lo;
5510 } else {
5511 *step = 1;
5512 return character;
5513 }
5514}
5515
5516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005517RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 NoHandleAllocation ha;
5519 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005520 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005522 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
5524 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005525 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526
5527 int unescaped_length = 0;
5528 for (int i = 0; i < length; unescaped_length++) {
5529 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005530 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005533 i += step;
5534 }
5535
5536 // No length change implies no change. Return original string if no change.
5537 if (unescaped_length == length)
5538 return source;
5539
lrn@chromium.org303ada72010-10-27 09:33:13 +00005540 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005541 { MaybeObject* maybe_o =
5542 ascii ?
5543 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5544 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005545 if (!maybe_o->ToObject(&o)) return maybe_o;
5546 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005547 String* destination = String::cast(o);
5548
5549 int dest_position = 0;
5550 for (int i = 0; i < length; dest_position++) {
5551 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005552 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553 i += step;
5554 }
5555 return destination;
5556}
5557
5558
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005559static const unsigned int kQuoteTableLength = 128u;
5560
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005561static const int kJsonQuotesCharactersPerEntry = 8;
5562static const char* const JsonQuotes =
5563 "\\u0000 \\u0001 \\u0002 \\u0003 "
5564 "\\u0004 \\u0005 \\u0006 \\u0007 "
5565 "\\b \\t \\n \\u000b "
5566 "\\f \\r \\u000e \\u000f "
5567 "\\u0010 \\u0011 \\u0012 \\u0013 "
5568 "\\u0014 \\u0015 \\u0016 \\u0017 "
5569 "\\u0018 \\u0019 \\u001a \\u001b "
5570 "\\u001c \\u001d \\u001e \\u001f "
5571 " ! \\\" # "
5572 "$ % & ' "
5573 "( ) * + "
5574 ", - . / "
5575 "0 1 2 3 "
5576 "4 5 6 7 "
5577 "8 9 : ; "
5578 "< = > ? "
5579 "@ A B C "
5580 "D E F G "
5581 "H I J K "
5582 "L M N O "
5583 "P Q R S "
5584 "T U V W "
5585 "X Y Z [ "
5586 "\\\\ ] ^ _ "
5587 "` a b c "
5588 "d e f g "
5589 "h i j k "
5590 "l m n o "
5591 "p q r s "
5592 "t u v w "
5593 "x y z { "
5594 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005595
5596
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597// For a string that is less than 32k characters it should always be
5598// possible to allocate it in new space.
5599static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5600
5601
5602// Doing JSON quoting cannot make the string more than this many times larger.
5603static const int kJsonQuoteWorstCaseBlowup = 6;
5604
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005605static const int kSpaceForQuotesAndComma = 3;
5606static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005607
5608// Covers the entire ASCII range (all other characters are unchanged by JSON
5609// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005610static const byte JsonQuoteLengths[kQuoteTableLength] = {
5611 6, 6, 6, 6, 6, 6, 6, 6,
5612 2, 2, 2, 6, 2, 2, 6, 6,
5613 6, 6, 6, 6, 6, 6, 6, 6,
5614 6, 6, 6, 6, 6, 6, 6, 6,
5615 1, 1, 2, 1, 1, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 1, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 2, 1, 1, 1,
5623 1, 1, 1, 1, 1, 1, 1, 1,
5624 1, 1, 1, 1, 1, 1, 1, 1,
5625 1, 1, 1, 1, 1, 1, 1, 1,
5626 1, 1, 1, 1, 1, 1, 1, 1,
5627};
5628
5629
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005632
5633
5634template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5636 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637}
5638
5639
5640template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005641MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5642 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005643}
5644
5645
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005646template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5648 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005649 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005650 const Char* read_cursor = characters.start();
5651 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005652 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005653 int quoted_length = kSpaceForQuotes;
5654 while (read_cursor < end) {
5655 Char c = *(read_cursor++);
5656 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5657 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005658 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005659 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660 }
5661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005662 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5663 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664 Object* new_object;
5665 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005666 return new_alloc;
5667 }
5668 StringType* new_string = StringType::cast(new_object);
5669
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005670 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005671 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005672 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005673 *(write_cursor++) = '"';
5674
5675 read_cursor = characters.start();
5676 while (read_cursor < end) {
5677 Char c = *(read_cursor++);
5678 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5679 *(write_cursor++) = c;
5680 } else {
5681 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5682 const char* replacement = JsonQuotes +
5683 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5684 for (int i = 0; i < len; i++) {
5685 *write_cursor++ = *replacement++;
5686 }
5687 }
5688 }
5689 *(write_cursor++) = '"';
5690 return new_string;
5691}
5692
5693
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005694template <typename SinkChar, typename SourceChar>
5695static inline SinkChar* WriteQuoteJsonString(
5696 Isolate* isolate,
5697 SinkChar* write_cursor,
5698 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005699 // SinkChar is only char if SourceChar is guaranteed to be char.
5700 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005701 const SourceChar* read_cursor = characters.start();
5702 const SourceChar* end = read_cursor + characters.length();
5703 *(write_cursor++) = '"';
5704 while (read_cursor < end) {
5705 SourceChar c = *(read_cursor++);
5706 if (sizeof(SourceChar) > 1u &&
5707 static_cast<unsigned>(c) >= kQuoteTableLength) {
5708 *(write_cursor++) = static_cast<SinkChar>(c);
5709 } else {
5710 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5711 const char* replacement = JsonQuotes +
5712 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5713 write_cursor[0] = replacement[0];
5714 if (len > 1) {
5715 write_cursor[1] = replacement[1];
5716 if (len > 2) {
5717 ASSERT(len == 6);
5718 write_cursor[2] = replacement[2];
5719 write_cursor[3] = replacement[3];
5720 write_cursor[4] = replacement[4];
5721 write_cursor[5] = replacement[5];
5722 }
5723 }
5724 write_cursor += len;
5725 }
5726 }
5727 *(write_cursor++) = '"';
5728 return write_cursor;
5729}
5730
5731
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005732template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733static MaybeObject* QuoteJsonString(Isolate* isolate,
5734 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005737 int worst_case_length =
5738 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005740 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005741 }
5742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005743 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5744 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005745 Object* new_object;
5746 if (!new_alloc->ToObject(&new_object)) {
5747 return new_alloc;
5748 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005749 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005750 // Even if our string is small enough to fit in new space we still have to
5751 // handle it being allocated in old space as may happen in the third
5752 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5753 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005755 }
5756 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005757 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005758
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005759 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005760 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005761 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005762 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5763 write_cursor,
5764 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005765 int final_length = static_cast<int>(
5766 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005767 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005768 isolate->heap()->new_space()->
5769 template ShrinkStringAtAllocationBoundary<StringType>(
5770 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005771 return new_string;
5772}
5773
5774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005775RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005776 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005777 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005778 if (!str->IsFlat()) {
5779 MaybeObject* try_flatten = str->TryFlatten();
5780 Object* flat;
5781 if (!try_flatten->ToObject(&flat)) {
5782 return try_flatten;
5783 }
5784 str = String::cast(flat);
5785 ASSERT(str->IsFlat());
5786 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 String::FlatContent flat = str->GetFlatContent();
5788 ASSERT(flat.IsFlat());
5789 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005791 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005792 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005794 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 }
5796}
5797
5798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005799RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005800 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005801 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005802 if (!str->IsFlat()) {
5803 MaybeObject* try_flatten = str->TryFlatten();
5804 Object* flat;
5805 if (!try_flatten->ToObject(&flat)) {
5806 return try_flatten;
5807 }
5808 str = String::cast(flat);
5809 ASSERT(str->IsFlat());
5810 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005811 String::FlatContent flat = str->GetFlatContent();
5812 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005814 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005815 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005817 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005818 }
5819}
5820
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005821
5822template <typename Char, typename StringType>
5823static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5824 FixedArray* array,
5825 int worst_case_length) {
5826 int length = array->length();
5827
5828 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5829 worst_case_length);
5830 Object* new_object;
5831 if (!new_alloc->ToObject(&new_object)) {
5832 return new_alloc;
5833 }
5834 if (!isolate->heap()->new_space()->Contains(new_object)) {
5835 // Even if our string is small enough to fit in new space we still have to
5836 // handle it being allocated in old space as may happen in the third
5837 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5838 // CEntryStub::GenerateCore.
5839 return isolate->heap()->undefined_value();
5840 }
5841 AssertNoAllocation no_gc;
5842 StringType* new_string = StringType::cast(new_object);
5843 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5844
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005845 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005846 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005847 *(write_cursor++) = '[';
5848 for (int i = 0; i < length; i++) {
5849 if (i != 0) *(write_cursor++) = ',';
5850 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005851 String::FlatContent content = str->GetFlatContent();
5852 ASSERT(content.IsFlat());
5853 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005854 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5855 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005856 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 } else {
5858 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5859 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005860 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005861 }
5862 }
5863 *(write_cursor++) = ']';
5864
5865 int final_length = static_cast<int>(
5866 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005867 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005868 isolate->heap()->new_space()->
5869 template ShrinkStringAtAllocationBoundary<StringType>(
5870 new_string, final_length);
5871 return new_string;
5872}
5873
5874
5875RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005878 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005879
5880 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5881 FixedArray* elements = FixedArray::cast(array->elements());
5882 int n = elements->length();
5883 bool ascii = true;
5884 int total_length = 0;
5885
5886 for (int i = 0; i < n; i++) {
5887 Object* elt = elements->get(i);
5888 if (!elt->IsString()) return isolate->heap()->undefined_value();
5889 String* element = String::cast(elt);
5890 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5891 total_length += element->length();
5892 if (ascii && element->IsTwoByteRepresentation()) {
5893 ascii = false;
5894 }
5895 }
5896
5897 int worst_case_length =
5898 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5899 + total_length * kJsonQuoteWorstCaseBlowup;
5900
5901 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5902 return isolate->heap()->undefined_value();
5903 }
5904
5905 if (ascii) {
5906 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5907 elements,
5908 worst_case_length);
5909 } else {
5910 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5911 elements,
5912 worst_case_length);
5913 }
5914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005920 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005921 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005923 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
lrn@chromium.org25156de2010-04-06 13:10:27 +00005925 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005926 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005927 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928}
5929
5930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005931RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005933 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005936 double value = StringToDouble(isolate->unicode_cache(),
5937 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
5939 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941}
5942
5943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005945MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005947 String* s,
5948 int length,
5949 int input_string_length,
5950 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005951 // We try this twice, once with the assumption that the result is no longer
5952 // than the input and, if that assumption breaks, again with the exact
5953 // length. This may not be pretty, but it is nicer than what was here before
5954 // and I hereby claim my vaffel-is.
5955 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 // Allocate the resulting string.
5957 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005958 // NOTE: This assumes that the upper/lower case of an ASCII
5959 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 // might break in the future if we implement more context and locale
5961 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962 Object* o;
5963 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005964 ? isolate->heap()->AllocateRawAsciiString(length)
5965 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005966 if (!maybe_o->ToObject(&o)) return maybe_o;
5967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 String* result = String::cast(o);
5969 bool has_changed_character = false;
5970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 // Convert all characters to upper case, assuming that they will fit
5972 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005973 Access<StringInputBuffer> buffer(
5974 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005976 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977 // We can assume that the string is not empty
5978 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005979 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005980 bool has_next = buffer->has_more();
5981 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 int char_length = mapping->get(current, next, chars);
5983 if (char_length == 0) {
5984 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005985 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 i++;
5987 } else if (char_length == 1) {
5988 // Common case: converting the letter resulted in one character.
5989 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005990 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 has_changed_character = true;
5992 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 // We've assumed that the result would be as long as the
5995 // input but here is a character that converts to several
5996 // characters. No matter, we calculate the exact length
5997 // of the result and try the whole thing again.
5998 //
5999 // Note that this leaves room for optimization. We could just
6000 // memcpy what we already have to the result string. Also,
6001 // the result string is the last object allocated we could
6002 // "realloc" it and probably, in the vast majority of cases,
6003 // extend the existing string to be able to hold the full
6004 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006005 int next_length = 0;
6006 if (has_next) {
6007 next_length = mapping->get(next, 0, chars);
6008 if (next_length == 0) next_length = 1;
6009 }
6010 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 while (buffer->has_more()) {
6012 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006013 // NOTE: we use 0 as the next character here because, while
6014 // the next character may affect what a character converts to,
6015 // it does not in any case affect the length of what it convert
6016 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 int char_length = mapping->get(current, 0, chars);
6018 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006019 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006020 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006022 return Failure::OutOfMemoryException();
6023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 // Try again with the real length.
6026 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 } else {
6028 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 i++;
6031 }
6032 has_changed_character = true;
6033 }
6034 current = next;
6035 }
6036 if (has_changed_character) {
6037 return result;
6038 } else {
6039 // If we didn't actually change anything in doing the conversion
6040 // we simple return the result and let the converted string
6041 // become garbage; there is no reason to keep two identical strings
6042 // alive.
6043 return s;
6044 }
6045}
6046
6047
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006048namespace {
6049
lrn@chromium.org303ada72010-10-27 09:33:13 +00006050static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6051
6052
6053// Given a word and two range boundaries returns a word with high bit
6054// set in every byte iff the corresponding input byte was strictly in
6055// the range (m, n). All the other bits in the result are cleared.
6056// This function is only useful when it can be inlined and the
6057// boundaries are statically known.
6058// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006059// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006060static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006061 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006062 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6063 // Use strict inequalities since in edge cases the function could be
6064 // further simplified.
6065 ASSERT(0 < m && m < n && n < 0x7F);
6066 // Has high bit set in every w byte less than n.
6067 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6068 // Has high bit set in every w byte greater than m.
6069 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6070 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6071}
6072
6073
6074enum AsciiCaseConversion {
6075 ASCII_TO_LOWER,
6076 ASCII_TO_UPPER
6077};
6078
6079
6080template <AsciiCaseConversion dir>
6081struct FastAsciiConverter {
6082 static bool Convert(char* dst, char* src, int length) {
6083#ifdef DEBUG
6084 char* saved_dst = dst;
6085 char* saved_src = src;
6086#endif
6087 // We rely on the distance between upper and lower case letters
6088 // being a known power of 2.
6089 ASSERT('a' - 'A' == (1 << 5));
6090 // Boundaries for the range of input characters than require conversion.
6091 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6092 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6093 bool changed = false;
6094 char* const limit = src + length;
6095#ifdef V8_HOST_CAN_READ_UNALIGNED
6096 // Process the prefix of the input that requires no conversion one
6097 // (machine) word at a time.
6098 while (src <= limit - sizeof(uintptr_t)) {
6099 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6100 if (AsciiRangeMask(w, lo, hi) != 0) {
6101 changed = true;
6102 break;
6103 }
6104 *reinterpret_cast<uintptr_t*>(dst) = w;
6105 src += sizeof(uintptr_t);
6106 dst += sizeof(uintptr_t);
6107 }
6108 // Process the remainder of the input performing conversion when
6109 // required one word at a time.
6110 while (src <= limit - sizeof(uintptr_t)) {
6111 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6112 uintptr_t m = AsciiRangeMask(w, lo, hi);
6113 // The mask has high (7th) bit set in every byte that needs
6114 // conversion and we know that the distance between cases is
6115 // 1 << 5.
6116 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6117 src += sizeof(uintptr_t);
6118 dst += sizeof(uintptr_t);
6119 }
6120#endif
6121 // Process the last few bytes of the input (or the whole input if
6122 // unaligned access is not supported).
6123 while (src < limit) {
6124 char c = *src;
6125 if (lo < c && c < hi) {
6126 c ^= (1 << 5);
6127 changed = true;
6128 }
6129 *dst = c;
6130 ++src;
6131 ++dst;
6132 }
6133#ifdef DEBUG
6134 CheckConvert(saved_dst, saved_src, length, changed);
6135#endif
6136 return changed;
6137 }
6138
6139#ifdef DEBUG
6140 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6141 bool expected_changed = false;
6142 for (int i = 0; i < length; i++) {
6143 if (dst[i] == src[i]) continue;
6144 expected_changed = true;
6145 if (dir == ASCII_TO_LOWER) {
6146 ASSERT('A' <= src[i] && src[i] <= 'Z');
6147 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6148 } else {
6149 ASSERT(dir == ASCII_TO_UPPER);
6150 ASSERT('a' <= src[i] && src[i] <= 'z');
6151 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6152 }
6153 }
6154 ASSERT(expected_changed == changed);
6155 }
6156#endif
6157};
6158
6159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160struct ToLowerTraits {
6161 typedef unibrow::ToLowercase UnibrowConverter;
6162
lrn@chromium.org303ada72010-10-27 09:33:13 +00006163 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164};
6165
6166
6167struct ToUpperTraits {
6168 typedef unibrow::ToUppercase UnibrowConverter;
6169
lrn@chromium.org303ada72010-10-27 09:33:13 +00006170 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171};
6172
6173} // namespace
6174
6175
6176template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006178 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006180 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006181 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006182 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006183 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006184
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006185 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006186 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 if (length == 0) return s;
6188
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006189 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006190 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006191 // NOTE: This assumes that the upper/lower case of an ASCII
6192 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006193 // might break in the future if we implement more context and locale
6194 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006195 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006196 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006197 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006198 if (!maybe_o->ToObject(&o)) return maybe_o;
6199 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006201 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006202 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006203 return has_changed_character ? result : s;
6204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006205
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 { MaybeObject* maybe_answer =
6208 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6210 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006211 if (answer->IsSmi()) {
6212 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006214 ConvertCaseHelper(isolate,
6215 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006216 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6217 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006224 return ConvertCase<ToLowerTraits>(
6225 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006226}
6227
6228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006229RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230 return ConvertCase<ToUpperTraits>(
6231 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232}
6233
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006235static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006236 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237}
6238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006241 NoHandleAllocation ha;
6242 ASSERT(args.length() == 3);
6243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006244 CONVERT_ARG_CHECKED(String, s, 0);
6245 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6246 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006247
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006248 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006249 int length = s->length();
6250
6251 int left = 0;
6252 if (trimLeft) {
6253 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6254 left++;
6255 }
6256 }
6257
6258 int right = length;
6259 if (trimRight) {
6260 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6261 right--;
6262 }
6263 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006264 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006265}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006268RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006270 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006271 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6272 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006273 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6274
6275 int subject_length = subject->length();
6276 int pattern_length = pattern->length();
6277 RUNTIME_ASSERT(pattern_length > 0);
6278
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006279 if (limit == 0xffffffffu) {
6280 Handle<Object> cached_answer(StringSplitCache::Lookup(
6281 isolate->heap()->string_split_cache(),
6282 *subject,
6283 *pattern));
6284 if (*cached_answer != Smi::FromInt(0)) {
6285 Handle<JSArray> result =
6286 isolate->factory()->NewJSArrayWithElements(
6287 Handle<FixedArray>::cast(cached_answer));
6288 return *result;
6289 }
6290 }
6291
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006292 // The limit can be very large (0xffffffffu), but since the pattern
6293 // isn't empty, we can never create more parts than ~half the length
6294 // of the subject.
6295
6296 if (!subject->IsFlat()) FlattenString(subject);
6297
6298 static const int kMaxInitialListCapacity = 16;
6299
danno@chromium.org40cb8782011-05-25 07:58:50 +00006300 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006301
6302 // Find (up to limit) indices of separator and end-of-string in subject
6303 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6304 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006305 if (!pattern->IsFlat()) FlattenString(pattern);
6306
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006307 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006308
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006309 if (static_cast<uint32_t>(indices.length()) < limit) {
6310 indices.Add(subject_length);
6311 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006312
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006313 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006314
6315 // Create JSArray of substrings separated by separator.
6316 int part_count = indices.length();
6317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006319 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006320 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 result->set_length(Smi::FromInt(part_count));
6322
6323 ASSERT(result->HasFastElements());
6324
6325 if (part_count == 1 && indices.at(0) == subject_length) {
6326 FixedArray::cast(result->elements())->set(0, *subject);
6327 return *result;
6328 }
6329
6330 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6331 int part_start = 0;
6332 for (int i = 0; i < part_count; i++) {
6333 HandleScope local_loop_handle;
6334 int part_end = indices.at(i);
6335 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006336 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006337 elements->set(i, *substring);
6338 part_start = part_end + pattern_length;
6339 }
6340
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006341 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006342 if (result->HasFastElements()) {
6343 StringSplitCache::Enter(isolate->heap(),
6344 isolate->heap()->string_split_cache(),
6345 *subject,
6346 *pattern,
6347 *elements);
6348 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006349 }
6350
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006351 return *result;
6352}
6353
6354
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006355// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006356// one-char strings in the cache. Gives up on the first char that is
6357// not in the cache and fills the remainder with smi zeros. Returns
6358// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359static int CopyCachedAsciiCharsToArray(Heap* heap,
6360 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006361 FixedArray* elements,
6362 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006363 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006364 FixedArray* ascii_cache = heap->single_character_string_cache();
6365 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006366 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006367 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368 for (i = 0; i < length; ++i) {
6369 Object* value = ascii_cache->get(chars[i]);
6370 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006371 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 }
6373 if (i < length) {
6374 ASSERT(Smi::FromInt(0) == 0);
6375 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6376 }
6377#ifdef DEBUG
6378 for (int j = 0; j < length; ++j) {
6379 Object* element = elements->get(j);
6380 ASSERT(element == Smi::FromInt(0) ||
6381 (element->IsString() && String::cast(element)->LooksValid()));
6382 }
6383#endif
6384 return i;
6385}
6386
6387
6388// Converts a String to JSArray.
6389// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006390RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006391 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006392 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006393 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006394 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006395
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006397 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006398
6399 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006400 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006402 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006403 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 { MaybeObject* maybe_obj =
6405 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006406 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006409 String::FlatContent content = s->GetFlatContent();
6410 if (content.IsAscii()) {
6411 Vector<const char> chars = content.ToAsciiVector();
6412 // Note, this will initialize all elements (not only the prefix)
6413 // to prevent GC from seeing partially initialized array.
6414 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6415 chars.start(),
6416 *elements,
6417 length);
6418 } else {
6419 MemsetPointer(elements->data_start(),
6420 isolate->heap()->undefined_value(),
6421 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422 }
6423 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006424 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006425 }
6426 for (int i = position; i < length; ++i) {
6427 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6428 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006429 }
6430
6431#ifdef DEBUG
6432 for (int i = 0; i < length; ++i) {
6433 ASSERT(String::cast(elements->get(i))->length() == 1);
6434 }
6435#endif
6436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006438}
6439
6440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006441RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006442 NoHandleAllocation ha;
6443 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006444 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006445 return value->ToObject();
6446}
6447
6448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006450 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006451 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006452 return char_length == 0;
6453}
6454
6455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006456RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 NoHandleAllocation ha;
6458 ASSERT(args.length() == 1);
6459
6460 Object* number = args[0];
6461 RUNTIME_ASSERT(number->IsNumber());
6462
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464}
6465
6466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006467RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006468 NoHandleAllocation ha;
6469 ASSERT(args.length() == 1);
6470
6471 Object* number = args[0];
6472 RUNTIME_ASSERT(number->IsNumber());
6473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006475}
6476
6477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006478RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479 NoHandleAllocation ha;
6480 ASSERT(args.length() == 1);
6481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006482 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006483
6484 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6485 if (number > 0 && number <= Smi::kMaxValue) {
6486 return Smi::FromInt(static_cast<int>(number));
6487 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006496 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006497
6498 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6499 if (number > 0 && number <= Smi::kMaxValue) {
6500 return Smi::FromInt(static_cast<int>(number));
6501 }
6502
6503 double double_value = DoubleToInteger(number);
6504 // Map both -0 and +0 to +0.
6505 if (double_value == 0) double_value = 0;
6506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006508}
6509
6510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006511RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512 NoHandleAllocation ha;
6513 ASSERT(args.length() == 1);
6514
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006515 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006516 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517}
6518
6519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 NoHandleAllocation ha;
6522 ASSERT(args.length() == 1);
6523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006524 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006525
6526 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6527 if (number > 0 && number <= Smi::kMaxValue) {
6528 return Smi::FromInt(static_cast<int>(number));
6529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531}
6532
6533
ager@chromium.org870a0b62008-11-04 11:43:05 +00006534// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6535// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
6539
6540 Object* obj = args[0];
6541 if (obj->IsSmi()) {
6542 return obj;
6543 }
6544 if (obj->IsHeapNumber()) {
6545 double value = HeapNumber::cast(obj)->value();
6546 int int_value = FastD2I(value);
6547 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6548 return Smi::FromInt(int_value);
6549 }
6550 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006552}
6553
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006555RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006556 NoHandleAllocation ha;
6557 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 2);
6565
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006566 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6567 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 2);
6575
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006576 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6577 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 2);
6585
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006586 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6587 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
6594 ASSERT(args.length() == 1);
6595
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006596 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598}
6599
6600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006601RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006602 NoHandleAllocation ha;
6603 ASSERT(args.length() == 0);
6604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006606}
6607
6608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 2);
6612
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006613 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6614 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006619RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 NoHandleAllocation ha;
6621 ASSERT(args.length() == 2);
6622
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006623 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6624 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625
ager@chromium.org3811b432009-10-28 14:53:37 +00006626 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006627 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629}
6630
6631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006632RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633 NoHandleAllocation ha;
6634 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006635 CONVERT_ARG_CHECKED(String, str1, 0);
6636 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006637 isolate->counters()->string_add_runtime()->Increment();
6638 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006639}
6640
6641
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006642template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006643static inline void StringBuilderConcatHelper(String* special,
6644 sinkchar* sink,
6645 FixedArray* fixed_array,
6646 int array_length) {
6647 int position = 0;
6648 for (int i = 0; i < array_length; i++) {
6649 Object* element = fixed_array->get(i);
6650 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006651 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006652 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006653 int pos;
6654 int len;
6655 if (encoded_slice > 0) {
6656 // Position and length encoded in one smi.
6657 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6658 len = StringBuilderSubstringLength::decode(encoded_slice);
6659 } else {
6660 // Position and length encoded in two smis.
6661 Object* obj = fixed_array->get(++i);
6662 ASSERT(obj->IsSmi());
6663 pos = Smi::cast(obj)->value();
6664 len = -encoded_slice;
6665 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006666 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006667 sink + position,
6668 pos,
6669 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006670 position += len;
6671 } else {
6672 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006673 int element_length = string->length();
6674 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006675 position += element_length;
6676 }
6677 }
6678}
6679
6680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006681RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006684 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006685 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006687 return Failure::OutOfMemoryException();
6688 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006689 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006690 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006691
6692 // This assumption is used by the slice encoding in one or two smis.
6693 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6694
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006695 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006696 if (maybe_result->IsFailure()) return maybe_result;
6697
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006698 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006700 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 }
6702 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006703 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006706
6707 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 } else if (array_length == 1) {
6710 Object* first = fixed_array->get(0);
6711 if (first->IsString()) return first;
6712 }
6713
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006714 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715 int position = 0;
6716 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 Object* elt = fixed_array->get(i);
6719 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006720 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006721 int smi_value = Smi::cast(elt)->value();
6722 int pos;
6723 int len;
6724 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006725 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 pos = StringBuilderSubstringPosition::decode(smi_value);
6727 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 } else {
6729 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006730 len = -smi_value;
6731 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006732 i++;
6733 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006735 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006736 Object* next_smi = fixed_array->get(i);
6737 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006739 }
6740 pos = Smi::cast(next_smi)->value();
6741 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006745 ASSERT(pos >= 0);
6746 ASSERT(len >= 0);
6747 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006748 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006749 }
6750 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 } else if (elt->IsString()) {
6752 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006753 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006754 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006755 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006759 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006760 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006762 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006764 return Failure::OutOfMemoryException();
6765 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006766 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 }
6768
6769 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 { MaybeObject* maybe_object =
6774 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006775 if (!maybe_object->ToObject(&object)) return maybe_object;
6776 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006777 SeqAsciiString* answer = SeqAsciiString::cast(object);
6778 StringBuilderConcatHelper(special,
6779 answer->GetChars(),
6780 fixed_array,
6781 array_length);
6782 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 { MaybeObject* maybe_object =
6785 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006786 if (!maybe_object->ToObject(&object)) return maybe_object;
6787 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006788 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6789 StringBuilderConcatHelper(special,
6790 answer->GetChars(),
6791 fixed_array,
6792 array_length);
6793 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795}
6796
6797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006798RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 NoHandleAllocation ha;
6800 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006801 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804 return Failure::OutOfMemoryException();
6805 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006806 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006807 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006808
6809 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811 }
6812 FixedArray* fixed_array = FixedArray::cast(array->elements());
6813 if (fixed_array->length() < array_length) {
6814 array_length = fixed_array->length();
6815 }
6816
6817 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006819 } else if (array_length == 1) {
6820 Object* first = fixed_array->get(0);
6821 if (first->IsString()) return first;
6822 }
6823
6824 int separator_length = separator->length();
6825 int max_nof_separators =
6826 (String::kMaxLength + separator_length - 1) / separator_length;
6827 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006828 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006829 return Failure::OutOfMemoryException();
6830 }
6831 int length = (array_length - 1) * separator_length;
6832 for (int i = 0; i < array_length; i++) {
6833 Object* element_obj = fixed_array->get(i);
6834 if (!element_obj->IsString()) {
6835 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006837 }
6838 String* element = String::cast(element_obj);
6839 int increment = element->length();
6840 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006841 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 return Failure::OutOfMemoryException();
6843 }
6844 length += increment;
6845 }
6846
6847 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006848 { MaybeObject* maybe_object =
6849 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006850 if (!maybe_object->ToObject(&object)) return maybe_object;
6851 }
6852 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6853
6854 uc16* sink = answer->GetChars();
6855#ifdef DEBUG
6856 uc16* end = sink + length;
6857#endif
6858
6859 String* first = String::cast(fixed_array->get(0));
6860 int first_length = first->length();
6861 String::WriteToFlat(first, sink, 0, first_length);
6862 sink += first_length;
6863
6864 for (int i = 1; i < array_length; i++) {
6865 ASSERT(sink + separator_length <= end);
6866 String::WriteToFlat(separator, sink, 0, separator_length);
6867 sink += separator_length;
6868
6869 String* element = String::cast(fixed_array->get(i));
6870 int element_length = element->length();
6871 ASSERT(sink + element_length <= end);
6872 String::WriteToFlat(element, sink, 0, element_length);
6873 sink += element_length;
6874 }
6875 ASSERT(sink == end);
6876
6877 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6878 return answer;
6879}
6880
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006881template <typename Char>
6882static void JoinSparseArrayWithSeparator(FixedArray* elements,
6883 int elements_length,
6884 uint32_t array_length,
6885 String* separator,
6886 Vector<Char> buffer) {
6887 int previous_separator_position = 0;
6888 int separator_length = separator->length();
6889 int cursor = 0;
6890 for (int i = 0; i < elements_length; i += 2) {
6891 int position = NumberToInt32(elements->get(i));
6892 String* string = String::cast(elements->get(i + 1));
6893 int string_length = string->length();
6894 if (string->length() > 0) {
6895 while (previous_separator_position < position) {
6896 String::WriteToFlat<Char>(separator, &buffer[cursor],
6897 0, separator_length);
6898 cursor += separator_length;
6899 previous_separator_position++;
6900 }
6901 String::WriteToFlat<Char>(string, &buffer[cursor],
6902 0, string_length);
6903 cursor += string->length();
6904 }
6905 }
6906 if (separator_length > 0) {
6907 // Array length must be representable as a signed 32-bit number,
6908 // otherwise the total string length would have been too large.
6909 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6910 int last_array_index = static_cast<int>(array_length - 1);
6911 while (previous_separator_position < last_array_index) {
6912 String::WriteToFlat<Char>(separator, &buffer[cursor],
6913 0, separator_length);
6914 cursor += separator_length;
6915 previous_separator_position++;
6916 }
6917 }
6918 ASSERT(cursor <= buffer.length());
6919}
6920
6921
6922RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6923 NoHandleAllocation ha;
6924 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006925 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006926 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6927 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006928 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006929 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006930 // elements_array is fast-mode JSarray of alternating positions
6931 // (increasing order) and strings.
6932 // array_length is length of original array (used to add separators);
6933 // separator is string to put between elements. Assumed to be non-empty.
6934
6935 // Find total length of join result.
6936 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006937 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006938 int max_string_length;
6939 if (is_ascii) {
6940 max_string_length = SeqAsciiString::kMaxLength;
6941 } else {
6942 max_string_length = SeqTwoByteString::kMaxLength;
6943 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006944 bool overflow = false;
6945 CONVERT_NUMBER_CHECKED(int, elements_length,
6946 Int32, elements_array->length());
6947 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6948 FixedArray* elements = FixedArray::cast(elements_array->elements());
6949 for (int i = 0; i < elements_length; i += 2) {
6950 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006951 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6952 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006953 int length = string->length();
6954 if (is_ascii && !string->IsAsciiRepresentation()) {
6955 is_ascii = false;
6956 max_string_length = SeqTwoByteString::kMaxLength;
6957 }
6958 if (length > max_string_length ||
6959 max_string_length - length < string_length) {
6960 overflow = true;
6961 break;
6962 }
6963 string_length += length;
6964 }
6965 int separator_length = separator->length();
6966 if (!overflow && separator_length > 0) {
6967 if (array_length <= 0x7fffffffu) {
6968 int separator_count = static_cast<int>(array_length) - 1;
6969 int remaining_length = max_string_length - string_length;
6970 if ((remaining_length / separator_length) >= separator_count) {
6971 string_length += separator_length * (array_length - 1);
6972 } else {
6973 // Not room for the separators within the maximal string length.
6974 overflow = true;
6975 }
6976 } else {
6977 // Nonempty separator and at least 2^31-1 separators necessary
6978 // means that the string is too large to create.
6979 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6980 overflow = true;
6981 }
6982 }
6983 if (overflow) {
6984 // Throw OutOfMemory exception for creating too large a string.
6985 V8::FatalProcessOutOfMemory("Array join result too large.");
6986 }
6987
6988 if (is_ascii) {
6989 MaybeObject* result_allocation =
6990 isolate->heap()->AllocateRawAsciiString(string_length);
6991 if (result_allocation->IsFailure()) return result_allocation;
6992 SeqAsciiString* result_string =
6993 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6994 JoinSparseArrayWithSeparator<char>(elements,
6995 elements_length,
6996 array_length,
6997 separator,
6998 Vector<char>(result_string->GetChars(),
6999 string_length));
7000 return result_string;
7001 } else {
7002 MaybeObject* result_allocation =
7003 isolate->heap()->AllocateRawTwoByteString(string_length);
7004 if (result_allocation->IsFailure()) return result_allocation;
7005 SeqTwoByteString* result_string =
7006 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7007 JoinSparseArrayWithSeparator<uc16>(elements,
7008 elements_length,
7009 array_length,
7010 separator,
7011 Vector<uc16>(result_string->GetChars(),
7012 string_length));
7013 return result_string;
7014 }
7015}
7016
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 2);
7021
7022 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7023 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 NoHandleAllocation ha;
7030 ASSERT(args.length() == 2);
7031
7032 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7033 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007034 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007038RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 2);
7041
7042 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7043 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 1);
7051
7052 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 2);
7060
7061 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7062 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7072 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 2);
7080
7081 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7082 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007083 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084}
7085
7086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088 NoHandleAllocation ha;
7089 ASSERT(args.length() == 2);
7090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007091 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7092 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7094 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7095 if (x == y) return Smi::FromInt(EQUAL);
7096 Object* result;
7097 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7098 result = Smi::FromInt(EQUAL);
7099 } else {
7100 result = Smi::FromInt(NOT_EQUAL);
7101 }
7102 return result;
7103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 2);
7109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007110 CONVERT_ARG_CHECKED(String, x, 0);
7111 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007113 bool not_equal = !x->Equals(y);
7114 // This is slightly convoluted because the value that signifies
7115 // equality is 0 and inequality is 1 so we have to negate the result
7116 // from String::Equals.
7117 ASSERT(not_equal == 0 || not_equal == 1);
7118 STATIC_CHECK(EQUAL == 0);
7119 STATIC_CHECK(NOT_EQUAL == 1);
7120 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121}
7122
7123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007124RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007125 NoHandleAllocation ha;
7126 ASSERT(args.length() == 3);
7127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7129 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 if (isnan(x) || isnan(y)) return args[2];
7131 if (x == y) return Smi::FromInt(EQUAL);
7132 if (isless(x, y)) return Smi::FromInt(LESS);
7133 return Smi::FromInt(GREATER);
7134}
7135
7136
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137// Compare two Smis as if they were converted to strings and then
7138// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007139RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140 NoHandleAllocation ha;
7141 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007142 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7143 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007144
7145 // If the integers are equal so are the string representations.
7146 if (x_value == y_value) return Smi::FromInt(EQUAL);
7147
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007148 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007149 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007150 if (x_value == 0 || y_value == 0)
7151 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152
ager@chromium.org32912102009-01-16 10:38:43 +00007153 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007154 // smallest because the char code of '-' is less than the char code
7155 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007156
7157 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7158 // architectures using 32-bit Smis.
7159 uint32_t x_scaled = x_value;
7160 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007161 if (x_value < 0 || y_value < 0) {
7162 if (y_value >= 0) return Smi::FromInt(LESS);
7163 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007164 x_scaled = -x_value;
7165 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007166 }
7167
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007168 static const uint32_t kPowersOf10[] = {
7169 1, 10, 100, 1000, 10*1000, 100*1000,
7170 1000*1000, 10*1000*1000, 100*1000*1000,
7171 1000*1000*1000
7172 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007173
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007174 // If the integers have the same number of decimal digits they can be
7175 // compared directly as the numeric order is the same as the
7176 // lexicographic order. If one integer has fewer digits, it is scaled
7177 // by some power of 10 to have the same number of digits as the longer
7178 // integer. If the scaled integers are equal it means the shorter
7179 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7182 int x_log2 = IntegerLog2(x_scaled);
7183 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7184 x_log10 -= x_scaled < kPowersOf10[x_log10];
7185
7186 int y_log2 = IntegerLog2(y_scaled);
7187 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7188 y_log10 -= y_scaled < kPowersOf10[y_log10];
7189
7190 int tie = EQUAL;
7191
7192 if (x_log10 < y_log10) {
7193 // X has fewer digits. We would like to simply scale up X but that
7194 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7195 // be scaled up to 9_000_000_000. So we scale up by the next
7196 // smallest power and scale down Y to drop one digit. It is OK to
7197 // drop one digit from the longer integer since the final digit is
7198 // past the length of the shorter integer.
7199 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7200 y_scaled /= 10;
7201 tie = LESS;
7202 } else if (y_log10 < x_log10) {
7203 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7204 x_scaled /= 10;
7205 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007206 }
7207
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007208 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7209 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7210 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007211}
7212
7213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214static Object* StringInputBufferCompare(RuntimeState* state,
7215 String* x,
7216 String* y) {
7217 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7218 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007219 bufx.Reset(x);
7220 bufy.Reset(y);
7221 while (bufx.has_more() && bufy.has_more()) {
7222 int d = bufx.GetNext() - bufy.GetNext();
7223 if (d < 0) return Smi::FromInt(LESS);
7224 else if (d > 0) return Smi::FromInt(GREATER);
7225 }
7226
7227 // x is (non-trivial) prefix of y:
7228 if (bufy.has_more()) return Smi::FromInt(LESS);
7229 // y is prefix of x:
7230 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7231}
7232
7233
7234static Object* FlatStringCompare(String* x, String* y) {
7235 ASSERT(x->IsFlat());
7236 ASSERT(y->IsFlat());
7237 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7238 int prefix_length = x->length();
7239 if (y->length() < prefix_length) {
7240 prefix_length = y->length();
7241 equal_prefix_result = Smi::FromInt(GREATER);
7242 } else if (y->length() > prefix_length) {
7243 equal_prefix_result = Smi::FromInt(LESS);
7244 }
7245 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007246 String::FlatContent x_content = x->GetFlatContent();
7247 String::FlatContent y_content = y->GetFlatContent();
7248 if (x_content.IsAscii()) {
7249 Vector<const char> x_chars = x_content.ToAsciiVector();
7250 if (y_content.IsAscii()) {
7251 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007252 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007253 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007254 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007255 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7256 }
7257 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007258 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7259 if (y_content.IsAscii()) {
7260 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007261 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7262 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007263 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007264 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7265 }
7266 }
7267 Object* result;
7268 if (r == 0) {
7269 result = equal_prefix_result;
7270 } else {
7271 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7272 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007273 ASSERT(result ==
7274 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007275 return result;
7276}
7277
7278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007279RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280 NoHandleAllocation ha;
7281 ASSERT(args.length() == 2);
7282
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007283 CONVERT_ARG_CHECKED(String, x, 0);
7284 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 // A few fast case tests before we flatten.
7289 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007290 if (y->length() == 0) {
7291 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007292 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 return Smi::FromInt(LESS);
7295 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007296
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007297 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007298 if (d < 0) return Smi::FromInt(LESS);
7299 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300
lrn@chromium.org303ada72010-10-27 09:33:13 +00007301 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007303 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311}
7312
7313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007314RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315 NoHandleAllocation ha;
7316 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007319 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321}
7322
7323
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007324RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 NoHandleAllocation ha;
7326 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007329 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331}
7332
7333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007334RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335 NoHandleAllocation ha;
7336 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007337 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007339 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341}
7342
7343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344static const double kPiDividedBy4 = 0.78539816339744830962;
7345
7346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007347RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 NoHandleAllocation ha;
7349 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007350 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7353 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 double result;
7355 if (isinf(x) && isinf(y)) {
7356 // Make sure that the result in case of two infinite arguments
7357 // is a multiple of Pi / 4. The sign of the result is determined
7358 // by the first argument (x) and the sign of the second argument
7359 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 int multiplier = (x < 0) ? -1 : 1;
7361 if (y < 0) multiplier *= 3;
7362 result = multiplier * kPiDividedBy4;
7363 } else {
7364 result = atan2(x, y);
7365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
7389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391 NoHandleAllocation ha;
7392 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007395 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397}
7398
7399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007400RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401 NoHandleAllocation ha;
7402 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007403 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007405 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407}
7408
7409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007410RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411 NoHandleAllocation ha;
7412 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007413 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007415 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417}
7418
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007419// Slow version of Math.pow. We check for fast paths for special cases.
7420// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007421RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422 NoHandleAllocation ha;
7423 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007426 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007427
7428 // If the second argument is a smi, it is much faster to call the
7429 // custom powi() function than the generic pow().
7430 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007433 }
7434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007435 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007436 int y_int = static_cast<int>(y);
7437 double result;
7438 if (y == y_int) {
7439 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7440 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007441 result = (isinf(x)) ? V8_INFINITY
7442 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007443 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007444 result = (isinf(x)) ? 0
7445 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007446 } else {
7447 result = power_double_double(x, y);
7448 }
7449 if (isnan(result)) return isolate->heap()->nan_value();
7450 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007453// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007454// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007455RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007456 NoHandleAllocation ha;
7457 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007458 isolate->counters()->math_pow()->Increment();
7459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007460 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7461 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007462 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007463 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007465 double result = power_double_double(x, y);
7466 if (isnan(result)) return isolate->heap()->nan_value();
7467 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007468 }
7469}
7470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007472RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473 NoHandleAllocation ha;
7474 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007475 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007477 if (!args[0]->IsHeapNumber()) {
7478 // Must be smi. Return the argument unchanged for all the other types
7479 // to make fuzz-natives test happy.
7480 return args[0];
7481 }
7482
7483 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7484
7485 double value = number->value();
7486 int exponent = number->get_exponent();
7487 int sign = number->get_sign();
7488
danno@chromium.org160a7b02011-04-18 15:51:38 +00007489 if (exponent < -1) {
7490 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7491 if (sign) return isolate->heap()->minus_zero_value();
7492 return Smi::FromInt(0);
7493 }
7494
7495 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7496 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007497 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007498 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007499 return Smi::FromInt(static_cast<int>(value + 0.5));
7500 }
7501
7502 // If the magnitude is big enough, there's no place for fraction part. If we
7503 // try to add 0.5 to this number, 1.0 will be added instead.
7504 if (exponent >= 52) {
7505 return number;
7506 }
7507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007509
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007510 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512}
7513
7514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007515RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 NoHandleAllocation ha;
7517 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007520 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522}
7523
7524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007525RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 NoHandleAllocation ha;
7527 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007529
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007530 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007531 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532}
7533
7534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007535RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007536 NoHandleAllocation ha;
7537 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007540 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007541 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542}
7543
7544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007545RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007546 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007547 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007548
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007549 CONVERT_SMI_ARG_CHECKED(year, 0);
7550 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007552 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007553}
7554
7555
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7557 HandleScope scope(isolate);
7558 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007560 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7561 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7562 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007563
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007564 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007565
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007566 Object* value = NULL;
7567 bool is_value_nan = false;
7568 if (isnan(time)) {
7569 value = isolate->heap()->nan_value();
7570 is_value_nan = true;
7571 } else if (!is_utc &&
7572 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7573 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7574 value = isolate->heap()->nan_value();
7575 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007576 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007577 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7578 if (time < -DateCache::kMaxTimeInMs ||
7579 time > DateCache::kMaxTimeInMs) {
7580 value = isolate->heap()->nan_value();
7581 is_value_nan = true;
7582 } else {
7583 MaybeObject* maybe_result =
7584 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7585 if (!maybe_result->ToObject(&value)) return maybe_result;
7586 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007587 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007588 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007589 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007590}
7591
7592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007593RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007594 HandleScope scope(isolate);
7595 ASSERT(args.length() == 3);
7596
7597 Handle<JSFunction> callee = args.at<JSFunction>(0);
7598 Object** parameters = reinterpret_cast<Object**>(args[1]);
7599 const int argument_count = Smi::cast(args[2])->value();
7600
7601 Handle<JSObject> result =
7602 isolate->factory()->NewArgumentsObject(callee, argument_count);
7603 // Allocate the elements if needed.
7604 int parameter_count = callee->shared()->formal_parameter_count();
7605 if (argument_count > 0) {
7606 if (parameter_count > 0) {
7607 int mapped_count = Min(argument_count, parameter_count);
7608 Handle<FixedArray> parameter_map =
7609 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7610 parameter_map->set_map(
7611 isolate->heap()->non_strict_arguments_elements_map());
7612
7613 Handle<Map> old_map(result->map());
7614 Handle<Map> new_map =
7615 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007616 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007617
7618 result->set_map(*new_map);
7619 result->set_elements(*parameter_map);
7620
7621 // Store the context and the arguments array at the beginning of the
7622 // parameter map.
7623 Handle<Context> context(isolate->context());
7624 Handle<FixedArray> arguments =
7625 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7626 parameter_map->set(0, *context);
7627 parameter_map->set(1, *arguments);
7628
7629 // Loop over the actual parameters backwards.
7630 int index = argument_count - 1;
7631 while (index >= mapped_count) {
7632 // These go directly in the arguments array and have no
7633 // corresponding slot in the parameter map.
7634 arguments->set(index, *(parameters - index - 1));
7635 --index;
7636 }
7637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007638 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 while (index >= 0) {
7640 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 Handle<String> name(scope_info->ParameterName(index));
7642 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007643 bool duplicate = false;
7644 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007645 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007646 duplicate = true;
7647 break;
7648 }
7649 }
7650
7651 if (duplicate) {
7652 // This goes directly in the arguments array with a hole in the
7653 // parameter map.
7654 arguments->set(index, *(parameters - index - 1));
7655 parameter_map->set_the_hole(index + 2);
7656 } else {
7657 // The context index goes in the parameter map with a hole in the
7658 // arguments array.
7659 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007660 for (int j = 0; j < context_local_count; ++j) {
7661 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007662 context_index = j;
7663 break;
7664 }
7665 }
7666 ASSERT(context_index >= 0);
7667 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007668 parameter_map->set(index + 2, Smi::FromInt(
7669 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007670 }
7671
7672 --index;
7673 }
7674 } else {
7675 // If there is no aliasing, the arguments object elements are not
7676 // special in any way.
7677 Handle<FixedArray> elements =
7678 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7679 result->set_elements(*elements);
7680 for (int i = 0; i < argument_count; ++i) {
7681 elements->set(i, *(parameters - i - 1));
7682 }
7683 }
7684 }
7685 return *result;
7686}
7687
7688
7689RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007690 NoHandleAllocation ha;
7691 ASSERT(args.length() == 3);
7692
7693 JSFunction* callee = JSFunction::cast(args[0]);
7694 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007695 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007696
lrn@chromium.org303ada72010-10-27 09:33:13 +00007697 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698 { MaybeObject* maybe_result =
7699 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007700 if (!maybe_result->ToObject(&result)) return maybe_result;
7701 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007702 // Allocate the elements if needed.
7703 if (length > 0) {
7704 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007705 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007706 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007707 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7708 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007709
7710 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007711 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007712 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007713 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007714
7715 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007716 for (int i = 0; i < length; i++) {
7717 array->set(i, *--parameters, mode);
7718 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007719 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007720 }
7721 return result;
7722}
7723
7724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007725RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007727 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007728 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7729 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7730 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731
whesse@chromium.org7b260152011-06-20 15:33:18 +00007732 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007733 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007734 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007736 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7737 context,
7738 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739 return *result;
7740}
7741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007742
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007743// Find the arguments of the JavaScript function invocation that called
7744// into C++ code. Collect these in a newly allocated array of handles (possibly
7745// prefixed by a number of empty handles).
7746static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7747 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007748 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007749 // Find frame containing arguments passed to the caller.
7750 JavaScriptFrameIterator it;
7751 JavaScriptFrame* frame = it.frame();
7752 List<JSFunction*> functions(2);
7753 frame->GetFunctions(&functions);
7754 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007755 int inlined_jsframe_index = functions.length() - 1;
7756 JSFunction* inlined_function = functions[inlined_jsframe_index];
7757 Vector<SlotRef> args_slots =
7758 SlotRef::ComputeSlotMappingForArguments(
7759 frame,
7760 inlined_jsframe_index,
7761 inlined_function->shared()->formal_parameter_count());
7762
7763 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007765 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007766 SmartArrayPointer<Handle<Object> > param_data(
7767 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768 for (int i = 0; i < args_count; i++) {
7769 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007770 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007772
7773 args_slots.Dispose();
7774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775 return param_data;
7776 } else {
7777 it.AdvanceToArgumentsFrame();
7778 frame = it.frame();
7779 int args_count = frame->ComputeParametersCount();
7780
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007781 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007782 SmartArrayPointer<Handle<Object> > param_data(
7783 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007784 for (int i = 0; i < args_count; i++) {
7785 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007786 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007787 }
7788 return param_data;
7789 }
7790}
7791
7792
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007793RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7794 HandleScope scope(isolate);
7795 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007796 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007797 RUNTIME_ASSERT(args[3]->IsNumber());
7798 Handle<Object> bindee = args.at<Object>(1);
7799
7800 // TODO(lrn): Create bound function in C++ code from premade shared info.
7801 bound_function->shared()->set_bound(true);
7802 // Get all arguments of calling function (Function.prototype.bind).
7803 int argc = 0;
7804 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7805 // Don't count the this-arg.
7806 if (argc > 0) {
7807 ASSERT(*arguments[0] == args[2]);
7808 argc--;
7809 } else {
7810 ASSERT(args[2]->IsUndefined());
7811 }
7812 // Initialize array of bindings (function, this, and any existing arguments
7813 // if the function was already bound).
7814 Handle<FixedArray> new_bindings;
7815 int i;
7816 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7817 Handle<FixedArray> old_bindings(
7818 JSFunction::cast(*bindee)->function_bindings());
7819 new_bindings =
7820 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7821 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7822 i = 0;
7823 for (int n = old_bindings->length(); i < n; i++) {
7824 new_bindings->set(i, old_bindings->get(i));
7825 }
7826 } else {
7827 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7828 new_bindings = isolate->factory()->NewFixedArray(array_size);
7829 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7830 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7831 i = 2;
7832 }
7833 // Copy arguments, skipping the first which is "this_arg".
7834 for (int j = 0; j < argc; j++, i++) {
7835 new_bindings->set(i, *arguments[j + 1]);
7836 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007837 new_bindings->set_map_no_write_barrier(
7838 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007839 bound_function->set_function_bindings(*new_bindings);
7840
7841 // Update length.
7842 Handle<String> length_symbol = isolate->factory()->length_symbol();
7843 Handle<Object> new_length(args.at<Object>(3));
7844 PropertyAttributes attr =
7845 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7846 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7847 return *bound_function;
7848}
7849
7850
7851RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7852 HandleScope handles(isolate);
7853 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007854 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007855 if (callable->IsJSFunction()) {
7856 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7857 if (function->shared()->bound()) {
7858 Handle<FixedArray> bindings(function->function_bindings());
7859 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7860 return *isolate->factory()->NewJSArrayWithElements(bindings);
7861 }
7862 }
7863 return isolate->heap()->undefined_value();
7864}
7865
7866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007867RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007869 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007870 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007871 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007872 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007873
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007874 // The argument is a bound function. Extract its bound arguments
7875 // and callable.
7876 Handle<FixedArray> bound_args =
7877 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7878 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7879 Handle<Object> bound_function(
7880 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7881 ASSERT(!bound_function->IsJSFunction() ||
7882 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007884 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007885 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007886 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007887 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007888 param_data[i] = Handle<Object>(bound_args->get(
7889 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007890 }
7891
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007892 if (!bound_function->IsJSFunction()) {
7893 bool exception_thrown;
7894 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7895 &exception_thrown);
7896 if (exception_thrown) return Failure::Exception();
7897 }
7898 ASSERT(bound_function->IsJSFunction());
7899
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007900 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007901 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007902 Execution::New(Handle<JSFunction>::cast(bound_function),
7903 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007904 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007905 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007906 }
7907 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007908 return *result;
7909}
7910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912static void TrySettingInlineConstructStub(Isolate* isolate,
7913 Handle<JSFunction> function) {
7914 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007915 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007916 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007917 }
7918 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007919 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007920 Handle<Code> code = compiler.CompileConstructStub(function);
7921 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007922 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007923}
7924
7925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007926RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007927 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928 ASSERT(args.length() == 1);
7929
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007930 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007932 // If the constructor isn't a proper function we throw a type error.
7933 if (!constructor->IsJSFunction()) {
7934 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7935 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007936 isolate->factory()->NewTypeError("not_constructor", arguments);
7937 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007938 }
7939
7940 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007941
7942 // If function should not have prototype, construction is not allowed. In this
7943 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007944 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007945 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7946 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 isolate->factory()->NewTypeError("not_constructor", arguments);
7948 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007949 }
7950
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007951#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007952 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007953 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 if (debug->StepInActive()) {
7955 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007956 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007957#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007958
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007959 if (function->has_initial_map()) {
7960 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 // The 'Function' function ignores the receiver object when
7962 // called using 'new' and creates a new JSFunction object that
7963 // is returned. The receiver object is only used for error
7964 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007966 // allocate JSFunctions since it does not properly initialize
7967 // the shared part of the function. Since the receiver is
7968 // ignored anyway, we use the global object as the receiver
7969 // instead of a new JSFunction object. This way, errors are
7970 // reported the same way whether or not 'Function' is called
7971 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 }
7975
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007976 // The function should be compiled for the optimization hints to be
7977 // available. We cannot use EnsureCompiled because that forces a
7978 // compilation through the shared function info which makes it
7979 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007980 if (!function->is_compiled()) {
7981 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7982 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007983
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007984 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007985 if (!function->has_initial_map() &&
7986 shared->IsInobjectSlackTrackingInProgress()) {
7987 // The tracking is already in progress for another function. We can only
7988 // track one initial_map at a time, so we force the completion before the
7989 // function is called as a constructor for the first time.
7990 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007991 }
7992
7993 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7995 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007996 // Delay setting the stub if inobject slack tracking is in progress.
7997 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007998 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007999 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008001 isolate->counters()->constructed_objects()->Increment();
8002 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008003
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008004 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005}
8006
8007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008008RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008009 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008010 ASSERT(args.length() == 1);
8011
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008012 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008013 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008016 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008017}
8018
8019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008020RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008022 ASSERT(args.length() == 1);
8023
8024 Handle<JSFunction> function = args.at<JSFunction>(0);
8025#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008026 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008028 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 PrintF("]\n");
8030 }
8031#endif
8032
lrn@chromium.org34e60782011-09-15 07:25:40 +00008033 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008034 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008035 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 return Failure::Exception();
8037 }
8038
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008039 // All done. Return the compiled code.
8040 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 return function->code();
8042}
8043
8044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008047 ASSERT(args.length() == 1);
8048 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008049
8050 // If the function is not compiled ignore the lazy
8051 // recompilation. This can happen if the debugger is activated and
8052 // the function is returned to the not compiled state.
8053 if (!function->shared()->is_compiled()) {
8054 function->ReplaceCode(function->shared()->code());
8055 return function->code();
8056 }
8057
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008058 // If the function is not optimizable or debugger is active continue using the
8059 // code from the full compiler.
8060 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008061 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008062 if (FLAG_trace_opt) {
8063 PrintF("[failed to optimize ");
8064 function->PrintName();
8065 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8066 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008067 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008068 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008069 function->ReplaceCode(function->shared()->code());
8070 return function->code();
8071 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008072 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008073 if (JSFunction::CompileOptimized(function,
8074 AstNode::kNoNumber,
8075 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008076 return function->code();
8077 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008078 if (FLAG_trace_opt) {
8079 PrintF("[failed to optimize ");
8080 function->PrintName();
8081 PrintF(": optimized compilation failed]\n");
8082 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008083 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008084 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008085}
8086
8087
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008088class ActivationsFinder : public ThreadVisitor {
8089 public:
8090 explicit ActivationsFinder(JSFunction* function)
8091 : function_(function), has_activations_(false) {}
8092
8093 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8094 if (has_activations_) return;
8095
8096 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8097 JavaScriptFrame* frame = it.frame();
8098 if (frame->is_optimized() && frame->function() == function_) {
8099 has_activations_ = true;
8100 return;
8101 }
8102 }
8103 }
8104
8105 bool has_activations() { return has_activations_; }
8106
8107 private:
8108 JSFunction* function_;
8109 bool has_activations_;
8110};
8111
8112
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008113static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8114 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 Handle<Object> arguments;
8117 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008118 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008119 if (arguments.is_null()) {
8120 // FunctionGetArguments can't throw an exception, so cast away the
8121 // doubt with an assert.
8122 arguments = Handle<Object>(
8123 Accessors::FunctionGetArguments(*function,
8124 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008125 ASSERT(*arguments != isolate->heap()->null_value());
8126 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008127 }
8128 frame->SetExpression(i, *arguments);
8129 }
8130 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008131}
8132
8133
8134RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8135 HandleScope scope(isolate);
8136 ASSERT(args.length() == 1);
8137 RUNTIME_ASSERT(args[0]->IsSmi());
8138 Deoptimizer::BailoutType type =
8139 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8140 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8141 ASSERT(isolate->heap()->IsAllocationAllowed());
8142 int jsframes = deoptimizer->jsframe_count();
8143
8144 deoptimizer->MaterializeHeapNumbers();
8145 delete deoptimizer;
8146
8147 JavaScriptFrameIterator it(isolate);
8148 for (int i = 0; i < jsframes - 1; i++) {
8149 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8150 it.Advance();
8151 }
8152
8153 JavaScriptFrame* frame = it.frame();
8154 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8155 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8156 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008157
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008158 if (type == Deoptimizer::EAGER) {
8159 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008160 }
8161
8162 // Avoid doing too much work when running with --always-opt and keep
8163 // the optimized code around.
8164 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008166 }
8167
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008168 // Find other optimized activations of the function.
8169 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170 while (!it.done()) {
8171 JavaScriptFrame* frame = it.frame();
8172 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008173 has_other_activations = true;
8174 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008175 }
8176 it.Advance();
8177 }
8178
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008179 if (!has_other_activations) {
8180 ActivationsFinder activations_finder(*function);
8181 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8182 has_other_activations = activations_finder.has_activations();
8183 }
8184
8185 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008186 if (FLAG_trace_deopt) {
8187 PrintF("[removing optimized code for: ");
8188 function->PrintName();
8189 PrintF("]\n");
8190 }
8191 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008192 } else {
8193 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196}
8197
8198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008199RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008201 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008202 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008203}
8204
8205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008206RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008209 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008211
8212 Deoptimizer::DeoptimizeFunction(*function);
8213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008214 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008215}
8216
8217
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008218RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8219#if defined(USE_SIMULATOR)
8220 return isolate->heap()->true_value();
8221#else
8222 return isolate->heap()->false_value();
8223#endif
8224}
8225
8226
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008227RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8228 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008229 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008231
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008232 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8233 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008234
8235 Code* unoptimized = function->shared()->code();
8236 if (args.length() == 2 &&
8237 unoptimized->kind() == Code::FUNCTION) {
8238 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8239 CHECK(type->IsEqualTo(CStrVector("osr")));
8240 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8241 unoptimized->set_allow_osr_at_loop_nesting_level(
8242 Code::kMaxLoopNestingMarker);
8243 }
8244
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008245 return isolate->heap()->undefined_value();
8246}
8247
8248
lrn@chromium.org1c092762011-05-09 09:42:16 +00008249RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8250 HandleScope scope(isolate);
8251 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008252 // The least significant bit (after untagging) indicates whether the
8253 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008254 if (!V8::UseCrankshaft()) {
8255 return Smi::FromInt(4); // 4 == "never".
8256 }
8257 if (FLAG_always_opt) {
8258 return Smi::FromInt(3); // 3 == "always".
8259 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008260 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008261 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8262 : Smi::FromInt(2); // 2 == "no".
8263}
8264
8265
8266RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8267 HandleScope scope(isolate);
8268 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008269 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008270 return Smi::FromInt(function->shared()->opt_count());
8271}
8272
8273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008274RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008276 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008277 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008278
8279 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008280 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008281
8282 // We have hit a back edge in an unoptimized frame for a function that was
8283 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008285 // Keep track of whether we've succeeded in optimizing.
8286 bool succeeded = unoptimized->optimizable();
8287 if (succeeded) {
8288 // If we are trying to do OSR when there are already optimized
8289 // activations of the function, it means (a) the function is directly or
8290 // indirectly recursive and (b) an optimized invocation has been
8291 // deoptimized so that we are currently in an unoptimized activation.
8292 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008293 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008294 while (succeeded && !it.done()) {
8295 JavaScriptFrame* frame = it.frame();
8296 succeeded = !frame->is_optimized() || frame->function() != *function;
8297 it.Advance();
8298 }
8299 }
8300
8301 int ast_id = AstNode::kNoNumber;
8302 if (succeeded) {
8303 // The top JS function is this one, the PC is somewhere in the
8304 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008305 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008306 JavaScriptFrame* frame = it.frame();
8307 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008308 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008309 ASSERT(unoptimized->contains(frame->pc()));
8310
8311 // Use linear search of the unoptimized code's stack check table to find
8312 // the AST id matching the PC.
8313 Address start = unoptimized->instruction_start();
8314 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008315 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008316 uint32_t table_length = Memory::uint32_at(table_cursor);
8317 table_cursor += kIntSize;
8318 for (unsigned i = 0; i < table_length; ++i) {
8319 // Table entries are (AST id, pc offset) pairs.
8320 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8321 if (pc_offset == target_pc_offset) {
8322 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8323 break;
8324 }
8325 table_cursor += 2 * kIntSize;
8326 }
8327 ASSERT(ast_id != AstNode::kNoNumber);
8328 if (FLAG_trace_osr) {
8329 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8330 function->PrintName();
8331 PrintF("]\n");
8332 }
8333
8334 // Try to compile the optimized code. A true return value from
8335 // CompileOptimized means that compilation succeeded, not necessarily
8336 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008337 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008338 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008339 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8340 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008341 if (data->OsrPcOffset()->value() >= 0) {
8342 if (FLAG_trace_osr) {
8343 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008344 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008345 }
8346 ASSERT(data->OsrAstId()->value() == ast_id);
8347 } else {
8348 // We may never generate the desired OSR entry if we emit an
8349 // early deoptimize.
8350 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008351 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008352 } else {
8353 succeeded = false;
8354 }
8355 }
8356
8357 // Revert to the original stack checks in the original unoptimized code.
8358 if (FLAG_trace_osr) {
8359 PrintF("[restoring original stack checks in ");
8360 function->PrintName();
8361 PrintF("]\n");
8362 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008363 Handle<Code> check_code;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008364 if (FLAG_count_based_interrupts) {
8365 InterruptStub interrupt_stub;
8366 check_code = interrupt_stub.GetCode();
8367 } else // NOLINT
yangguo@chromium.org56454712012-02-16 15:33:53 +00008368 { // NOLINT
8369 StackCheckStub check_stub;
8370 check_code = check_stub.GetCode();
8371 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008372 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008373 Deoptimizer::RevertStackCheckCode(*unoptimized,
8374 *check_code,
8375 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008376
8377 // Allow OSR only at nesting level zero again.
8378 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8379
8380 // If the optimization attempt succeeded, return the AST id tagged as a
8381 // smi. This tells the builtin that we need to translate the unoptimized
8382 // frame to an optimized one.
8383 if (succeeded) {
8384 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8385 return Smi::FromInt(ast_id);
8386 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008387 if (function->IsMarkedForLazyRecompilation()) {
8388 function->ReplaceCode(function->shared()->code());
8389 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008390 return Smi::FromInt(-1);
8391 }
8392}
8393
8394
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008395RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8396 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8397 return isolate->heap()->undefined_value();
8398}
8399
8400
danno@chromium.orgc612e022011-11-10 11:38:15 +00008401RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8402 HandleScope scope(isolate);
8403 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008404 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008405 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8406 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008407
8408 // If there are too many arguments, allocate argv via malloc.
8409 const int argv_small_size = 10;
8410 Handle<Object> argv_small_buffer[argv_small_size];
8411 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8412 Handle<Object>* argv = argv_small_buffer;
8413 if (argc > argv_small_size) {
8414 argv = new Handle<Object>[argc];
8415 if (argv == NULL) return isolate->StackOverflow();
8416 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8417 }
8418
8419 for (int i = 0; i < argc; ++i) {
8420 MaybeObject* maybe = args[1 + i];
8421 Object* object;
8422 if (!maybe->To<Object>(&object)) return maybe;
8423 argv[i] = Handle<Object>(object);
8424 }
8425
8426 bool threw;
8427 Handle<JSReceiver> hfun(fun);
8428 Handle<Object> hreceiver(receiver);
8429 Handle<Object> result =
8430 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8431
8432 if (threw) return Failure::Exception();
8433 return *result;
8434}
8435
8436
lrn@chromium.org34e60782011-09-15 07:25:40 +00008437RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8438 HandleScope scope(isolate);
8439 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008440 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008441 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008442 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008443 CONVERT_SMI_ARG_CHECKED(offset, 3);
8444 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008445 ASSERT(offset >= 0);
8446 ASSERT(argc >= 0);
8447
8448 // If there are too many arguments, allocate argv via malloc.
8449 const int argv_small_size = 10;
8450 Handle<Object> argv_small_buffer[argv_small_size];
8451 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8452 Handle<Object>* argv = argv_small_buffer;
8453 if (argc > argv_small_size) {
8454 argv = new Handle<Object>[argc];
8455 if (argv == NULL) return isolate->StackOverflow();
8456 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8457 }
8458
8459 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008460 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008461 }
8462
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008463 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008464 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008465 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008466
8467 if (threw) return Failure::Exception();
8468 return *result;
8469}
8470
8471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008472RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 ASSERT(args.length() == 1);
8475 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8476 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8477}
8478
8479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008480RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008481 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008482 ASSERT(args.length() == 1);
8483 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8484 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8485}
8486
8487
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008489 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008490 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008491
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008492 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008493 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008494 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 { MaybeObject* maybe_result =
8496 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008497 if (!maybe_result->ToObject(&result)) return maybe_result;
8498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008501
kasper.lund7276f142008-07-30 08:49:36 +00008502 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008503}
8504
lrn@chromium.org303ada72010-10-27 09:33:13 +00008505
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008506RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8507 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008508 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008509 JSObject* extension_object;
8510 if (args[0]->IsJSObject()) {
8511 extension_object = JSObject::cast(args[0]);
8512 } else {
8513 // Convert the object to a proper JavaScript object.
8514 MaybeObject* maybe_js_object = args[0]->ToObject();
8515 if (!maybe_js_object->To(&extension_object)) {
8516 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8517 HandleScope scope(isolate);
8518 Handle<Object> handle = args.at<Object>(0);
8519 Handle<Object> result =
8520 isolate->factory()->NewTypeError("with_expression",
8521 HandleVector(&handle, 1));
8522 return isolate->Throw(*result);
8523 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008524 return maybe_js_object;
8525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008526 }
8527 }
8528
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008529 JSFunction* function;
8530 if (args[1]->IsSmi()) {
8531 // A smi sentinel indicates a context nested inside global code rather
8532 // than some function. There is a canonical empty function that can be
8533 // gotten from the global context.
8534 function = isolate->context()->global_context()->closure();
8535 } else {
8536 function = JSFunction::cast(args[1]);
8537 }
8538
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008539 Context* context;
8540 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008541 isolate->heap()->AllocateWithContext(function,
8542 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008543 extension_object);
8544 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008545 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008546 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008547}
8548
8549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008550RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008551 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008552 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008553 String* name = String::cast(args[0]);
8554 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008555 JSFunction* function;
8556 if (args[2]->IsSmi()) {
8557 // A smi sentinel indicates a context nested inside global code rather
8558 // than some function. There is a canonical empty function that can be
8559 // gotten from the global context.
8560 function = isolate->context()->global_context()->closure();
8561 } else {
8562 function = JSFunction::cast(args[2]);
8563 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008564 Context* context;
8565 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008566 isolate->heap()->AllocateCatchContext(function,
8567 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008568 name,
8569 thrown_object);
8570 if (!maybe_context->To(&context)) return maybe_context;
8571 isolate->set_context(context);
8572 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008573}
8574
8575
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008576RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8577 NoHandleAllocation ha;
8578 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008579 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008580 JSFunction* function;
8581 if (args[1]->IsSmi()) {
8582 // A smi sentinel indicates a context nested inside global code rather
8583 // than some function. There is a canonical empty function that can be
8584 // gotten from the global context.
8585 function = isolate->context()->global_context()->closure();
8586 } else {
8587 function = JSFunction::cast(args[1]);
8588 }
8589 Context* context;
8590 MaybeObject* maybe_context =
8591 isolate->heap()->AllocateBlockContext(function,
8592 isolate->context(),
8593 scope_info);
8594 if (!maybe_context->To(&context)) return maybe_context;
8595 isolate->set_context(context);
8596 return context;
8597}
8598
8599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008600RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008601 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602 ASSERT(args.length() == 2);
8603
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008604 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8605 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606
8607 int index;
8608 PropertyAttributes attributes;
8609 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008610 BindingFlags binding_flags;
8611 Handle<Object> holder = context->Lookup(name,
8612 flags,
8613 &index,
8614 &attributes,
8615 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008616
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008617 // If the slot was not found the result is true.
8618 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008619 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008620 }
8621
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008622 // If the slot was found in a context, it should be DONT_DELETE.
8623 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008624 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008625 }
8626
8627 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008628 // the global object, or the subject of a with. Try to delete it
8629 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008630 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008631 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632}
8633
8634
ager@chromium.orga1645e22009-09-09 19:27:10 +00008635// A mechanism to return a pair of Object pointers in registers (if possible).
8636// How this is achieved is calling convention-dependent.
8637// All currently supported x86 compiles uses calling conventions that are cdecl
8638// variants where a 64-bit value is returned in two 32-bit registers
8639// (edx:eax on ia32, r1:r0 on ARM).
8640// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8641// In Win64 calling convention, a struct of two pointers is returned in memory,
8642// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008643#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008644struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008645 MaybeObject* x;
8646 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008647};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008648
lrn@chromium.org303ada72010-10-27 09:33:13 +00008649static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008650 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008651 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8652 // In Win64 they are assigned to a hidden first argument.
8653 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008654}
8655#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008656typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008657static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008658 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008659 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008661#endif
8662
8663
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664static inline MaybeObject* Unhole(Heap* heap,
8665 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008666 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8668 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008669 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008670}
8671
8672
danno@chromium.org40cb8782011-05-25 07:58:50 +00008673static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8674 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008675 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008676 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008677 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008678 JSFunction* context_extension_function =
8679 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008680 // If the holder isn't a context extension object, we just return it
8681 // as the receiver. This allows arguments objects to be used as
8682 // receivers, but only if they are put in the context scope chain
8683 // explicitly via a with-statement.
8684 Object* constructor = holder->map()->constructor();
8685 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008686 // Fall back to using the global object as the implicit receiver if
8687 // the property turns out to be a local variable allocated in a
8688 // context extension object - introduced via eval. Implicit global
8689 // receivers are indicated with the hole value.
8690 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008691}
8692
8693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008694static ObjectPair LoadContextSlotHelper(Arguments args,
8695 Isolate* isolate,
8696 bool throw_error) {
8697 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008698 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008700 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008701 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008704 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008705
8706 int index;
8707 PropertyAttributes attributes;
8708 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008709 BindingFlags binding_flags;
8710 Handle<Object> holder = context->Lookup(name,
8711 flags,
8712 &index,
8713 &attributes,
8714 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008715
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008716 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008718 ASSERT(holder->IsContext());
8719 // If the "property" we were looking for is a local variable, the
8720 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008721 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008722 // Use the hole as the receiver to signal that the receiver is implicit
8723 // and that the global receiver should be used (as distinguished from an
8724 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008725 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008726 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008727 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008728 switch (binding_flags) {
8729 case MUTABLE_CHECK_INITIALIZED:
8730 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8731 if (value->IsTheHole()) {
8732 Handle<Object> reference_error =
8733 isolate->factory()->NewReferenceError("not_defined",
8734 HandleVector(&name, 1));
8735 return MakePair(isolate->Throw(*reference_error), NULL);
8736 }
8737 // FALLTHROUGH
8738 case MUTABLE_IS_INITIALIZED:
8739 case IMMUTABLE_IS_INITIALIZED:
8740 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8741 ASSERT(!value->IsTheHole());
8742 return MakePair(value, *receiver);
8743 case IMMUTABLE_CHECK_INITIALIZED:
8744 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8745 case MISSING_BINDING:
8746 UNREACHABLE();
8747 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008748 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008749 }
8750
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008751 // Otherwise, if the slot was found the holder is a context extension
8752 // object, subject of a with, or a global object. We read the named
8753 // property from it.
8754 if (!holder.is_null()) {
8755 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8756 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008757 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008758 Handle<Object> receiver_handle(object->IsGlobalObject()
8759 ? GlobalObject::cast(*object)->global_receiver()
8760 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008762 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008763 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008764 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008765 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008766 }
8767
8768 if (throw_error) {
8769 // The property doesn't exist - throw exception.
8770 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771 isolate->factory()->NewReferenceError("not_defined",
8772 HandleVector(&name, 1));
8773 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008775 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008776 return MakePair(isolate->heap()->undefined_value(),
8777 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008778 }
8779}
8780
8781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008782RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784}
8785
8786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008787RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008788 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789}
8790
8791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008792RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008793 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008794 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008796 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008797 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8798 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008799 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8800 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8801 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802
8803 int index;
8804 PropertyAttributes attributes;
8805 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008806 BindingFlags binding_flags;
8807 Handle<Object> holder = context->Lookup(name,
8808 flags,
8809 &index,
8810 &attributes,
8811 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812
8813 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008814 // The property was found in a context slot.
8815 Handle<Context> context = Handle<Context>::cast(holder);
8816 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8817 context->get(index)->IsTheHole()) {
8818 Handle<Object> error =
8819 isolate->factory()->NewReferenceError("not_defined",
8820 HandleVector(&name, 1));
8821 return isolate->Throw(*error);
8822 }
8823 // Ignore if read_only variable.
8824 if ((attributes & READ_ONLY) == 0) {
8825 // Context is a fixed array and set cannot fail.
8826 context->set(index, *value);
8827 } else if (strict_mode == kStrictMode) {
8828 // Setting read only property in strict mode.
8829 Handle<Object> error =
8830 isolate->factory()->NewTypeError("strict_cannot_assign",
8831 HandleVector(&name, 1));
8832 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833 }
8834 return *value;
8835 }
8836
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008837 // Slow case: The property is not in a context slot. It is either in a
8838 // context extension object, a property of the subject of a with, or a
8839 // property of the global object.
8840 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008842 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008843 // The property exists on the holder.
8844 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008846 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008848
8849 if (strict_mode == kStrictMode) {
8850 // Throw in strict mode (assignment to undefined variable).
8851 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008852 isolate->factory()->NewReferenceError(
8853 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008854 return isolate->Throw(*error);
8855 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008856 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008858 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008859 }
8860
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008861 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008862 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008863 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008864 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008866 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008867 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008868 // Setting read only property in strict mode.
8869 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008870 isolate->factory()->NewTypeError(
8871 "strict_cannot_assign", HandleVector(&name, 1));
8872 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 }
8874 return *value;
8875}
8876
8877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008878RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008879 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 ASSERT(args.length() == 1);
8881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008882 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008883}
8884
8885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008886RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008887 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888 ASSERT(args.length() == 1);
8889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891}
8892
8893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008894RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008895 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008896 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008897}
8898
8899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008900RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902 ASSERT(args.length() == 1);
8903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008904 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 isolate->factory()->NewReferenceError("not_defined",
8907 HandleVector(&name, 1));
8908 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909}
8910
8911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008912RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008913 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914
8915 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008916 if (isolate->stack_guard()->IsStackOverflow()) {
8917 NoHandleAllocation na;
8918 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008919 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920
ulan@chromium.org812308e2012-02-29 15:58:45 +00008921 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922}
8923
8924
yangguo@chromium.org56454712012-02-16 15:33:53 +00008925RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8926 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008927 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008928}
8929
8930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931static int StackSize() {
8932 int n = 0;
8933 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8934 return n;
8935}
8936
8937
8938static void PrintTransition(Object* result) {
8939 // indentation
8940 { const int nmax = 80;
8941 int n = StackSize();
8942 if (n <= nmax)
8943 PrintF("%4d:%*s", n, n, "");
8944 else
8945 PrintF("%4d:%*s", n, nmax, "...");
8946 }
8947
8948 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008949 JavaScriptFrame::PrintTop(stdout, true, false);
8950 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 } else {
8952 // function result
8953 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008954 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 PrintF("\n");
8956 }
8957}
8958
8959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008960RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008961 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962 NoHandleAllocation ha;
8963 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965}
8966
8967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008968RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 NoHandleAllocation ha;
8970 PrintTransition(args[0]);
8971 return args[0]; // return TOS
8972}
8973
8974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008975RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 NoHandleAllocation ha;
8977 ASSERT(args.length() == 1);
8978
8979#ifdef DEBUG
8980 if (args[0]->IsString()) {
8981 // If we have a string, assume it's a code "marker"
8982 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008983 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008985 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8986 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008987 } else {
8988 PrintF("DebugPrint: ");
8989 }
8990 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008991 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008992 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008993 HeapObject::cast(args[0])->map()->Print();
8994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008996 // ShortPrint is available in release mode. Print is not.
8997 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998#endif
8999 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009000 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001
9002 return args[0]; // return TOS
9003}
9004
9005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009006RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009007 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 isolate->PrintStack();
9010 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011}
9012
9013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009014RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009016 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017
9018 // According to ECMA-262, section 15.9.1, page 117, the precision of
9019 // the number in a Date object representing a particular instant in
9020 // time is milliseconds. Therefore, we floor the result of getting
9021 // the OS time.
9022 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024}
9025
9026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009027RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009029 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009031 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009032 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009034 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009035
9036 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009037 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009038 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009039 RUNTIME_ASSERT(output->HasFastElements());
9040
9041 AssertNoAllocation no_allocation;
9042
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009043 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009044 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9045 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009046 String::FlatContent str_content = str->GetFlatContent();
9047 if (str_content.IsAscii()) {
9048 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009049 output_array,
9050 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009052 ASSERT(str_content.IsTwoByte());
9053 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009054 output_array,
9055 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009056 }
9057
9058 if (result) {
9059 return *output;
9060 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009061 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 }
9063}
9064
9065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009066RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067 NoHandleAllocation ha;
9068 ASSERT(args.length() == 1);
9069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009070 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009071 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9072 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009073 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074}
9075
9076
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009077RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009078 NoHandleAllocation ha;
9079 ASSERT(args.length() == 1);
9080
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009081 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009082 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9083
9084 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085}
9086
9087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009088RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009089 ASSERT(args.length() == 1);
9090 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009092 return JSGlobalObject::cast(global)->global_receiver();
9093}
9094
9095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009098 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009099 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009100
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009101 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009102 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009103 Handle<Object> result;
9104 if (source->IsSeqAsciiString()) {
9105 result = JsonParser<true>::Parse(source);
9106 } else {
9107 result = JsonParser<false>::Parse(source);
9108 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009109 if (result.is_null()) {
9110 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009112 return Failure::Exception();
9113 }
9114 return *result;
9115}
9116
9117
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009118bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9119 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009120 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9121 // Check with callback if set.
9122 AllowCodeGenerationFromStringsCallback callback =
9123 isolate->allow_code_gen_callback();
9124 if (callback == NULL) {
9125 // No callback set and code generation disallowed.
9126 return false;
9127 } else {
9128 // Callback set. Let it decide if code generation is allowed.
9129 VMState state(isolate, EXTERNAL);
9130 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009131 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009132}
9133
9134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009135RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009137 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009138 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009139
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009140 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009142
9143 // Check if global context allows code generation from
9144 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009145 if (context->allow_code_gen_from_strings()->IsFalse() &&
9146 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009147 return isolate->Throw(*isolate->factory()->NewError(
9148 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9149 }
9150
9151 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009152 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009153 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009154 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9157 context,
9158 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 return *fun;
9160}
9161
9162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163static ObjectPair CompileGlobalEval(Isolate* isolate,
9164 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009165 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009166 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009167 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009168 Handle<Context> context = Handle<Context>(isolate->context());
9169 Handle<Context> global_context = Handle<Context>(context->global_context());
9170
9171 // Check if global context allows code generation from
9172 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009173 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9174 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009175 isolate->Throw(*isolate->factory()->NewError(
9176 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9177 return MakePair(Failure::Exception(), NULL);
9178 }
9179
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009180 // Deal with a normal eval call with a string argument. Compile it
9181 // and return the compiled function bound in the local context.
9182 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9183 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009185 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009186 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009187 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009188 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 Handle<JSFunction> compiled =
9190 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009191 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009192 return MakePair(*compiled, *receiver);
9193}
9194
9195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009196RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009197 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009200 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009201
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009202 // If "eval" didn't refer to the original GlobalEval, it's not a
9203 // direct call to eval.
9204 // (And even if it is, but the first argument isn't a string, just let
9205 // execution default to an indirect call to eval, which will also return
9206 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009208 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009209 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009210 }
9211
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009212 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009213 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009214 return CompileGlobalEval(isolate,
9215 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009216 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009217 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009218 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009219}
9220
9221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009222RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 // This utility adjusts the property attributes for newly created Function
9224 // object ("new Function(...)") by changing the map.
9225 // All it does is changing the prototype property to enumerable
9226 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009229 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009231 Handle<Map> map = func->shared()->is_classic_mode()
9232 ? isolate->function_instance_map()
9233 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234
9235 ASSERT(func->map()->instance_type() == map->instance_type());
9236 ASSERT(func->map()->instance_size() == map->instance_size());
9237 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009238 return *func;
9239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009243 // Allocate a block of memory in NewSpace (filled with a filler).
9244 // Use as fallback for allocation in generated code when NewSpace
9245 // is full.
9246 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009247 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009248 int size = size_smi->value();
9249 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9250 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 Heap* heap = isolate->heap();
9252 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009253 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009254 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009256 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009258 }
9259 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009260 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009261}
9262
9263
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009264// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009265// array. Returns true if the element was pushed on the stack and
9266// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009267RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009268 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009269 CONVERT_ARG_CHECKED(JSArray, array, 0);
9270 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009271 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009272 int length = Smi::cast(array->length())->value();
9273 FixedArray* elements = FixedArray::cast(array->elements());
9274 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009275 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009276 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009277 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009278 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009279 { MaybeObject* maybe_obj =
9280 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009281 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9282 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009284}
9285
9286
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009287/**
9288 * A simple visitor visits every element of Array's.
9289 * The backend storage can be a fixed array for fast elements case,
9290 * or a dictionary for sparse array. Since Dictionary is a subtype
9291 * of FixedArray, the class can be used by both fast and slow cases.
9292 * The second parameter of the constructor, fast_elements, specifies
9293 * whether the storage is a FixedArray or Dictionary.
9294 *
9295 * An index limit is used to deal with the situation that a result array
9296 * length overflows 32-bit non-negative integer.
9297 */
9298class ArrayConcatVisitor {
9299 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 ArrayConcatVisitor(Isolate* isolate,
9301 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009302 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 isolate_(isolate),
9304 storage_(Handle<FixedArray>::cast(
9305 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009306 index_offset_(0u),
9307 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009308
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009309 ~ArrayConcatVisitor() {
9310 clear_storage();
9311 }
9312
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009313 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009314 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009315 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009316
9317 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009318 if (index < static_cast<uint32_t>(storage_->length())) {
9319 storage_->set(index, *elm);
9320 return;
9321 }
9322 // Our initial estimate of length was foiled, possibly by
9323 // getters on the arrays increasing the length of later arrays
9324 // during iteration.
9325 // This shouldn't happen in anything but pathological cases.
9326 SetDictionaryMode(index);
9327 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009328 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009329 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009330 Handle<SeededNumberDictionary> dict(
9331 SeededNumberDictionary::cast(*storage_));
9332 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009333 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009335 // Dictionary needed to grow.
9336 clear_storage();
9337 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009338 }
9339}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009340
9341 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009342 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9343 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009344 } else {
9345 index_offset_ += delta;
9346 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009347 }
9348
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009349 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009350 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009351 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009353 Handle<Map> map;
9354 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009355 map = isolate_->factory()->GetElementsTransitionMap(array,
9356 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009357 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009358 map = isolate_->factory()->GetElementsTransitionMap(array,
9359 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 }
9361 array->set_map(*map);
9362 array->set_length(*length);
9363 array->set_elements(*storage_);
9364 return array;
9365 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009366
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009367 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009368 // Convert storage to dictionary mode.
9369 void SetDictionaryMode(uint32_t index) {
9370 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009371 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009372 Handle<SeededNumberDictionary> slow_storage(
9373 isolate_->factory()->NewSeededNumberDictionary(
9374 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009375 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9376 for (uint32_t i = 0; i < current_length; i++) {
9377 HandleScope loop_scope;
9378 Handle<Object> element(current_storage->get(i));
9379 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009380 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009381 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009382 if (!new_storage.is_identical_to(slow_storage)) {
9383 slow_storage = loop_scope.CloseAndEscape(new_storage);
9384 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009385 }
9386 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009387 clear_storage();
9388 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 fast_elements_ = false;
9390 }
9391
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009392 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009393 isolate_->global_handles()->Destroy(
9394 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009395 }
9396
9397 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 storage_ = Handle<FixedArray>::cast(
9399 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009400 }
9401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009403 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009404 // Index after last seen index. Always less than or equal to
9405 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009406 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009407 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009408};
9409
9410
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009411static uint32_t EstimateElementCount(Handle<JSArray> array) {
9412 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9413 int element_count = 0;
9414 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009415 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009416 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009417 // Fast elements can't have lengths that are not representable by
9418 // a 32-bit signed integer.
9419 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9420 int fast_length = static_cast<int>(length);
9421 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9422 for (int i = 0; i < fast_length; i++) {
9423 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009424 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009425 break;
9426 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009427 case FAST_DOUBLE_ELEMENTS:
9428 // TODO(1810): Decide if it's worthwhile to implement this.
9429 UNREACHABLE();
9430 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009431 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009432 Handle<SeededNumberDictionary> dictionary(
9433 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009434 int capacity = dictionary->Capacity();
9435 for (int i = 0; i < capacity; i++) {
9436 Handle<Object> key(dictionary->KeyAt(i));
9437 if (dictionary->IsKey(*key)) {
9438 element_count++;
9439 }
9440 }
9441 break;
9442 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009443 case NON_STRICT_ARGUMENTS_ELEMENTS:
9444 case EXTERNAL_BYTE_ELEMENTS:
9445 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9446 case EXTERNAL_SHORT_ELEMENTS:
9447 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9448 case EXTERNAL_INT_ELEMENTS:
9449 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9450 case EXTERNAL_FLOAT_ELEMENTS:
9451 case EXTERNAL_DOUBLE_ELEMENTS:
9452 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009453 // External arrays are always dense.
9454 return length;
9455 }
9456 // As an estimate, we assume that the prototype doesn't contain any
9457 // inherited elements.
9458 return element_count;
9459}
9460
9461
9462
9463template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464static void IterateExternalArrayElements(Isolate* isolate,
9465 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 bool elements_are_ints,
9467 bool elements_are_guaranteed_smis,
9468 ArrayConcatVisitor* visitor) {
9469 Handle<ExternalArrayClass> array(
9470 ExternalArrayClass::cast(receiver->elements()));
9471 uint32_t len = static_cast<uint32_t>(array->length());
9472
9473 ASSERT(visitor != NULL);
9474 if (elements_are_ints) {
9475 if (elements_are_guaranteed_smis) {
9476 for (uint32_t j = 0; j < len; j++) {
9477 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009478 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009479 visitor->visit(j, e);
9480 }
9481 } else {
9482 for (uint32_t j = 0; j < len; j++) {
9483 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009484 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009485 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9486 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9487 visitor->visit(j, e);
9488 } else {
9489 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 visitor->visit(j, e);
9492 }
9493 }
9494 }
9495 } else {
9496 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009497 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009498 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009499 visitor->visit(j, e);
9500 }
9501 }
9502}
9503
9504
9505// Used for sorting indices in a List<uint32_t>.
9506static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9507 uint32_t a = *ap;
9508 uint32_t b = *bp;
9509 return (a == b) ? 0 : (a < b) ? -1 : 1;
9510}
9511
9512
9513static void CollectElementIndices(Handle<JSObject> object,
9514 uint32_t range,
9515 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009516 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009517 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009518 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009519 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009520 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9521 uint32_t length = static_cast<uint32_t>(elements->length());
9522 if (range < length) length = range;
9523 for (uint32_t i = 0; i < length; i++) {
9524 if (!elements->get(i)->IsTheHole()) {
9525 indices->Add(i);
9526 }
9527 }
9528 break;
9529 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009530 case FAST_DOUBLE_ELEMENTS: {
9531 // TODO(1810): Decide if it's worthwhile to implement this.
9532 UNREACHABLE();
9533 break;
9534 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009535 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009536 Handle<SeededNumberDictionary> dict(
9537 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009538 uint32_t capacity = dict->Capacity();
9539 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009541 Handle<Object> k(dict->KeyAt(j));
9542 if (dict->IsKey(*k)) {
9543 ASSERT(k->IsNumber());
9544 uint32_t index = static_cast<uint32_t>(k->Number());
9545 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009546 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009547 }
9548 }
9549 }
9550 break;
9551 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009552 default: {
9553 int dense_elements_length;
9554 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009555 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009556 dense_elements_length =
9557 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009558 break;
9559 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009560 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009561 dense_elements_length =
9562 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009563 break;
9564 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009565 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009566 dense_elements_length =
9567 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009568 break;
9569 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009570 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009571 dense_elements_length =
9572 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009573 break;
9574 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009575 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009576 dense_elements_length =
9577 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 break;
9579 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009580 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009581 dense_elements_length =
9582 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009583 break;
9584 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009585 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009586 dense_elements_length =
9587 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009588 break;
9589 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009590 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009591 dense_elements_length =
9592 ExternalFloatArray::cast(object->elements())->length();
9593 break;
9594 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009595 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009596 dense_elements_length =
9597 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 break;
9599 }
9600 default:
9601 UNREACHABLE();
9602 dense_elements_length = 0;
9603 break;
9604 }
9605 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9606 if (range <= length) {
9607 length = range;
9608 // We will add all indices, so we might as well clear it first
9609 // and avoid duplicates.
9610 indices->Clear();
9611 }
9612 for (uint32_t i = 0; i < length; i++) {
9613 indices->Add(i);
9614 }
9615 if (length == range) return; // All indices accounted for already.
9616 break;
9617 }
9618 }
9619
9620 Handle<Object> prototype(object->GetPrototype());
9621 if (prototype->IsJSObject()) {
9622 // The prototype will usually have no inherited element indices,
9623 // but we have to check.
9624 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9625 }
9626}
9627
9628
9629/**
9630 * A helper function that visits elements of a JSArray in numerical
9631 * order.
9632 *
9633 * The visitor argument called for each existing element in the array
9634 * with the element index and the element's value.
9635 * Afterwards it increments the base-index of the visitor by the array
9636 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009637 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009638 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009639static bool IterateElements(Isolate* isolate,
9640 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 ArrayConcatVisitor* visitor) {
9642 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9643 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009644 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009645 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 // Run through the elements FixedArray and use HasElement and GetElement
9647 // to check the prototype for missing elements.
9648 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9649 int fast_length = static_cast<int>(length);
9650 ASSERT(fast_length <= elements->length());
9651 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 HandleScope loop_scope(isolate);
9653 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 if (!element_value->IsTheHole()) {
9655 visitor->visit(j, element_value);
9656 } else if (receiver->HasElement(j)) {
9657 // Call GetElement on receiver, not its prototype, or getters won't
9658 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009659 element_value = Object::GetElement(receiver, j);
9660 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 visitor->visit(j, element_value);
9662 }
9663 }
9664 break;
9665 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009666 case FAST_DOUBLE_ELEMENTS: {
9667 // TODO(1810): Decide if it's worthwhile to implement this.
9668 UNREACHABLE();
9669 break;
9670 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009671 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009672 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 List<uint32_t> indices(dict->Capacity() / 2);
9674 // Collect all indices in the object and the prototypes less
9675 // than length. This might introduce duplicates in the indices list.
9676 CollectElementIndices(receiver, length, &indices);
9677 indices.Sort(&compareUInt32);
9678 int j = 0;
9679 int n = indices.length();
9680 while (j < n) {
9681 HandleScope loop_scope;
9682 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009683 Handle<Object> element = Object::GetElement(receiver, index);
9684 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009685 visitor->visit(index, element);
9686 // Skip to next different index (i.e., omit duplicates).
9687 do {
9688 j++;
9689 } while (j < n && indices[j] == index);
9690 }
9691 break;
9692 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009693 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009694 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9695 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009697 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698 visitor->visit(j, e);
9699 }
9700 break;
9701 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009702 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009704 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 break;
9706 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009707 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 break;
9711 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009712 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009713 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009714 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009715 break;
9716 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009717 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009719 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009720 break;
9721 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009722 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 break;
9726 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009727 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730 break;
9731 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009732 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 break;
9736 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009737 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009738 IterateExternalArrayElements<ExternalDoubleArray, double>(
9739 isolate, receiver, false, false, visitor);
9740 break;
9741 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009742 default:
9743 UNREACHABLE();
9744 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009745 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009747 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009748}
9749
9750
9751/**
9752 * Array::concat implementation.
9753 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009755 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009756 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009757RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009758 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009759 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009760
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009761 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 int argument_count = static_cast<int>(arguments->length()->Number());
9763 RUNTIME_ASSERT(arguments->HasFastElements());
9764 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009765
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 // Pass 1: estimate the length and number of elements of the result.
9767 // The actual length can be larger if any of the arguments have getters
9768 // that mutate other arguments (but will otherwise be precise).
9769 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009770
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009771 uint32_t estimate_result_length = 0;
9772 uint32_t estimate_nof_elements = 0;
9773 {
9774 for (int i = 0; i < argument_count; i++) {
9775 HandleScope loop_scope;
9776 Handle<Object> obj(elements->get(i));
9777 uint32_t length_estimate;
9778 uint32_t element_estimate;
9779 if (obj->IsJSArray()) {
9780 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009781 // TODO(1810): Find out if it's worthwhile to properly support
9782 // arbitrary ElementsKinds. For now, pessimistically transition to
9783 // FAST_ELEMENTS.
9784 if (array->HasFastDoubleElements()) {
9785 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009786 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009787 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009788 length_estimate =
9789 static_cast<uint32_t>(array->length()->Number());
9790 element_estimate =
9791 EstimateElementCount(array);
9792 } else {
9793 length_estimate = 1;
9794 element_estimate = 1;
9795 }
9796 // Avoid overflows by capping at kMaxElementCount.
9797 if (JSObject::kMaxElementCount - estimate_result_length <
9798 length_estimate) {
9799 estimate_result_length = JSObject::kMaxElementCount;
9800 } else {
9801 estimate_result_length += length_estimate;
9802 }
9803 if (JSObject::kMaxElementCount - estimate_nof_elements <
9804 element_estimate) {
9805 estimate_nof_elements = JSObject::kMaxElementCount;
9806 } else {
9807 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009808 }
9809 }
9810 }
9811
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009812 // If estimated number of elements is more than half of length, a
9813 // fixed array (fast case) is more time and space-efficient than a
9814 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009815 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009816
9817 Handle<FixedArray> storage;
9818 if (fast_case) {
9819 // The backing storage array must have non-existing elements to
9820 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009821 storage = isolate->factory()->NewFixedArrayWithHoles(
9822 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009823 } else {
9824 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9825 uint32_t at_least_space_for = estimate_nof_elements +
9826 (estimate_nof_elements >> 2);
9827 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009828 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009829 }
9830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009832
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 for (int i = 0; i < argument_count; i++) {
9834 Handle<Object> obj(elements->get(i));
9835 if (obj->IsJSArray()) {
9836 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009837 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009838 return Failure::Exception();
9839 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 } else {
9841 visitor.visit(0, obj);
9842 visitor.increase_index_offset(1);
9843 }
9844 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009845
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009846 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009847}
9848
9849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850// This will not allocate (flatten the string), but it may run
9851// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009852RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 NoHandleAllocation ha;
9854 ASSERT(args.length() == 1);
9855
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009856 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857 StringInputBuffer buffer(string);
9858 while (buffer.has_more()) {
9859 uint16_t character = buffer.GetNext();
9860 PrintF("%c", character);
9861 }
9862 return string;
9863}
9864
ager@chromium.org5ec48922009-05-05 07:25:34 +00009865// Moves all own elements of an object, that are below a limit, to positions
9866// starting at zero. All undefined values are placed after non-undefined values,
9867// and are followed by non-existing element. Does not change the length
9868// property.
9869// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009870RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009871 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009872 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009873 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9874 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875}
9876
9877
9878// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009879RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009881 CONVERT_ARG_CHECKED(JSArray, from, 0);
9882 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009883 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009884 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009885 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009886 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9887 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009888 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009889 } else if (new_elements->map() ==
9890 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009891 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009892 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009893 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009894 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009895 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009896 Object* new_map;
9897 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009898 to->set_map(Map::cast(new_map));
9899 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009901 Object* obj;
9902 { MaybeObject* maybe_obj = from->ResetElements();
9903 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9904 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009905 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906 return to;
9907}
9908
9909
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009910// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009911RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009913 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009914 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009916 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9917 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009918 } else if (object->IsJSArray()) {
9919 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009921 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 }
9923}
9924
9925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009926RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009927 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009928
9929 ASSERT_EQ(3, args.length());
9930
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009931 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009932 Handle<Object> key1 = args.at<Object>(1);
9933 Handle<Object> key2 = args.at<Object>(2);
9934
9935 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009936 if (!key1->ToArrayIndex(&index1)
9937 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009939 }
9940
ager@chromium.orgac091b72010-05-05 07:34:42 +00009941 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009942 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009944 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009946
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009947 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009948 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009949 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009950 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009953}
9954
9955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009957// might have elements. Can either return keys (positive integers) or
9958// intervals (pair of a negative integer (-start-1) followed by a
9959// positive (length)) or undefined values.
9960// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009961RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009963 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009964 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009966 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009967 // Create an array and get all the keys into it, then remove all the
9968 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009969 bool threw = false;
9970 Handle<FixedArray> keys =
9971 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9972 if (threw) return Failure::Exception();
9973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 int keys_length = keys->length();
9975 for (int i = 0; i < keys_length; i++) {
9976 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009977 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009978 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979 // Zap invalid keys.
9980 keys->set_undefined(i);
9981 }
9982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009985 ASSERT(array->HasFastElements() ||
9986 array->HasFastSmiOnlyElements() ||
9987 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009988 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009990 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009991 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009992 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009993 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009994 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 }
10000}
10001
10002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010003RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010005 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10006 CONVERT_ARG_CHECKED(String, name, 1);
10007 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010008 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10009 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010}
10011
10012
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010013#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010014RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010015 ASSERT(args.length() == 0);
10016 return Execution::DebugBreakHelper();
10017}
10018
10019
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020// Helper functions for wrapping and unwrapping stack frame ids.
10021static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010022 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023 return Smi::FromInt(id >> 2);
10024}
10025
10026
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010027static StackFrame::Id UnwrapFrameId(int wrapped) {
10028 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029}
10030
10031
10032// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010033// args[0]: debug event listener function to set or null or undefined for
10034// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010036RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010038 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10039 args[0]->IsUndefined() ||
10040 args[0]->IsNull());
10041 Handle<Object> callback = args.at<Object>(0);
10042 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010045 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010046}
10047
10048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010049RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010050 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 isolate->stack_guard()->DebugBreak();
10052 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053}
10054
10055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056static MaybeObject* DebugLookupResultValue(Heap* heap,
10057 Object* receiver,
10058 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010059 LookupResult* result,
10060 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010061 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010063 case NORMAL:
10064 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010065 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 }
10068 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010069 case FIELD:
10070 value =
10071 JSObject::cast(
10072 result->holder())->FastPropertyAt(result->GetFieldIndex());
10073 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010074 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010075 }
10076 return value;
10077 case CONSTANT_FUNCTION:
10078 return result->GetConstantFunction();
10079 case CALLBACKS: {
10080 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010081 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010082 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10083 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010084 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010085 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010086 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 maybe_value = heap->isolate()->pending_exception();
10088 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010089 if (caught_exception != NULL) {
10090 *caught_exception = true;
10091 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010092 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010093 }
10094 return value;
10095 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010096 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010097 }
10098 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010099 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010100 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010101 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010102 case CONSTANT_TRANSITION:
10103 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010105 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010107 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010109 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010110 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111}
10112
10113
ager@chromium.org32912102009-01-16 10:38:43 +000010114// Get debugger related details for an object property.
10115// args[0]: object holding property
10116// args[1]: name of the property
10117//
10118// The array returned contains the following information:
10119// 0: Property value
10120// 1: Property details
10121// 2: Property value is exception
10122// 3: Getter function if defined
10123// 4: Setter function if defined
10124// Items 2-4 are only filled if the property has either a getter or a setter
10125// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010126RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010127 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128
10129 ASSERT(args.length() == 2);
10130
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010131 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10132 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010134 // Make sure to set the current context to the context before the debugger was
10135 // entered (if the debugger is entered). The reason for switching context here
10136 // is that for some property lookups (accessors and interceptors) callbacks
10137 // into the embedding application can occour, and the embedding application
10138 // could have the assumption that its own global context is the current
10139 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 SaveContext save(isolate);
10141 if (isolate->debug()->InDebugger()) {
10142 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010143 }
10144
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010145 // Skip the global proxy as it has no properties and always delegates to the
10146 // real global object.
10147 if (obj->IsJSGlobalProxy()) {
10148 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10149 }
10150
10151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 // Check if the name is trivially convertible to an index and get the element
10153 // if so.
10154 uint32_t index;
10155 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010157 Object* element_or_char;
10158 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010159 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010160 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10161 return maybe_element_or_char;
10162 }
10163 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010164 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 }
10168
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010169 // Find the number of objects making up this.
10170 int length = LocalPrototypeChainLength(*obj);
10171
10172 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010173 Handle<JSObject> jsproto = obj;
10174 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010175 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010176 jsproto->LocalLookup(*name, &result);
10177 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010178 // LookupResult is not GC safe as it holds raw object pointers.
10179 // GC can happen later in this code so put the required fields into
10180 // local variables using handles when required for later use.
10181 PropertyType result_type = result.type();
10182 Handle<Object> result_callback_obj;
10183 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010184 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10185 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010186 }
10187 Smi* property_details = result.GetPropertyDetails().AsSmi();
10188 // DebugLookupResultValue can cause GC so details from LookupResult needs
10189 // to be copied to handles before this.
10190 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010191 Object* raw_value;
10192 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 DebugLookupResultValue(isolate->heap(), *obj, *name,
10194 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010195 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10196 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010197 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010198
10199 // If the callback object is a fixed array then it contains JavaScript
10200 // getter and/or setter.
10201 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010202 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010203 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010205 details->set(0, *value);
10206 details->set(1, property_details);
10207 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010208 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010209 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010210 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10211 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010212 }
10213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010214 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010215 }
10216 if (i < length - 1) {
10217 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10218 }
10219 }
10220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222}
10223
10224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010225RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227
10228 ASSERT(args.length() == 2);
10229
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010230 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10231 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010233 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234 obj->Lookup(*name, &result);
10235 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010236 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239}
10240
10241
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242// Return the property type calculated from the property details.
10243// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010244RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010246 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10247 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248}
10249
10250
10251// Return the property attribute calculated from the property details.
10252// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010253RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010255 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10256 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257}
10258
10259
10260// Return the property insertion index calculated from the property details.
10261// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010262RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010264 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10265 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266}
10267
10268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269// Return property value from named interceptor.
10270// args[0]: object
10271// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010272RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010275 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010277 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278
10279 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010280 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281}
10282
10283
10284// Return element value from indexed interceptor.
10285// args[0]: object
10286// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010287RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010290 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10292 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10293
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010294 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295}
10296
10297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010298RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299 ASSERT(args.length() >= 1);
10300 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010301 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 if (isolate->debug()->break_id() == 0 ||
10303 break_id != isolate->debug()->break_id()) {
10304 return isolate->Throw(
10305 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 }
10307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309}
10310
10311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010312RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314 ASSERT(args.length() == 1);
10315
10316 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010317 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10319 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 if (!maybe_result->ToObject(&result)) return maybe_result;
10321 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322
10323 // Count all frames which are relevant to debugging stack trace.
10324 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010326 if (id == StackFrame::NO_ID) {
10327 // If there is no JavaScript stack frame count is 0.
10328 return Smi::FromInt(0);
10329 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010330
10331 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10332 n += it.frame()->GetInlineCount();
10333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334 return Smi::FromInt(n);
10335}
10336
10337
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010338class FrameInspector {
10339 public:
10340 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010341 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010342 Isolate* isolate)
10343 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10344 // Calculate the deoptimized frame.
10345 if (frame->is_optimized()) {
10346 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010347 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010348 }
10349 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010350 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010351 is_optimized_ = frame_->is_optimized();
10352 }
10353
10354 ~FrameInspector() {
10355 // Get rid of the calculated deoptimized frame if any.
10356 if (deoptimized_frame_ != NULL) {
10357 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10358 isolate_);
10359 }
10360 }
10361
10362 int GetParametersCount() {
10363 return is_optimized_
10364 ? deoptimized_frame_->parameters_count()
10365 : frame_->ComputeParametersCount();
10366 }
10367 int expression_count() { return deoptimized_frame_->expression_count(); }
10368 Object* GetFunction() {
10369 return is_optimized_
10370 ? deoptimized_frame_->GetFunction()
10371 : frame_->function();
10372 }
10373 Object* GetParameter(int index) {
10374 return is_optimized_
10375 ? deoptimized_frame_->GetParameter(index)
10376 : frame_->GetParameter(index);
10377 }
10378 Object* GetExpression(int index) {
10379 return is_optimized_
10380 ? deoptimized_frame_->GetExpression(index)
10381 : frame_->GetExpression(index);
10382 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010383 int GetSourcePosition() {
10384 return is_optimized_
10385 ? deoptimized_frame_->GetSourcePosition()
10386 : frame_->LookupCode()->SourcePosition(frame_->pc());
10387 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010388 bool IsConstructor() {
10389 return is_optimized_ && !is_bottommost_
10390 ? deoptimized_frame_->HasConstructStub()
10391 : frame_->IsConstructor();
10392 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010393
10394 // To inspect all the provided arguments the frame might need to be
10395 // replaced with the arguments frame.
10396 void SetArgumentsFrame(JavaScriptFrame* frame) {
10397 ASSERT(has_adapted_arguments_);
10398 frame_ = frame;
10399 is_optimized_ = frame_->is_optimized();
10400 ASSERT(!is_optimized_);
10401 }
10402
10403 private:
10404 JavaScriptFrame* frame_;
10405 DeoptimizedFrameInfo* deoptimized_frame_;
10406 Isolate* isolate_;
10407 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010408 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010409 bool has_adapted_arguments_;
10410
10411 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10412};
10413
10414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415static const int kFrameDetailsFrameIdIndex = 0;
10416static const int kFrameDetailsReceiverIndex = 1;
10417static const int kFrameDetailsFunctionIndex = 2;
10418static const int kFrameDetailsArgumentCountIndex = 3;
10419static const int kFrameDetailsLocalCountIndex = 4;
10420static const int kFrameDetailsSourcePositionIndex = 5;
10421static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010422static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010423static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010424static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010426
10427static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10428 JavaScriptFrame* frame) {
10429 SaveContext* save = isolate->save_context();
10430 while (save != NULL && !save->IsBelowFrame(frame)) {
10431 save = save->prev();
10432 }
10433 ASSERT(save != NULL);
10434 return save;
10435}
10436
10437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438// Return an array with frame details
10439// args[0]: number: break id
10440// args[1]: number: frame index
10441//
10442// The array returned contains the following information:
10443// 0: Frame id
10444// 1: Receiver
10445// 2: Function
10446// 3: Argument count
10447// 4: Local count
10448// 5: Source position
10449// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010450// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010451// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452// Arguments name, value
10453// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010454// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010455RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 ASSERT(args.length() == 2);
10458
10459 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010460 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010461 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10462 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010463 if (!maybe_check->ToObject(&check)) return maybe_check;
10464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010466 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467
10468 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010470 if (id == StackFrame::NO_ID) {
10471 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010473 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010476 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010478 if (index < count + it.frame()->GetInlineCount()) break;
10479 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010480 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010481 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010482
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010483 bool is_optimized = it.frame()->is_optimized();
10484
10485 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10486 if (is_optimized) {
10487 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010488 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010489 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010490 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010492 // Traverse the saved contexts chain to find the active context for the
10493 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010494 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495
10496 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010499 // Find source position in unoptimized code.
10500 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501
ulan@chromium.org967e2702012-02-28 09:49:15 +000010502 // Check for constructor frame.
10503 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010505 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010506 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010507 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010508 Handle<ScopeInfo> scope_info(shared->scope_info());
10509 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511 // Get the locals names and values into a temporary array.
10512 //
10513 // TODO(1240907): Hide compiler-introduced stack variables
10514 // (e.g. .result)? For users of the debugger, they will probably be
10515 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010516 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010517 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010519 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010520 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010521 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010522 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010523 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010524 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010525 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010526 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010527 // Get the context containing declarations.
10528 Handle<Context> context(
10529 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010530 for (; i < scope_info->LocalCount(); ++i) {
10531 Handle<String> name(scope_info->LocalName(i));
10532 VariableMode mode;
10533 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010534 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010535 locals->set(i * 2 + 1, context->get(
10536 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010537 }
10538 }
10539
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010540 // Check whether this frame is positioned at return. If not top
10541 // frame or if the frame is optimized it cannot be at a return.
10542 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010543 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010545 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010546
10547 // If positioned just before return find the value to be returned and add it
10548 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010549 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010550 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010551 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010552 Address internal_frame_sp = NULL;
10553 while (!it2.done()) {
10554 if (it2.frame()->is_internal()) {
10555 internal_frame_sp = it2.frame()->sp();
10556 } else {
10557 if (it2.frame()->is_java_script()) {
10558 if (it2.frame()->id() == it.frame()->id()) {
10559 // The internal frame just before the JavaScript frame contains the
10560 // value to return on top. A debug break at return will create an
10561 // internal frame to store the return value (eax/rax/r0) before
10562 // entering the debug break exit frame.
10563 if (internal_frame_sp != NULL) {
10564 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 Handle<Object>(Memory::Object_at(internal_frame_sp),
10566 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010567 break;
10568 }
10569 }
10570 }
10571
10572 // Indicate that the previous frame was not an internal frame.
10573 internal_frame_sp = NULL;
10574 }
10575 it2.Advance();
10576 }
10577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578
10579 // Now advance to the arguments adapter frame (if any). It contains all
10580 // the provided parameters whereas the function frame always have the number
10581 // of arguments matching the functions parameters. The rest of the
10582 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010583 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010584 it.AdvanceToArgumentsFrame();
10585 frame_inspector.SetArgumentsFrame(it.frame());
10586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587
10588 // Find the number of arguments to fill. At least fill the number of
10589 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010590 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010591 if (argument_count < frame_inspector.GetParametersCount()) {
10592 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 }
10594
10595 // Calculate the size of the result.
10596 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010597 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010598 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010599 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600
10601 // Add the frame id.
10602 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10603
10604 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010605 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606
10607 // Add the arguments count.
10608 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10609
10610 // Add the locals count
10611 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010612 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613
10614 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010615 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10617 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 }
10620
10621 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010624 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010626
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010627 // Add flags to indicate information on whether this frame is
10628 // bit 0: invoked in the debugger context.
10629 // bit 1: optimized frame.
10630 // bit 2: inlined in optimized frame
10631 int flags = 0;
10632 if (*save->context() == *isolate->debug()->debug_context()) {
10633 flags |= 1 << 0;
10634 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010635 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010636 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010637 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010638 }
10639 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640
10641 // Fill the dynamic part.
10642 int details_index = kFrameDetailsFirstDynamicIndex;
10643
10644 // Add arguments name and value.
10645 for (int i = 0; i < argument_count; i++) {
10646 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010647 if (i < scope_info->ParameterCount()) {
10648 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651 }
10652
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010653 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010654 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010655 // Get the value from the stack.
10656 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010658 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 }
10660 }
10661
10662 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010663 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 details->set(details_index++, locals->get(i));
10665 }
10666
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010667 // Add the value being returned.
10668 if (at_return) {
10669 details->set(details_index++, *return_value);
10670 }
10671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010672 // Add the receiver (same as in function frame).
10673 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10674 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010675 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010676 if (!receiver->IsJSObject() &&
10677 shared->is_classic_mode() &&
10678 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010679 // If the receiver is not a JSObject and the function is not a
10680 // builtin or strict-mode we have hit an optimization where a
10681 // value object is not converted into a wrapped JS objects. To
10682 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 // by creating correct wrapper object based on the calling frame's
10684 // global context.
10685 it.Advance();
10686 Handle<Context> calling_frames_global_context(
10687 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 receiver =
10689 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690 }
10691 details->set(kFrameDetailsReceiverIndex, *receiver);
10692
10693 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695}
10696
10697
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010698// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010699static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010700 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010701 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010702 Handle<Context> context,
10703 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010704 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010705 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10706 VariableMode mode;
10707 InitializationFlag init_flag;
10708 int context_index = scope_info->ContextSlotIndex(
10709 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010710
whesse@chromium.org7b260152011-06-20 15:33:18 +000010711 RETURN_IF_EMPTY_HANDLE_VALUE(
10712 isolate,
10713 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010714 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010715 Handle<Object>(context->get(context_index), isolate),
10716 NONE,
10717 kNonStrictMode),
10718 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010719 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010720
10721 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010722}
10723
10724
10725// Create a plain JSObject which materializes the local scope for the specified
10726// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010727static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010728 Isolate* isolate,
10729 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010730 FrameInspector* frame_inspector) {
10731 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010732 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010733 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010734
10735 // Allocate and initialize a JSObject with all the arguments, stack locals
10736 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010737 Handle<JSObject> local_scope =
10738 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010739
10740 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010741 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010742 Handle<Object> value(
10743 i < frame_inspector->GetParametersCount() ?
10744 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10745
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010746 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010747 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010748 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010749 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010750 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010751 NONE,
10752 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010753 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 }
10755
10756 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010757 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010758 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010759 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010760 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010761 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010762 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010763 NONE,
10764 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010765 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010766 }
10767
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010768 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010769 // Third fill all context locals.
10770 Handle<Context> frame_context(Context::cast(frame->context()));
10771 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010772 if (!CopyContextLocalsToScopeObject(
10773 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010774 return Handle<JSObject>();
10775 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010776
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010777 // Finally copy any properties from the function context extension.
10778 // These will be variables introduced by eval.
10779 if (function_context->closure() == *function) {
10780 if (function_context->has_extension() &&
10781 !function_context->IsGlobalContext()) {
10782 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010783 bool threw = false;
10784 Handle<FixedArray> keys =
10785 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10786 if (threw) return Handle<JSObject>();
10787
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010788 for (int i = 0; i < keys->length(); i++) {
10789 // Names of variables introduced by eval are strings.
10790 ASSERT(keys->get(i)->IsString());
10791 Handle<String> key(String::cast(keys->get(i)));
10792 RETURN_IF_EMPTY_HANDLE_VALUE(
10793 isolate,
10794 SetProperty(local_scope,
10795 key,
10796 GetProperty(ext, key),
10797 NONE,
10798 kNonStrictMode),
10799 Handle<JSObject>());
10800 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010801 }
10802 }
10803 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010804
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010805 return local_scope;
10806}
10807
10808
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010809static Handle<JSObject> MaterializeLocalScope(
10810 Isolate* isolate,
10811 JavaScriptFrame* frame,
10812 int inlined_jsframe_index) {
10813 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10814 return MaterializeLocalScopeWithFrameInspector(isolate,
10815 frame,
10816 &frame_inspector);
10817}
10818
10819
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010820// Create a plain JSObject which materializes the closure content for the
10821// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10823 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010824 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010825
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010826 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010827 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010828
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010829 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010830 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 Handle<JSObject> closure_scope =
10832 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010833
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010834 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010835 if (!CopyContextLocalsToScopeObject(
10836 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010837 return Handle<JSObject>();
10838 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010839
10840 // Finally copy any properties from the function context extension. This will
10841 // be variables introduced by eval.
10842 if (context->has_extension()) {
10843 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010844 bool threw = false;
10845 Handle<FixedArray> keys =
10846 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10847 if (threw) return Handle<JSObject>();
10848
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010849 for (int i = 0; i < keys->length(); i++) {
10850 // Names of variables introduced by eval are strings.
10851 ASSERT(keys->get(i)->IsString());
10852 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 RETURN_IF_EMPTY_HANDLE_VALUE(
10854 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010855 SetProperty(closure_scope,
10856 key,
10857 GetProperty(ext, key),
10858 NONE,
10859 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010860 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010861 }
10862 }
10863
10864 return closure_scope;
10865}
10866
10867
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010868// Create a plain JSObject which materializes the scope for the specified
10869// catch context.
10870static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10871 Handle<Context> context) {
10872 ASSERT(context->IsCatchContext());
10873 Handle<String> name(String::cast(context->extension()));
10874 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10875 Handle<JSObject> catch_scope =
10876 isolate->factory()->NewJSObject(isolate->object_function());
10877 RETURN_IF_EMPTY_HANDLE_VALUE(
10878 isolate,
10879 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10880 Handle<JSObject>());
10881 return catch_scope;
10882}
10883
10884
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010885// Create a plain JSObject which materializes the block scope for the specified
10886// block context.
10887static Handle<JSObject> MaterializeBlockScope(
10888 Isolate* isolate,
10889 Handle<Context> context) {
10890 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010891 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010892
10893 // Allocate and initialize a JSObject with all the arguments, stack locals
10894 // heap locals and extension properties of the debugged function.
10895 Handle<JSObject> block_scope =
10896 isolate->factory()->NewJSObject(isolate->object_function());
10897
10898 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010899 if (!CopyContextLocalsToScopeObject(
10900 isolate, scope_info, context, block_scope)) {
10901 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010902 }
10903
10904 return block_scope;
10905}
10906
10907
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010908// Create a plain JSObject which materializes the module scope for the specified
10909// module context.
10910static Handle<JSObject> MaterializeModuleScope(
10911 Isolate* isolate,
10912 Handle<Context> context) {
10913 ASSERT(context->IsModuleContext());
10914 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10915
10916 // Allocate and initialize a JSObject with all the members of the debugged
10917 // module.
10918 Handle<JSObject> module_scope =
10919 isolate->factory()->NewJSObject(isolate->object_function());
10920
10921 // Fill all context locals.
10922 if (!CopyContextLocalsToScopeObject(
10923 isolate, scope_info, context, module_scope)) {
10924 return Handle<JSObject>();
10925 }
10926
10927 return module_scope;
10928}
10929
10930
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010931// Iterate over the actual scopes visible from a stack frame. The iteration
10932// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010933// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010934// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010935class ScopeIterator {
10936 public:
10937 enum ScopeType {
10938 ScopeTypeGlobal = 0,
10939 ScopeTypeLocal,
10940 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010941 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010942 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010943 ScopeTypeBlock,
10944 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010945 };
10946
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010947 ScopeIterator(Isolate* isolate,
10948 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010949 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 : isolate_(isolate),
10951 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010952 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010953 function_(JSFunction::cast(frame->function())),
10954 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010955 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010956
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010957 // Catch the case when the debugger stops in an internal function.
10958 Handle<SharedFunctionInfo> shared_info(function_->shared());
10959 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10960 if (shared_info->script() == isolate->heap()->undefined_value()) {
10961 while (context_->closure() == *function_) {
10962 context_ = Handle<Context>(context_->previous(), isolate_);
10963 }
10964 return;
10965 }
10966
10967 // Get the debug info (create it if it does not exist).
10968 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10969 // Return if ensuring debug info failed.
10970 return;
10971 }
10972 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10973
10974 // Find the break point where execution has stopped.
10975 BreakLocationIterator break_location_iterator(debug_info,
10976 ALL_BREAK_LOCATIONS);
10977 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10978 if (break_location_iterator.IsExit()) {
10979 // We are within the return sequence. At the momemt it is not possible to
10980 // get a source position which is consistent with the current scope chain.
10981 // Thus all nested with, catch and block contexts are skipped and we only
10982 // provide the function scope.
10983 if (scope_info->HasContext()) {
10984 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10985 } else {
10986 while (context_->closure() == *function_) {
10987 context_ = Handle<Context>(context_->previous(), isolate_);
10988 }
10989 }
10990 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10991 } else {
10992 // Reparse the code and analyze the scopes.
10993 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
10994 Handle<Script> script(Script::cast(shared_info->script()));
10995 Scope* scope = NULL;
10996
10997 // Check whether we are in global, eval or function code.
10998 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10999 if (scope_info->Type() != FUNCTION_SCOPE) {
11000 // Global or eval code.
11001 CompilationInfo info(script);
11002 if (scope_info->Type() == GLOBAL_SCOPE) {
11003 info.MarkAsGlobal();
11004 } else {
11005 ASSERT(scope_info->Type() == EVAL_SCOPE);
11006 info.MarkAsEval();
11007 info.SetCallingContext(Handle<Context>(function_->context()));
11008 }
11009 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11010 scope = info.function()->scope();
11011 }
11012 } else {
11013 // Function code
11014 CompilationInfo info(shared_info);
11015 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11016 scope = info.function()->scope();
11017 }
11018 }
11019
11020 // Retrieve the scope chain for the current position.
11021 if (scope != NULL) {
11022 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11023 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11024 } else {
11025 // A failed reparse indicates that the preparser has diverged from the
11026 // parser or that the preparse data given to the initial parse has been
11027 // faulty. We fail in debug mode but in release mode we only provide the
11028 // information we get from the context chain but nothing about
11029 // completely stack allocated scopes or stack allocated locals.
11030 UNREACHABLE();
11031 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011032 }
11033 }
11034
11035 // More scopes?
11036 bool Done() { return context_.is_null(); }
11037
11038 // Move to the next scope.
11039 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011040 ScopeType scope_type = Type();
11041 if (scope_type == ScopeTypeGlobal) {
11042 // The global scope is always the last in the chain.
11043 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011044 context_ = Handle<Context>();
11045 return;
11046 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011047 if (nested_scope_chain_.is_empty()) {
11048 context_ = Handle<Context>(context_->previous(), isolate_);
11049 } else {
11050 if (nested_scope_chain_.last()->HasContext()) {
11051 ASSERT(context_->previous() != NULL);
11052 context_ = Handle<Context>(context_->previous(), isolate_);
11053 }
11054 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011055 }
11056 }
11057
11058 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011059 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011060 if (!nested_scope_chain_.is_empty()) {
11061 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11062 switch (scope_info->Type()) {
11063 case FUNCTION_SCOPE:
11064 ASSERT(context_->IsFunctionContext() ||
11065 !scope_info->HasContext());
11066 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011067 case MODULE_SCOPE:
11068 ASSERT(context_->IsModuleContext());
11069 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011070 case GLOBAL_SCOPE:
11071 ASSERT(context_->IsGlobalContext());
11072 return ScopeTypeGlobal;
11073 case WITH_SCOPE:
11074 ASSERT(context_->IsWithContext());
11075 return ScopeTypeWith;
11076 case CATCH_SCOPE:
11077 ASSERT(context_->IsCatchContext());
11078 return ScopeTypeCatch;
11079 case BLOCK_SCOPE:
11080 ASSERT(!scope_info->HasContext() ||
11081 context_->IsBlockContext());
11082 return ScopeTypeBlock;
11083 case EVAL_SCOPE:
11084 UNREACHABLE();
11085 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011086 }
11087 if (context_->IsGlobalContext()) {
11088 ASSERT(context_->global()->IsGlobalObject());
11089 return ScopeTypeGlobal;
11090 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011091 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011092 return ScopeTypeClosure;
11093 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011094 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011095 return ScopeTypeCatch;
11096 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011097 if (context_->IsBlockContext()) {
11098 return ScopeTypeBlock;
11099 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011100 if (context_->IsModuleContext()) {
11101 return ScopeTypeModule;
11102 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011103 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011104 return ScopeTypeWith;
11105 }
11106
11107 // Return the JavaScript object with the content of the current scope.
11108 Handle<JSObject> ScopeObject() {
11109 switch (Type()) {
11110 case ScopeIterator::ScopeTypeGlobal:
11111 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 case ScopeIterator::ScopeTypeLocal:
11113 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011114 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011115 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011116 case ScopeIterator::ScopeTypeWith:
11117 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011118 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11119 case ScopeIterator::ScopeTypeCatch:
11120 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 case ScopeIterator::ScopeTypeClosure:
11122 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011124 case ScopeIterator::ScopeTypeBlock:
11125 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011126 case ScopeIterator::ScopeTypeModule:
11127 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128 }
11129 UNREACHABLE();
11130 return Handle<JSObject>();
11131 }
11132
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011133 Handle<ScopeInfo> CurrentScopeInfo() {
11134 if (!nested_scope_chain_.is_empty()) {
11135 return nested_scope_chain_.last();
11136 } else if (context_->IsBlockContext()) {
11137 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11138 } else if (context_->IsFunctionContext()) {
11139 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11140 }
11141 return Handle<ScopeInfo>::null();
11142 }
11143
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 // Return the context for this scope. For the local context there might not
11145 // be an actual context.
11146 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011147 if (Type() == ScopeTypeGlobal ||
11148 nested_scope_chain_.is_empty()) {
11149 return context_;
11150 } else if (nested_scope_chain_.last()->HasContext()) {
11151 return context_;
11152 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011153 return Handle<Context>();
11154 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011155 }
11156
11157#ifdef DEBUG
11158 // Debug print of the content of the current scope.
11159 void DebugPrint() {
11160 switch (Type()) {
11161 case ScopeIterator::ScopeTypeGlobal:
11162 PrintF("Global:\n");
11163 CurrentContext()->Print();
11164 break;
11165
11166 case ScopeIterator::ScopeTypeLocal: {
11167 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011168 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011169 if (!CurrentContext().is_null()) {
11170 CurrentContext()->Print();
11171 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011172 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011173 if (extension->IsJSContextExtensionObject()) {
11174 extension->Print();
11175 }
11176 }
11177 }
11178 break;
11179 }
11180
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011181 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011182 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011183 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011184 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011186 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011187 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011188 CurrentContext()->extension()->Print();
11189 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011190 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011191
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011192 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 PrintF("Closure:\n");
11194 CurrentContext()->Print();
11195 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011196 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197 if (extension->IsJSContextExtensionObject()) {
11198 extension->Print();
11199 }
11200 }
11201 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202
11203 default:
11204 UNREACHABLE();
11205 }
11206 PrintF("\n");
11207 }
11208#endif
11209
11210 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011211 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011212 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011213 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011214 Handle<JSFunction> function_;
11215 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011216 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217
11218 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11219};
11220
11221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011222RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011223 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011224 ASSERT(args.length() == 2);
11225
11226 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011227 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011228 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11229 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011230 if (!maybe_check->ToObject(&check)) return maybe_check;
11231 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011232 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011233
11234 // Get the frame where the debugging is performed.
11235 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011236 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011237 JavaScriptFrame* frame = it.frame();
11238
11239 // Count the visible scopes.
11240 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011241 for (ScopeIterator it(isolate, frame, 0);
11242 !it.Done();
11243 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011244 n++;
11245 }
11246
11247 return Smi::FromInt(n);
11248}
11249
11250
11251static const int kScopeDetailsTypeIndex = 0;
11252static const int kScopeDetailsObjectIndex = 1;
11253static const int kScopeDetailsSize = 2;
11254
11255// Return an array with scope details
11256// args[0]: number: break id
11257// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011258// args[2]: number: inlined frame index
11259// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011260//
11261// The array returned contains the following information:
11262// 0: Scope type
11263// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011264RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011266 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011267
11268 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011269 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011270 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11271 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011272 if (!maybe_check->ToObject(&check)) return maybe_check;
11273 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011274 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011275 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011276 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011277
11278 // Get the frame where the debugging is performed.
11279 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011280 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011281 JavaScriptFrame* frame = frame_it.frame();
11282
11283 // Find the requested scope.
11284 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011285 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011286 for (; !it.Done() && n < index; it.Next()) {
11287 n++;
11288 }
11289 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011290 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011291 }
11292
11293 // Calculate the size of the result.
11294 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011295 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011296
11297 // Fill in scope details.
11298 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011299 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011300 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011301 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011304}
11305
11306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011307RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011308 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011309 ASSERT(args.length() == 0);
11310
11311#ifdef DEBUG
11312 // Print the scopes for the top frame.
11313 StackFrameLocator locator;
11314 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011315 for (ScopeIterator it(isolate, frame, 0);
11316 !it.Done();
11317 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011318 it.DebugPrint();
11319 }
11320#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011321 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322}
11323
11324
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011325RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011327 ASSERT(args.length() == 1);
11328
11329 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011330 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011331 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11332 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011333 if (!maybe_result->ToObject(&result)) return maybe_result;
11334 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011335
11336 // Count all archived V8 threads.
11337 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011338 for (ThreadState* thread =
11339 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011340 thread != NULL;
11341 thread = thread->Next()) {
11342 n++;
11343 }
11344
11345 // Total number of threads is current thread and archived threads.
11346 return Smi::FromInt(n + 1);
11347}
11348
11349
11350static const int kThreadDetailsCurrentThreadIndex = 0;
11351static const int kThreadDetailsThreadIdIndex = 1;
11352static const int kThreadDetailsSize = 2;
11353
11354// Return an array with thread details
11355// args[0]: number: break id
11356// args[1]: number: thread index
11357//
11358// The array returned contains the following information:
11359// 0: Is current thread?
11360// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011361RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011362 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011363 ASSERT(args.length() == 2);
11364
11365 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011366 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011367 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11368 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011369 if (!maybe_check->ToObject(&check)) return maybe_check;
11370 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011371 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11372
11373 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 Handle<FixedArray> details =
11375 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011376
11377 // Thread index 0 is current thread.
11378 if (index == 0) {
11379 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 details->set(kThreadDetailsCurrentThreadIndex,
11381 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011382 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011383 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011384 } else {
11385 // Find the thread with the requested index.
11386 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011387 ThreadState* thread =
11388 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011389 while (index != n && thread != NULL) {
11390 thread = thread->Next();
11391 n++;
11392 }
11393 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011395 }
11396
11397 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011398 details->set(kThreadDetailsCurrentThreadIndex,
11399 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011400 details->set(kThreadDetailsThreadIdIndex,
11401 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011402 }
11403
11404 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011406}
11407
11408
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011409// Sets the disable break state
11410// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011411RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011413 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011414 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 isolate->debug()->set_disable_break(disable_break);
11416 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011417}
11418
11419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011420RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011422 ASSERT(args.length() == 1);
11423
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011424 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011425 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011426 // Find the number of break points
11427 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011428 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011429 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011430 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011431 Handle<FixedArray>::cast(break_locations));
11432}
11433
11434
11435// Set a break point in a function
11436// args[0]: function
11437// args[1]: number: break source position (within the function source)
11438// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011439RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011441 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011442 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011443 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11445 RUNTIME_ASSERT(source_position >= 0);
11446 Handle<Object> break_point_object_arg = args.at<Object>(2);
11447
11448 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011449 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11450 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011451
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011452 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011453}
11454
11455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11457 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011458 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011459 // Iterate the heap looking for SharedFunctionInfo generated from the
11460 // script. The inner most SharedFunctionInfo containing the source position
11461 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011462 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 // which is found is not compiled it is compiled and the heap is iterated
11464 // again as the compilation might create inner functions from the newly
11465 // compiled function and the actual requested break point might be in one of
11466 // these functions.
11467 bool done = false;
11468 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011469 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011470 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011471 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011472 { // Extra scope for iterator and no-allocation.
11473 isolate->heap()->EnsureHeapIsIterable();
11474 AssertNoAllocation no_alloc_during_heap_iteration;
11475 HeapIterator iterator;
11476 for (HeapObject* obj = iterator.next();
11477 obj != NULL; obj = iterator.next()) {
11478 if (obj->IsSharedFunctionInfo()) {
11479 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11480 if (shared->script() == *script) {
11481 // If the SharedFunctionInfo found has the requested script data and
11482 // contains the source position it is a candidate.
11483 int start_position = shared->function_token_position();
11484 if (start_position == RelocInfo::kNoPosition) {
11485 start_position = shared->start_position();
11486 }
11487 if (start_position <= position &&
11488 position <= shared->end_position()) {
11489 // If there is no candidate or this function is within the current
11490 // candidate this is the new candidate.
11491 if (target.is_null()) {
11492 target_start_position = start_position;
11493 target = shared;
11494 } else {
11495 if (target_start_position == start_position &&
11496 shared->end_position() == target->end_position()) {
11497 // If a top-level function contain only one function
11498 // declartion the source for the top-level and the
11499 // function is the same. In that case prefer the non
11500 // top-level function.
11501 if (!shared->is_toplevel()) {
11502 target_start_position = start_position;
11503 target = shared;
11504 }
11505 } else if (target_start_position <= start_position &&
11506 shared->end_position() <= target->end_position()) {
11507 // This containment check includes equality as a function
11508 // inside a top-level function can share either start or end
11509 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011510 target_start_position = start_position;
11511 target = shared;
11512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011513 }
11514 }
11515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011517 } // End for loop.
11518 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522 }
11523
11524 // If the candidate found is compiled we are done. NOTE: when lazy
11525 // compilation of inner functions is introduced some additional checking
11526 // needs to be done here to compile inner functions.
11527 done = target->is_compiled();
11528 if (!done) {
11529 // If the candidate is not compiled compile it to reveal any inner
11530 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011531 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011533 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011534
11535 return *target;
11536}
11537
11538
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011539// Changes the state of a break point in a script and returns source position
11540// where break point was set. NOTE: Regarding performance see the NOTE for
11541// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542// args[0]: script to set break point in
11543// args[1]: number: break source position (within the script source)
11544// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011545RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011547 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011548 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11550 RUNTIME_ASSERT(source_position >= 0);
11551 Handle<Object> break_point_object_arg = args.at<Object>(2);
11552
11553 // Get the script from the script wrapper.
11554 RUNTIME_ASSERT(wrapper->value()->IsScript());
11555 Handle<Script> script(Script::cast(wrapper->value()));
11556
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011557 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011559 if (!result->IsUndefined()) {
11560 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11561 // Find position within function. The script position might be before the
11562 // source position of the first function.
11563 int position;
11564 if (shared->start_position() > source_position) {
11565 position = 0;
11566 } else {
11567 position = source_position - shared->start_position();
11568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011570 position += shared->start_position();
11571 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011574}
11575
11576
11577// Clear a break point
11578// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011579RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581 ASSERT(args.length() == 1);
11582 Handle<Object> break_point_object_arg = args.at<Object>(0);
11583
11584 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011586
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588}
11589
11590
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011591// Change the state of break on exceptions.
11592// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11593// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011596 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011597 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011598 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011599
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011600 // If the number doesn't match an enum value, the ChangeBreakOnException
11601 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602 ExceptionBreakType type =
11603 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011604 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 isolate->debug()->ChangeBreakOnException(type, enable);
11606 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011607}
11608
11609
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011610// Returns the state of break on exceptions
11611// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011612RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011614 ASSERT(args.length() == 1);
11615 RUNTIME_ASSERT(args[0]->IsNumber());
11616
11617 ExceptionBreakType type =
11618 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011620 return Smi::FromInt(result);
11621}
11622
11623
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011624// Prepare for stepping
11625// args[0]: break id for checking execution state
11626// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011627// args[2]: number of times to perform the step, for step out it is the number
11628// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011629RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 ASSERT(args.length() == 3);
11632 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011633 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011634 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11635 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011636 if (!maybe_check->ToObject(&check)) return maybe_check;
11637 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011638 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011640 }
11641
11642 // Get the step action and check validity.
11643 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11644 if (step_action != StepIn &&
11645 step_action != StepNext &&
11646 step_action != StepOut &&
11647 step_action != StepInMin &&
11648 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011650 }
11651
11652 // Get the number of steps.
11653 int step_count = NumberToInt32(args[2]);
11654 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656 }
11657
ager@chromium.orga1645e22009-09-09 19:27:10 +000011658 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011660
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11663 step_count);
11664 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011665}
11666
11667
11668// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011669RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011671 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 isolate->debug()->ClearStepping();
11673 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011674}
11675
11676
11677// Creates a copy of the with context chain. The copy of the context chain is
11678// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011679static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11680 Handle<JSFunction> function,
11681 Handle<Context> base,
11682 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011683 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011684 HandleScope scope(isolate);
11685 List<Handle<ScopeInfo> > scope_chain;
11686 List<Handle<Context> > context_chain;
11687
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011688 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011689 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11690 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11691 ASSERT(!it.Done());
11692 scope_chain.Add(it.CurrentScopeInfo());
11693 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011694 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011695
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011696 // At the end of the chain. Return the base context to link to.
11697 Handle<Context> context = base;
11698
11699 // Iteratively copy and or materialize the nested contexts.
11700 while (!scope_chain.is_empty()) {
11701 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11702 Handle<Context> current = context_chain.RemoveLast();
11703 ASSERT(!(scope_info->HasContext() & current.is_null()));
11704
11705 if (scope_info->Type() == CATCH_SCOPE) {
11706 Handle<String> name(String::cast(current->extension()));
11707 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11708 context =
11709 isolate->factory()->NewCatchContext(function,
11710 context,
11711 name,
11712 thrown_object);
11713 } else if (scope_info->Type() == BLOCK_SCOPE) {
11714 // Materialize the contents of the block scope into a JSObject.
11715 Handle<JSObject> block_scope_object =
11716 MaterializeBlockScope(isolate, current);
11717 if (block_scope_object.is_null()) {
11718 return Handle<Context>::null();
11719 }
11720 // Allocate a new function context for the debug evaluation and set the
11721 // extension object.
11722 Handle<Context> new_context =
11723 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11724 function);
11725 new_context->set_extension(*block_scope_object);
11726 new_context->set_previous(*context);
11727 context = new_context;
11728 } else {
11729 ASSERT(scope_info->Type() == WITH_SCOPE);
11730 ASSERT(current->IsWithContext());
11731 Handle<JSObject> extension(JSObject::cast(current->extension()));
11732 context =
11733 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011734 }
erikcorry0ad885c2011-11-21 13:51:57 +000011735 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011736
11737 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738}
11739
11740
11741// Helper function to find or create the arguments object for
11742// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743static Handle<Object> GetArgumentsObject(Isolate* isolate,
11744 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011745 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011746 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011747 Handle<Context> function_context) {
11748 // Try to find the value of 'arguments' to pass as parameter. If it is not
11749 // found (that is the debugged function does not reference 'arguments' and
11750 // does not support eval) then create an 'arguments' object.
11751 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011752 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011755 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 }
11757 }
11758
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011759 if (scope_info->HasHeapAllocatedLocals()) {
11760 VariableMode mode;
11761 InitializationFlag init_flag;
11762 index = scope_info->ContextSlotIndex(
11763 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011765 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011766 }
11767 }
11768
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011769 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11770 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 Handle<JSObject> arguments =
11772 isolate->factory()->NewArgumentsObject(function, length);
11773 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011774
11775 AssertNoAllocation no_gc;
11776 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011778 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011779 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011780 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781 return arguments;
11782}
11783
11784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785static const char kSourceStr[] =
11786 "(function(arguments,__source__){return eval(__source__);})";
11787
11788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011790// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011791// extension part has all the parameters and locals of the function on the
11792// stack frame. A function which calls eval with the code to evaluate is then
11793// compiled in this context and called in this context. As this context
11794// replaces the context of the function on the stack frame a new (empty)
11795// function is created as well to be used as the closure for the context.
11796// This function and the context acts as replacements for the function on the
11797// stack frame presenting the same view of the values of parameters and
11798// local variables as if the piece of JavaScript was evaluated at the point
11799// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011800RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011801 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802
11803 // Check the execution state and decode arguments frame and source to be
11804 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011805 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011806 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011807 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11808 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011809 if (!maybe_check_result->ToObject(&check_result)) {
11810 return maybe_check_result;
11811 }
11812 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011813 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011814 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011815 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11816 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011817 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011818
11819 // Handle the processing of break.
11820 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821
11822 // Get the frame where the debugging is performed.
11823 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011824 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011825 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011826 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11827 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011828 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829
11830 // Traverse the saved contexts chain to find the active context for the
11831 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011832 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011834 SaveContext savex(isolate);
11835 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836
11837 // Create the (empty) function replacing the function on the stack frame for
11838 // the purpose of evaluating in the context created below. It is important
11839 // that this function does not describe any parameters and local variables
11840 // in the context. If it does then this will cause problems with the lookup
11841 // in Context::Lookup, where context slots for parameters and local variables
11842 // are looked at before the extension object.
11843 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11845 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 go_between->set_context(function->context());
11847#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011848 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11849 ASSERT(go_between_scope_info->ParameterCount() == 0);
11850 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851#endif
11852
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011853 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011854 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11855 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857
11858 // Allocate a new context for the debug evaluation and set the extension
11859 // object build.
11860 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11862 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011863 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011865 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011866 Handle<Context> function_context;
11867 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011868 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011869 function_context = Handle<Context>(frame_context->declaration_context());
11870 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011871 context = CopyNestedScopeContextChain(isolate,
11872 go_between,
11873 context,
11874 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011875 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011877 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011878 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011879 context =
11880 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011881 }
11882
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 // Wrap the evaluation statement in a new function compiled in the newly
11884 // created context. The function has one parameter which has to be called
11885 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011886 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011887 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 isolate->factory()->NewStringFromAscii(
11891 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011892
11893 // Currently, the eval code will be executed in non-strict mode,
11894 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011895 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011896 Compiler::CompileEval(function_source,
11897 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011898 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011899 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011900 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011901 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904
11905 // Invoke the result of the compilation to get the evaluation function.
11906 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011907 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011908 Handle<Object> evaluation_function =
11909 Execution::Call(compiled_function, receiver, 0, NULL,
11910 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011911 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011913 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011914 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011915 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011916 scope_info,
11917 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918
11919 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011920 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011922 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11923 receiver,
11924 ARRAY_SIZE(argv),
11925 argv,
11926 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011927 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011928
11929 // Skip the global proxy as it has no properties and always delegates to the
11930 // real global object.
11931 if (result->IsJSGlobalProxy()) {
11932 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11933 }
11934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 return *result;
11936}
11937
11938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011939RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011941
11942 // Check the execution state and decode arguments frame and source to be
11943 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011944 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011945 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011946 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11947 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011948 if (!maybe_check_result->ToObject(&check_result)) {
11949 return maybe_check_result;
11950 }
11951 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011952 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11953 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011954 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011955
11956 // Handle the processing of break.
11957 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958
11959 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963 top = top->prev();
11964 }
11965 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011967 }
11968
11969 // Get the global context now set to the top context from before the
11970 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011971 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011972
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011973 bool is_global = true;
11974
11975 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011976 // Create a new with context with the additional context information between
11977 // the context of the debugged function and the eval code to be executed.
11978 context = isolate->factory()->NewWithContext(
11979 Handle<JSFunction>(context->closure()),
11980 context,
11981 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011982 is_global = false;
11983 }
11984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011985 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011986 // Currently, the eval code will be executed in non-strict mode,
11987 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011988 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011989 Compiler::CompileEval(source,
11990 context,
11991 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011992 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011993 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011994 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011996 Handle<JSFunction>(
11997 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11998 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011999
12000 // Invoke the result of the compilation to get the evaluation function.
12001 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012003 Handle<Object> result =
12004 Execution::Call(compiled_function, receiver, 0, NULL,
12005 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012006 // Clear the oneshot breakpoints so that the debugger does not step further.
12007 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012008 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012009 return *result;
12010}
12011
12012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012013RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012014 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012015 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019
12020 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012021 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012022 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12023 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12024 // because using
12025 // instances->set(i, *GetScriptWrapper(script))
12026 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012027 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012028 Handle<JSValue> wrapper = GetScriptWrapper(script);
12029 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012030 }
12031
12032 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012033 Handle<JSObject> result =
12034 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012035 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036 return *result;
12037}
12038
12039
12040// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012041static int DebugReferencedBy(HeapIterator* iterator,
12042 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043 Object* instance_filter, int max_references,
12044 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045 JSFunction* arguments_function) {
12046 NoHandleAllocation ha;
12047 AssertNoAllocation no_alloc;
12048
12049 // Iterate the heap.
12050 int count = 0;
12051 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012052 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012053 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054 (max_references == 0 || count < max_references)) {
12055 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 if (heap_obj->IsJSObject()) {
12057 // Skip context extension objects and argument arrays as these are
12058 // checked in the context of functions using them.
12059 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012060 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 obj->map()->constructor() == arguments_function) {
12062 continue;
12063 }
12064
12065 // Check if the JS object has a reference to the object looked for.
12066 if (obj->ReferencesObject(target)) {
12067 // Check instance filter if supplied. This is normally used to avoid
12068 // references from mirror objects (see Runtime_IsInPrototypeChain).
12069 if (!instance_filter->IsUndefined()) {
12070 Object* V = obj;
12071 while (true) {
12072 Object* prototype = V->GetPrototype();
12073 if (prototype->IsNull()) {
12074 break;
12075 }
12076 if (instance_filter == prototype) {
12077 obj = NULL; // Don't add this object.
12078 break;
12079 }
12080 V = prototype;
12081 }
12082 }
12083
12084 if (obj != NULL) {
12085 // Valid reference found add to instance array if supplied an update
12086 // count.
12087 if (instances != NULL && count < instances_size) {
12088 instances->set(count, obj);
12089 }
12090 last = obj;
12091 count++;
12092 }
12093 }
12094 }
12095 }
12096
12097 // Check for circular reference only. This can happen when the object is only
12098 // referenced from mirrors and has a circular reference in which case the
12099 // object is not really alive and would have been garbage collected if not
12100 // referenced from the mirror.
12101 if (count == 1 && last == target) {
12102 count = 0;
12103 }
12104
12105 // Return the number of referencing objects found.
12106 return count;
12107}
12108
12109
12110// Scan the heap for objects with direct references to an object
12111// args[0]: the object to find references to
12112// args[1]: constructor function for instances to exclude (Mirror)
12113// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012114RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 ASSERT(args.length() == 3);
12116
12117 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012118 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12119 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012120 // The heap iterator reserves the right to do a GC to make the heap iterable.
12121 // Due to the GC above we know it won't need to do that, but it seems cleaner
12122 // to get the heap iterator constructed before we start having unprotected
12123 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124
12125 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012126 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127 Object* instance_filter = args[1];
12128 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12129 instance_filter->IsJSObject());
12130 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12131 RUNTIME_ASSERT(max_references >= 0);
12132
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012136 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137 JSFunction* arguments_function =
12138 JSFunction::cast(arguments_boilerplate->map()->constructor());
12139
12140 // Get the number of referencing objects.
12141 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012142 HeapIterator heap_iterator;
12143 count = DebugReferencedBy(&heap_iterator,
12144 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012145 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012146
12147 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012148 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012149 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012150 if (!maybe_object->ToObject(&object)) return maybe_object;
12151 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152 FixedArray* instances = FixedArray::cast(object);
12153
12154 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012155 // AllocateFixedArray above does not make the heap non-iterable.
12156 ASSERT(HEAP->IsHeapIterable());
12157 HeapIterator heap_iterator2;
12158 count = DebugReferencedBy(&heap_iterator2,
12159 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012160 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161
12162 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012163 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012164 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012166 if (!maybe_result->ToObject(&result)) return maybe_result;
12167 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168}
12169
12170
12171// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012172static int DebugConstructedBy(HeapIterator* iterator,
12173 JSFunction* constructor,
12174 int max_references,
12175 FixedArray* instances,
12176 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177 AssertNoAllocation no_alloc;
12178
12179 // Iterate the heap.
12180 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012181 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012182 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183 (max_references == 0 || count < max_references)) {
12184 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185 if (heap_obj->IsJSObject()) {
12186 JSObject* obj = JSObject::cast(heap_obj);
12187 if (obj->map()->constructor() == constructor) {
12188 // Valid reference found add to instance array if supplied an update
12189 // count.
12190 if (instances != NULL && count < instances_size) {
12191 instances->set(count, obj);
12192 }
12193 count++;
12194 }
12195 }
12196 }
12197
12198 // Return the number of referencing objects found.
12199 return count;
12200}
12201
12202
12203// Scan the heap for objects constructed by a specific function.
12204// args[0]: the constructor to find instances of
12205// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012206RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207 ASSERT(args.length() == 2);
12208
12209 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012210 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12211 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012212
12213 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012214 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12216 RUNTIME_ASSERT(max_references >= 0);
12217
12218 // Get the number of referencing objects.
12219 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012220 HeapIterator heap_iterator;
12221 count = DebugConstructedBy(&heap_iterator,
12222 constructor,
12223 max_references,
12224 NULL,
12225 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012226
12227 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012228 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012229 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012230 if (!maybe_object->ToObject(&object)) return maybe_object;
12231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 FixedArray* instances = FixedArray::cast(object);
12233
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012234 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012236 HeapIterator heap_iterator2;
12237 count = DebugConstructedBy(&heap_iterator2,
12238 constructor,
12239 max_references,
12240 instances,
12241 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242
12243 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012244 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012245 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12246 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012247 if (!maybe_result->ToObject(&result)) return maybe_result;
12248 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012249 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250}
12251
12252
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012253// Find the effective prototype object as returned by __proto__.
12254// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012255RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012256 ASSERT(args.length() == 1);
12257
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012258 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012260 // Use the __proto__ accessor.
12261 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262}
12263
12264
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012265// Patches script source (should be called upon BeforeCompile event).
12266RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12267 HandleScope scope(isolate);
12268 ASSERT(args.length() == 2);
12269
12270 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12271 Handle<String> source(String::cast(args[1]));
12272
12273 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12274 Handle<Script> script(Script::cast(script_wrapper->value()));
12275
12276 int compilation_state = Smi::cast(script->compilation_state())->value();
12277 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12278 script->set_source(*source);
12279
12280 return isolate->heap()->undefined_value();
12281}
12282
12283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012284RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012285 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012286 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012287 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288}
12289
12290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012291RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012292#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012293 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012294 ASSERT(args.length() == 1);
12295 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012296 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012297 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012298 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012299 return Failure::Exception();
12300 }
12301 func->code()->PrintLn();
12302#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012303 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012304}
ager@chromium.org9085a012009-05-11 19:22:57 +000012305
12306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012307RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012308#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012309 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012310 ASSERT(args.length() == 1);
12311 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012312 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012313 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012314 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012315 return Failure::Exception();
12316 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012317 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012318#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012319 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012320}
12321
12322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012323RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012324 NoHandleAllocation ha;
12325 ASSERT(args.length() == 1);
12326
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012327 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012328 return f->shared()->inferred_name();
12329}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012330
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012331
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012332static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12333 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012334 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012335 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012336 int counter = 0;
12337 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012338 for (HeapObject* obj = iterator->next();
12339 obj != NULL;
12340 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012341 ASSERT(obj != NULL);
12342 if (!obj->IsSharedFunctionInfo()) {
12343 continue;
12344 }
12345 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12346 if (shared->script() != script) {
12347 continue;
12348 }
12349 if (counter < buffer_size) {
12350 buffer->set(counter, shared);
12351 }
12352 counter++;
12353 }
12354 return counter;
12355}
12356
12357// For a script finds all SharedFunctionInfo's in the heap that points
12358// to this script. Returns JSArray of SharedFunctionInfo wrapped
12359// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012360RUNTIME_FUNCTION(MaybeObject*,
12361 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012362 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012364 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012365
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012366
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012367 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12368
12369 const int kBufferSize = 32;
12370
12371 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012372 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012373 int number;
12374 {
12375 isolate->heap()->EnsureHeapIsIterable();
12376 AssertNoAllocation no_allocations;
12377 HeapIterator heap_iterator;
12378 Script* scr = *script;
12379 FixedArray* arr = *array;
12380 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12381 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012382 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012383 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384 isolate->heap()->EnsureHeapIsIterable();
12385 AssertNoAllocation no_allocations;
12386 HeapIterator heap_iterator;
12387 Script* scr = *script;
12388 FixedArray* arr = *array;
12389 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012390 }
12391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012392 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012393 result->set_length(Smi::FromInt(number));
12394
12395 LiveEdit::WrapSharedFunctionInfos(result);
12396
12397 return *result;
12398}
12399
12400// For a script calculates compilation information about all its functions.
12401// The script source is explicitly specified by the second argument.
12402// The source of the actual script is not used, however it is important that
12403// all generated code keeps references to this particular instance of script.
12404// Returns a JSArray of compilation infos. The array is ordered so that
12405// each function with all its descendant is always stored in a continues range
12406// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012407RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012408 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012409 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012410 CONVERT_ARG_CHECKED(JSValue, script, 0);
12411 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012412 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12413
12414 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012417 return Failure::Exception();
12418 }
12419
12420 return result;
12421}
12422
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012423// Changes the source of the script to a new_source.
12424// If old_script_name is provided (i.e. is a String), also creates a copy of
12425// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012426RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012427 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012428 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012429 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12430 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012432
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012433 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12434 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012436 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12437 new_source,
12438 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012440 if (old_script->IsScript()) {
12441 Handle<Script> script_handle(Script::cast(old_script));
12442 return *(GetScriptWrapper(script_handle));
12443 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012445 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012446}
12447
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012449RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012450 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012452 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012453 return LiveEdit::FunctionSourceUpdated(shared_info);
12454}
12455
12456
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012457// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012458RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012459 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012460 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012461 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12462 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012463
ager@chromium.orgac091b72010-05-05 07:34:42 +000012464 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012465}
12466
12467// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012468RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012469 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 HandleScope scope(isolate);
12471 Handle<Object> function_object(args[0], isolate);
12472 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012473
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012474 if (function_object->IsJSValue()) {
12475 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12476 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012477 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12478 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012480 }
12481
12482 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12483 } else {
12484 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12485 // and we check it in this function.
12486 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012488 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012489}
12490
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012491
12492// In a code of a parent function replaces original function as embedded object
12493// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012494RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012495 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012496 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012497
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012498 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12499 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12500 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012501
12502 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12503 subst_wrapper);
12504
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012505 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012506}
12507
12508
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012509// Updates positions of a shared function info (first parameter) according
12510// to script source change. Text change is described in second parameter as
12511// array of groups of 3 numbers:
12512// (change_begin, change_end, change_end_new_position).
12513// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012514RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012515 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012517 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12518 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012519
ager@chromium.orgac091b72010-05-05 07:34:42 +000012520 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012521}
12522
12523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012524// For array of SharedFunctionInfo's (each wrapped in JSValue)
12525// checks that none of them have activations on stacks (of any thread).
12526// Returns array of the same length with corresponding results of
12527// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012528RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012529 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012530 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012531 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12532 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012533
ager@chromium.org357bf652010-04-12 11:30:10 +000012534 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012535}
12536
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012537// Compares 2 strings line-by-line, then token-wise and returns diff in form
12538// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12539// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012540RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012541 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012542 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012543 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12544 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012545
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012546 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012547}
12548
12549
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012550// A testing entry. Returns statement position which is the closest to
12551// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012553 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012554 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012555 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012556 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012559
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012560 if (code->kind() != Code::FUNCTION &&
12561 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012563 }
12564
12565 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012566 int closest_pc = 0;
12567 int distance = kMaxInt;
12568 while (!it.done()) {
12569 int statement_position = static_cast<int>(it.rinfo()->data());
12570 // Check if this break point is closer that what was previously found.
12571 if (source_position <= statement_position &&
12572 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012573 closest_pc =
12574 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012575 distance = statement_position - source_position;
12576 // Check whether we can't get any closer.
12577 if (distance == 0) break;
12578 }
12579 it.next();
12580 }
12581
12582 return Smi::FromInt(closest_pc);
12583}
12584
12585
ager@chromium.org357bf652010-04-12 11:30:10 +000012586// Calls specified function with or without entering the debugger.
12587// This is used in unit tests to run code as if debugger is entered or simply
12588// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012589RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012590 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012591 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012592 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12593 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012594
12595 Handle<Object> result;
12596 bool pending_exception;
12597 {
12598 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012599 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012600 &pending_exception);
12601 } else {
12602 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012604 &pending_exception);
12605 }
12606 }
12607 if (!pending_exception) {
12608 return *result;
12609 } else {
12610 return Failure::Exception();
12611 }
12612}
12613
12614
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012615// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012616RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012617 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012618 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012619 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12620 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012621 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012622}
12623
12624
12625// Performs a GC.
12626// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012627RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012628 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012629 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012630}
12631
12632
12633// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012634RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012635 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012636 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012638 }
12639 return Smi::FromInt(usage);
12640}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012641
12642
12643// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012644RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012645#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012647#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012648 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649#endif
12650}
12651
12652
12653// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012654RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012655#ifdef LIVE_OBJECT_LIST
12656 return LiveObjectList::Capture();
12657#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012659#endif
12660}
12661
12662
12663// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012664RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012665#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012666 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012667 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012668 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012669#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012671#endif
12672}
12673
12674
12675// Generates the response to a debugger request for a dump of the objects
12676// contained in the difference between the captured live object lists
12677// specified by id1 and id2.
12678// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12679// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012680RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012681#ifdef LIVE_OBJECT_LIST
12682 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012683 CONVERT_SMI_ARG_CHECKED(id1, 0);
12684 CONVERT_SMI_ARG_CHECKED(id2, 1);
12685 CONVERT_SMI_ARG_CHECKED(start, 2);
12686 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012687 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012688 EnterDebugger enter_debugger;
12689 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12690#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012691 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012692#endif
12693}
12694
12695
12696// Gets the specified object as requested by the debugger.
12697// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012698RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012699#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012700 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012701 Object* result = LiveObjectList::GetObj(obj_id);
12702 return result;
12703#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012705#endif
12706}
12707
12708
12709// Gets the obj id for the specified address if valid.
12710// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#ifdef LIVE_OBJECT_LIST
12713 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012714 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012715 Object* result = LiveObjectList::GetObjId(address);
12716 return result;
12717#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012718 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012719#endif
12720}
12721
12722
12723// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012724RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012725#ifdef LIVE_OBJECT_LIST
12726 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012727 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012728 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12729 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12730 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12731 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012732 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012733
12734 Handle<JSObject> instance_filter;
12735 if (args[1]->IsJSObject()) {
12736 instance_filter = args.at<JSObject>(1);
12737 }
12738 bool verbose = false;
12739 if (args[2]->IsBoolean()) {
12740 verbose = args[2]->IsTrue();
12741 }
12742 int start = 0;
12743 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012744 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012745 }
12746 int limit = Smi::kMaxValue;
12747 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012748 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012749 }
12750
12751 return LiveObjectList::GetObjRetainers(obj_id,
12752 instance_filter,
12753 verbose,
12754 start,
12755 limit,
12756 filter_obj);
12757#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012758 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012759#endif
12760}
12761
12762
12763// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012765#ifdef LIVE_OBJECT_LIST
12766 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012767 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12768 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012769 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12770
12771 Handle<JSObject> instance_filter;
12772 if (args[2]->IsJSObject()) {
12773 instance_filter = args.at<JSObject>(2);
12774 }
12775
12776 Object* result =
12777 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12778 return result;
12779#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012780 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012781#endif
12782}
12783
12784
12785// Generates the response to a debugger request for a list of all
12786// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012787RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012788#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012789 CONVERT_SMI_ARG_CHECKED(start, 0);
12790 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012791 return LiveObjectList::Info(start, count);
12792#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012793 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012794#endif
12795}
12796
12797
12798// Gets a dump of the specified object as requested by the debugger.
12799// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012800RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012801#ifdef LIVE_OBJECT_LIST
12802 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012803 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804 Object* result = LiveObjectList::PrintObj(obj_id);
12805 return result;
12806#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012807 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012808#endif
12809}
12810
12811
12812// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012814#ifdef LIVE_OBJECT_LIST
12815 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012817#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012818 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012819#endif
12820}
12821
12822
12823// Generates the response to a debugger request for a summary of the types
12824// of objects in the difference between the captured live object lists
12825// specified by id1 and id2.
12826// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12827// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012829#ifdef LIVE_OBJECT_LIST
12830 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012831 CONVERT_SMI_ARG_CHECKED(id1, 0);
12832 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012833 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012834
12835 EnterDebugger enter_debugger;
12836 return LiveObjectList::Summarize(id1, id2, filter_obj);
12837#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012838 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012839#endif
12840}
12841
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012842#endif // ENABLE_DEBUGGER_SUPPORT
12843
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012845RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012846 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012847 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012848 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012849}
12850
12851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012852RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012853 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012854 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012855 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012856}
12857
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012858
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012859// Finds the script object from the script data. NOTE: This operation uses
12860// heap traversal to find the function generated for the source position
12861// for the requested break point. For lazily compiled functions several heap
12862// traversals might be required rendering this operation as a rather slow
12863// operation. However for setting break points which is normally done through
12864// some kind of user interaction the performance is not crucial.
12865static Handle<Object> Runtime_GetScriptFromScriptName(
12866 Handle<String> script_name) {
12867 // Scan the heap for Script objects to find the script with the requested
12868 // script data.
12869 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012870 script_name->GetHeap()->EnsureHeapIsIterable();
12871 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012872 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012873 HeapObject* obj = NULL;
12874 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012875 // If a script is found check if it has the script data requested.
12876 if (obj->IsScript()) {
12877 if (Script::cast(obj)->name()->IsString()) {
12878 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12879 script = Handle<Script>(Script::cast(obj));
12880 }
12881 }
12882 }
12883 }
12884
12885 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012886 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012887
12888 // Return the script found.
12889 return GetScriptWrapper(script);
12890}
12891
12892
12893// Get the script object from script data. NOTE: Regarding performance
12894// see the NOTE for GetScriptFromScriptData.
12895// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012896RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012897 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012898
12899 ASSERT(args.length() == 1);
12900
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012901 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012902
12903 // Find the requested script.
12904 Handle<Object> result =
12905 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12906 return *result;
12907}
12908
12909
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012910// Determines whether the given stack frame should be displayed in
12911// a stack trace. The caller is the error constructor that asked
12912// for the stack trace to be collected. The first time a construct
12913// call to this function is encountered it is skipped. The seen_caller
12914// in/out parameter is used to remember if the caller has been seen
12915// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012916static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12917 Object* caller,
12918 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012919 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012920 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012921 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012922 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012923 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12924 Object* raw_fun = frame->function();
12925 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012926 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012927 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012928 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012929 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012930 *seen_caller = true;
12931 return false;
12932 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012933 // Skip all frames until we've seen the caller.
12934 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012935 // Also, skip non-visible built-in functions and any call with the builtins
12936 // object as receiver, so as to not reveal either the builtins object or
12937 // an internal function.
12938 // The --builtins-in-stack-traces command line flag allows including
12939 // internal call sites in the stack trace for debugging purposes.
12940 if (!FLAG_builtins_in_stack_traces) {
12941 JSFunction* fun = JSFunction::cast(raw_fun);
12942 if (frame->receiver()->IsJSBuiltinsObject() ||
12943 (fun->IsBuiltin() && !fun->shared()->native())) {
12944 return false;
12945 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012946 }
12947 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012948}
12949
12950
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012951// Collect the raw data for a stack trace. Returns an array of 4
12952// element segments each containing a receiver, function, code and
12953// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012954RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012955 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012956 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012957 Handle<Object> caller = args.at<Object>(1);
12958 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012960 HandleScope scope(isolate);
12961 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012962
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012963 limit = Max(limit, 0); // Ensure that limit is not negative.
12964 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012965 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012966 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012967
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012968 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012969 // If the caller parameter is a function we skip frames until we're
12970 // under it before starting to collect.
12971 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012972 int cursor = 0;
12973 int frames_seen = 0;
12974 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012975 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012976 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012977 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012978 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012979 // Set initial size to the maximum inlining level + 1 for the outermost
12980 // function.
12981 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012982 frame->Summarize(&frames);
12983 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012984 if (cursor + 4 > elements->length()) {
12985 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12986 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012987 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012988 for (int i = 0; i < cursor; i++) {
12989 new_elements->set(i, elements->get(i));
12990 }
12991 elements = new_elements;
12992 }
12993 ASSERT(cursor + 4 <= elements->length());
12994
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012995 Handle<Object> recv = frames[i].receiver();
12996 Handle<JSFunction> fun = frames[i].function();
12997 Handle<Code> code = frames[i].code();
12998 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012999 elements->set(cursor++, *recv);
13000 elements->set(cursor++, *fun);
13001 elements->set(cursor++, *code);
13002 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013003 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013004 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013005 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013006 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013007 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013008 // Capture and attach a more detailed stack trace if necessary.
13009 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013010 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013011 return *result;
13012}
13013
13014
ager@chromium.org3811b432009-10-28 14:53:37 +000013015// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013016RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013017 ASSERT_EQ(args.length(), 0);
13018
13019 NoHandleAllocation ha;
13020
13021 const char* version_string = v8::V8::GetVersion();
13022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013023 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13024 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013025}
13026
13027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013028RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013029 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013030 OS::PrintError("abort: %s\n",
13031 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013032 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013033 OS::Abort();
13034 UNREACHABLE();
13035 return NULL;
13036}
13037
13038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013039RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013040 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013041 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013042 Object* key = args[1];
13043
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013044 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013045 Object* o = cache->get(finger_index);
13046 if (o == key) {
13047 // The fastest case: hit the same place again.
13048 return cache->get(finger_index + 1);
13049 }
13050
13051 for (int i = finger_index - 2;
13052 i >= JSFunctionResultCache::kEntriesIndex;
13053 i -= 2) {
13054 o = cache->get(i);
13055 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013056 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013057 return cache->get(i + 1);
13058 }
13059 }
13060
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013061 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013062 ASSERT(size <= cache->length());
13063
13064 for (int i = size - 2; i > finger_index; i -= 2) {
13065 o = cache->get(i);
13066 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013067 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013068 return cache->get(i + 1);
13069 }
13070 }
13071
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013072 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013073 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013074
13075 Handle<JSFunctionResultCache> cache_handle(cache);
13076 Handle<Object> key_handle(key);
13077 Handle<Object> value;
13078 {
13079 Handle<JSFunction> factory(JSFunction::cast(
13080 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13081 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013082 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013083 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013084 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013085 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013086 value = Execution::Call(factory,
13087 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013088 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013089 argv,
13090 &pending_exception);
13091 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013092 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013093
13094#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013095 if (FLAG_verify_heap) {
13096 cache_handle->JSFunctionResultCacheVerify();
13097 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013098#endif
13099
13100 // Function invocation may have cleared the cache. Reread all the data.
13101 finger_index = cache_handle->finger_index();
13102 size = cache_handle->size();
13103
13104 // If we have spare room, put new data into it, otherwise evict post finger
13105 // entry which is likely to be the least recently used.
13106 int index = -1;
13107 if (size < cache_handle->length()) {
13108 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13109 index = size;
13110 } else {
13111 index = finger_index + JSFunctionResultCache::kEntrySize;
13112 if (index == cache_handle->length()) {
13113 index = JSFunctionResultCache::kEntriesIndex;
13114 }
13115 }
13116
13117 ASSERT(index % 2 == 0);
13118 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13119 ASSERT(index < cache_handle->length());
13120
13121 cache_handle->set(index, *key_handle);
13122 cache_handle->set(index + 1, *value);
13123 cache_handle->set_finger_index(index);
13124
13125#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013126 if (FLAG_verify_heap) {
13127 cache_handle->JSFunctionResultCacheVerify();
13128 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013129#endif
13130
13131 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013132}
13133
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013135RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013136 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013137 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13138 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013139 return *isolate->factory()->NewJSMessageObject(
13140 type,
13141 arguments,
13142 0,
13143 0,
13144 isolate->factory()->undefined_value(),
13145 isolate->factory()->undefined_value(),
13146 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013147}
13148
13149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013150RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013151 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013152 return message->type();
13153}
13154
13155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013156RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013157 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013158 return message->arguments();
13159}
13160
13161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013162RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013163 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013164 return Smi::FromInt(message->start_position());
13165}
13166
13167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013168RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013169 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013170 return message->script();
13171}
13172
13173
kasper.lund44510672008-07-25 07:37:58 +000013174#ifdef DEBUG
13175// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13176// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013177RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013178 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013180#define COUNT_ENTRY(Name, argc, ressize) + 1
13181 int entry_count = 0
13182 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13183 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13184 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13185#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013186 Factory* factory = isolate->factory();
13187 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013188 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013189 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013190#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013191 { \
13192 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013193 Handle<String> name; \
13194 /* Inline runtime functions have an underscore in front of the name. */ \
13195 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013196 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013197 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13198 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013199 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013200 Vector<const char>(#Name, StrLength(#Name))); \
13201 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013202 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013203 pair_elements->set(0, *name); \
13204 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013205 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013206 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013207 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013208 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013209 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013210 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013211 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013212 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013213#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013214 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013215 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013216 return *result;
13217}
kasper.lund44510672008-07-25 07:37:58 +000013218#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013219
13220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013221RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013222 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013223 CONVERT_ARG_CHECKED(String, format, 0);
13224 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013225 String::FlatContent format_content = format->GetFlatContent();
13226 RUNTIME_ASSERT(format_content.IsAscii());
13227 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013228 LOGGER->LogRuntime(chars, elms);
13229 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013230}
13231
13232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013233RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013234 UNREACHABLE(); // implemented as macro in the parser
13235 return NULL;
13236}
13237
13238
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013239#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13240 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013241 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013242 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13243 }
13244
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013245ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013246ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13247ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13248ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13249ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13250ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13251ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13252ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13253ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13254ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13255ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13256ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13257ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13258ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13259
13260#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13261
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013262
13263RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13264 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013265 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13266 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013267 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13268}
13269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013270// ----------------------------------------------------------------------------
13271// Implementation of Runtime
13272
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013273#define F(name, number_of_args, result_size) \
13274 { Runtime::k##name, Runtime::RUNTIME, #name, \
13275 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013276
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013277
13278#define I(name, number_of_args, result_size) \
13279 { Runtime::kInline##name, Runtime::INLINE, \
13280 "_" #name, NULL, number_of_args, result_size },
13281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013282static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013283 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013284 INLINE_FUNCTION_LIST(I)
13285 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013286};
13287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013289MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13290 Object* dictionary) {
13291 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013292 ASSERT(dictionary != NULL);
13293 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13294 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013295 Object* name_symbol;
13296 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013297 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013298 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13299 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013300 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013301 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13302 String::cast(name_symbol),
13303 Smi::FromInt(i),
13304 PropertyDetails(NONE, NORMAL));
13305 if (!maybe_dictionary->ToObject(&dictionary)) {
13306 // Non-recoverable failure. Calling code must restart heap
13307 // initialization.
13308 return maybe_dictionary;
13309 }
13310 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013311 }
13312 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013313}
13314
13315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013316const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13317 Heap* heap = name->GetHeap();
13318 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013319 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013320 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013321 int function_index = Smi::cast(smi_index)->value();
13322 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013323 }
13324 return NULL;
13325}
13326
13327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013328const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013329 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13330}
13331
13332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013333void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013334 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013335 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013336 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013337 if (isolate->heap()->new_space()->AddFreshPage()) {
13338 return;
13339 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013340
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013341 // Try to do a garbage collection; ignore it if it fails. The C
13342 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013343 isolate->heap()->CollectGarbage(failure->allocation_space(),
13344 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013345 } else {
13346 // Handle last resort GC and make sure to allow future allocations
13347 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013348 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013349 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13350 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013352}
13353
13354
13355} } // namespace v8::internal