blob: a1e1633331a3b890443ec40b62f19866ac55b04c [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);
4672 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4673#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);
4683 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004684 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4685 FixedDoubleArray* double_array =
4686 FixedDoubleArray::cast(object->elements());
4687 HeapNumber* number = HeapNumber::cast(*value);
4688 double_array->set(store_index, number->Number());
4689 } else {
4690 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4691 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004692 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4693 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004694 FixedArray* object_array =
4695 FixedArray::cast(object->elements());
4696 object_array->set(store_index, *value);
4697 }
4698 return *object;
4699}
4700
4701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702// Set a local property, even if it is READ_ONLY. If the property does not
4703// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004704RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004706 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004707 CONVERT_ARG_CHECKED(JSObject, object, 0);
4708 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004709 // Compute attributes.
4710 PropertyAttributes attributes = NONE;
4711 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004712 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004713 // Only attribute bits should be set.
4714 RUNTIME_ASSERT(
4715 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4716 attributes = static_cast<PropertyAttributes>(unchecked_value);
4717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004719 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004720 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721}
4722
4723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004724RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004726 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004728 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4729 CONVERT_ARG_CHECKED(String, key, 1);
4730 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004731 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004732 ? JSReceiver::STRICT_DELETION
4733 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734}
4735
4736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737static Object* HasLocalPropertyImplementation(Isolate* isolate,
4738 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004739 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004741 // Handle hidden prototypes. If there's a hidden prototype above this thing
4742 // then we have to check it for properties, because they are supposed to
4743 // look like they are on this object.
4744 Handle<Object> proto(object->GetPrototype());
4745 if (proto->IsJSObject() &&
4746 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 return HasLocalPropertyImplementation(isolate,
4748 Handle<JSObject>::cast(proto),
4749 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004750 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004751 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004752}
4753
4754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004755RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 NoHandleAllocation ha;
4757 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004758 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004760 uint32_t index;
4761 const bool key_is_array_index = key->AsArrayIndex(&index);
4762
ager@chromium.org9085a012009-05-11 19:22:57 +00004763 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004765 if (obj->IsJSObject()) {
4766 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004767 // Fast case: either the key is a real named property or it is not
4768 // an array index and there are no interceptors or hidden
4769 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004770 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 Map* map = object->map();
4772 if (!key_is_array_index &&
4773 !map->has_named_interceptor() &&
4774 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4775 return isolate->heap()->false_value();
4776 }
4777 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 HandleScope scope(isolate);
4779 return HasLocalPropertyImplementation(isolate,
4780 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004781 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004782 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004784 String* string = String::cast(obj);
4785 if (index < static_cast<uint32_t>(string->length())) {
4786 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 }
4788 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004789 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004793RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 NoHandleAllocation na;
4795 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004796 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4797 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004799 bool result = receiver->HasProperty(key);
4800 if (isolate->has_pending_exception()) return Failure::Exception();
4801 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802}
4803
4804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004805RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 NoHandleAllocation na;
4807 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004808 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4809 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004811 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004812 if (isolate->has_pending_exception()) return Failure::Exception();
4813 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814}
4815
4816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004817RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 NoHandleAllocation ha;
4819 ASSERT(args.length() == 2);
4820
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004821 CONVERT_ARG_CHECKED(JSObject, object, 0);
4822 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823
4824 uint32_t index;
4825 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004826 JSObject::LocalElementType type = object->HasLocalElement(index);
4827 switch (type) {
4828 case JSObject::UNDEFINED_ELEMENT:
4829 case JSObject::STRING_CHARACTER_ELEMENT:
4830 return isolate->heap()->false_value();
4831 case JSObject::INTERCEPTED_ELEMENT:
4832 case JSObject::FAST_ELEMENT:
4833 return isolate->heap()->true_value();
4834 case JSObject::DICTIONARY_ELEMENT: {
4835 if (object->IsJSGlobalProxy()) {
4836 Object* proto = object->GetPrototype();
4837 if (proto->IsNull()) {
4838 return isolate->heap()->false_value();
4839 }
4840 ASSERT(proto->IsJSGlobalObject());
4841 object = JSObject::cast(proto);
4842 }
4843 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004844 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004845 if (elements->map() ==
4846 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004847 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004848 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004849 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004850 }
4851 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004852 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004853 PropertyDetails details = dictionary->DetailsAt(entry);
4854 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4855 }
4856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 }
4858
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004860 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861}
4862
4863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004868 bool threw = false;
4869 Handle<JSArray> result = GetKeysFor(object, &threw);
4870 if (threw) return Failure::Exception();
4871 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872}
4873
4874
4875// Returns either a FixedArray as Runtime_GetPropertyNames,
4876// or, if the given object has an enum cache that contains
4877// all enumerable properties of the object and its prototypes
4878// have none, the map of the object. This is used to speed up
4879// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004880RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 ASSERT(args.length() == 1);
4882
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004883 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884
4885 if (raw_object->IsSimpleEnum()) return raw_object->map();
4886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004887 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004888 Handle<JSReceiver> object(raw_object);
4889 bool threw = false;
4890 Handle<FixedArray> content =
4891 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4892 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 // Test again, since cache may have been built by preceding call.
4895 if (object->IsSimpleEnum()) return object->map();
4896
4897 return *content;
4898}
4899
4900
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004901// Find the length of the prototype chain that is to to handled as one. If a
4902// prototype object is hidden it is to be viewed as part of the the object it
4903// is prototype for.
4904static int LocalPrototypeChainLength(JSObject* obj) {
4905 int count = 1;
4906 Object* proto = obj->GetPrototype();
4907 while (proto->IsJSObject() &&
4908 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4909 count++;
4910 proto = JSObject::cast(proto)->GetPrototype();
4911 }
4912 return count;
4913}
4914
4915
4916// Return the names of the local named properties.
4917// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004918RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004920 ASSERT(args.length() == 1);
4921 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004922 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004923 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004924 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004925
4926 // Skip the global proxy as it has no properties and always delegates to the
4927 // real global object.
4928 if (obj->IsJSGlobalProxy()) {
4929 // Only collect names if access is permitted.
4930 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 !isolate->MayNamedAccess(*obj,
4932 isolate->heap()->undefined_value(),
4933 v8::ACCESS_KEYS)) {
4934 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4935 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004936 }
4937 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4938 }
4939
4940 // Find the number of objects making up this.
4941 int length = LocalPrototypeChainLength(*obj);
4942
4943 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004944 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004945 int total_property_count = 0;
4946 Handle<JSObject> jsproto = obj;
4947 for (int i = 0; i < length; i++) {
4948 // Only collect names if access is permitted.
4949 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 !isolate->MayNamedAccess(*jsproto,
4951 isolate->heap()->undefined_value(),
4952 v8::ACCESS_KEYS)) {
4953 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4954 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004955 }
4956 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004957 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004958 local_property_count[i] = n;
4959 total_property_count += n;
4960 if (i < length - 1) {
4961 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4962 }
4963 }
4964
4965 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004966 Handle<FixedArray> names =
4967 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968
4969 // Get the property names.
4970 jsproto = obj;
4971 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004972 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004973 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004974 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4975 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004976 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 proto_with_hidden_properties++;
4978 }
4979 if (i < length - 1) {
4980 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4981 }
4982 }
4983
4984 // Filter out name of hidden propeties object.
4985 if (proto_with_hidden_properties > 0) {
4986 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004987 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004988 names->length() - proto_with_hidden_properties);
4989 int dest_pos = 0;
4990 for (int i = 0; i < total_property_count; i++) {
4991 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993 continue;
4994 }
4995 names->set(dest_pos++, name);
4996 }
4997 }
4998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000}
5001
5002
5003// Return the names of the local indexed properties.
5004// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007 ASSERT(args.length() == 1);
5008 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005010 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005011 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005012
5013 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005015 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017}
5018
5019
5020// Return information on whether an object has a named or indexed interceptor.
5021// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005024 ASSERT(args.length() == 1);
5025 if (!args[0]->IsJSObject()) {
5026 return Smi::FromInt(0);
5027 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005028 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029
5030 int result = 0;
5031 if (obj->HasNamedInterceptor()) result |= 2;
5032 if (obj->HasIndexedInterceptor()) result |= 1;
5033
5034 return Smi::FromInt(result);
5035}
5036
5037
5038// Return property names from named interceptor.
5039// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005040RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005043 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044
5045 if (obj->HasNamedInterceptor()) {
5046 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5047 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005050}
5051
5052
5053// Return element names from indexed interceptor.
5054// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005055RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005057 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005059
5060 if (obj->HasIndexedInterceptor()) {
5061 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5062 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5063 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065}
5066
5067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005068RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005069 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005070 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005072 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005073
5074 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005075 // Do access checks before going to the global object.
5076 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005077 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005078 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5080 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005081 }
5082
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005083 Handle<Object> proto(object->GetPrototype());
5084 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005086 object = Handle<JSObject>::cast(proto);
5087 }
5088
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005089 bool threw = false;
5090 Handle<FixedArray> contents =
5091 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5092 if (threw) return Failure::Exception();
5093
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005094 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5095 // property array and since the result is mutable we have to create
5096 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005097 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005098 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005099 for (int i = 0; i < length; i++) {
5100 Object* entry = contents->get(i);
5101 if (entry->IsString()) {
5102 copy->set(i, entry);
5103 } else {
5104 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 HandleScope scope(isolate);
5106 Handle<Object> entry_handle(entry, isolate);
5107 Handle<Object> entry_str =
5108 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005109 copy->set(i, *entry_str);
5110 }
5111 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005113}
5114
5115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005116RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005117 NoHandleAllocation ha;
5118 ASSERT(args.length() == 1);
5119
5120 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005121 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122 it.AdvanceToArgumentsFrame();
5123 JavaScriptFrame* frame = it.frame();
5124
5125 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005126 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127
5128 // Try to convert the key to an index. If successful and within
5129 // index return the the argument from the frame.
5130 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005131 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132 return frame->GetParameter(index);
5133 }
5134
5135 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005136 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005137 bool exception = false;
5138 Handle<Object> converted =
5139 Execution::ToString(args.at<Object>(0), &exception);
5140 if (exception) return Failure::Exception();
5141 Handle<String> key = Handle<String>::cast(converted);
5142
5143 // Try to convert the string key into an array index.
5144 if (key->AsArrayIndex(&index)) {
5145 if (index < n) {
5146 return frame->GetParameter(index);
5147 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149 }
5150 }
5151
5152 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5154 if (key->Equals(isolate->heap()->callee_symbol())) {
5155 Object* function = frame->function();
5156 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005157 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005158 return isolate->Throw(*isolate->factory()->NewTypeError(
5159 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5160 }
5161 return function;
5162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163
5164 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166}
5167
5168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005169RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005170 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005171 Object* object = args[0];
5172 return (object->IsJSObject() && !object->IsGlobalObject())
5173 ? JSObject::cast(object)->TransformToFastProperties(0)
5174 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005175}
5176
5177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005178RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005179 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005180 Object* obj = args[0];
5181 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5182 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5183 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005184}
5185
5186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005187RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 NoHandleAllocation ha;
5189 ASSERT(args.length() == 1);
5190
5191 return args[0]->ToBoolean();
5192}
5193
5194
5195// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5196// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005197RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 NoHandleAllocation ha;
5199
5200 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 HeapObject* heap_obj = HeapObject::cast(obj);
5203
5204 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 if (heap_obj->map()->is_undetectable()) {
5206 return isolate->heap()->undefined_symbol();
5207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208
5209 InstanceType instance_type = heap_obj->map()->instance_type();
5210 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 }
5213
5214 switch (instance_type) {
5215 case ODDBALL_TYPE:
5216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 }
5219 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005220 return FLAG_harmony_typeof
5221 ? isolate->heap()->null_symbol()
5222 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 }
5224 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005226 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005227 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 default:
5230 // For any kind of object not handled above, the spec rule for
5231 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 }
5234}
5235
5236
lrn@chromium.org25156de2010-04-06 13:10:27 +00005237static bool AreDigits(const char*s, int from, int to) {
5238 for (int i = from; i < to; i++) {
5239 if (s[i] < '0' || s[i] > '9') return false;
5240 }
5241
5242 return true;
5243}
5244
5245
5246static int ParseDecimalInteger(const char*s, int from, int to) {
5247 ASSERT(to - from < 10); // Overflow is not possible.
5248 ASSERT(from < to);
5249 int d = s[from] - '0';
5250
5251 for (int i = from + 1; i < to; i++) {
5252 d = 10 * d + (s[i] - '0');
5253 }
5254
5255 return d;
5256}
5257
5258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 NoHandleAllocation ha;
5261 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005262 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005263 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264
5265 // Fast case: short integer or some sorts of junk values.
5266 int len = subject->length();
5267 if (subject->IsSeqAsciiString()) {
5268 if (len == 0) return Smi::FromInt(0);
5269
5270 char const* data = SeqAsciiString::cast(subject)->GetChars();
5271 bool minus = (data[0] == '-');
5272 int start_pos = (minus ? 1 : 0);
5273
5274 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005276 } else if (data[start_pos] > '9') {
5277 // Fast check for a junk value. A valid string may start from a
5278 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5279 // the 'I' character ('Infinity'). All of that have codes not greater than
5280 // '9' except 'I'.
5281 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005282 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005283 }
5284 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5285 // The maximal/minimal smi has 10 digits. If the string has less digits we
5286 // know it will fit into the smi-data type.
5287 int d = ParseDecimalInteger(data, start_pos, len);
5288 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005289 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005290 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005291 } else if (!subject->HasHashCode() &&
5292 len <= String::kMaxArrayIndexSize &&
5293 (len == 1 || data[0] != '0')) {
5294 // String hash is not calculated yet but all the data are present.
5295 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005296 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005297#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005298 subject->Hash(); // Force hash calculation.
5299 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5300 static_cast<int>(hash));
5301#endif
5302 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005303 }
5304 return Smi::FromInt(d);
5305 }
5306 }
5307
5308 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005309 return isolate->heap()->NumberFromDouble(
5310 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311}
5312
5313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 NoHandleAllocation ha;
5316 ASSERT(args.length() == 1);
5317
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005318 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 int length = Smi::cast(codes->length())->value();
5320
5321 // Check if the string can be ASCII.
5322 int i;
5323 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005324 Object* element;
5325 { MaybeObject* maybe_element = codes->GetElement(i);
5326 // We probably can't get an exception here, but just in order to enforce
5327 // the checking of inputs in the runtime calls we check here.
5328 if (!maybe_element->ToObject(&element)) return maybe_element;
5329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005330 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5331 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5332 break;
5333 }
5334
lrn@chromium.org303ada72010-10-27 09:33:13 +00005335 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005339 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
5341
lrn@chromium.org303ada72010-10-27 09:33:13 +00005342 Object* object = NULL;
5343 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 String* result = String::cast(object);
5345 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346 Object* element;
5347 { MaybeObject* maybe_element = codes->GetElement(i);
5348 if (!maybe_element->ToObject(&element)) return maybe_element;
5349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005350 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005351 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 }
5353 return result;
5354}
5355
5356
5357// kNotEscaped is generated by the following:
5358//
5359// #!/bin/perl
5360// for (my $i = 0; $i < 256; $i++) {
5361// print "\n" if $i % 16 == 0;
5362// my $c = chr($i);
5363// my $escaped = 1;
5364// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5365// print $escaped ? "0, " : "1, ";
5366// }
5367
5368
5369static bool IsNotEscaped(uint16_t character) {
5370 // Only for 8 bit characters, the rest are always escaped (in a different way)
5371 ASSERT(character < 256);
5372 static const char kNotEscaped[256] = {
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5379 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
5390 return kNotEscaped[character] != 0;
5391}
5392
5393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005394RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 const char hex_chars[] = "0123456789ABCDEF";
5396 NoHandleAllocation ha;
5397 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005398 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
5402 int escaped_length = 0;
5403 int length = source->length();
5404 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 Access<StringInputBuffer> buffer(
5406 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407 buffer->Reset(source);
5408 while (buffer->has_more()) {
5409 uint16_t character = buffer->GetNext();
5410 if (character >= 256) {
5411 escaped_length += 6;
5412 } else if (IsNotEscaped(character)) {
5413 escaped_length++;
5414 } else {
5415 escaped_length += 3;
5416 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005417 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005418 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005419 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 return Failure::OutOfMemoryException();
5422 }
5423 }
5424 }
5425 // No length change implies no change. Return original string if no change.
5426 if (escaped_length == length) {
5427 return source;
5428 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005429 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005430 { MaybeObject* maybe_o =
5431 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005432 if (!maybe_o->ToObject(&o)) return maybe_o;
5433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434 String* destination = String::cast(o);
5435 int dest_position = 0;
5436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 Access<StringInputBuffer> buffer(
5438 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 buffer->Rewind();
5440 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005441 uint16_t chr = buffer->GetNext();
5442 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 destination->Set(dest_position, '%');
5444 destination->Set(dest_position+1, 'u');
5445 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5446 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5447 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5448 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005450 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452 dest_position++;
5453 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005454 destination->Set(dest_position, '%');
5455 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5456 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 dest_position += 3;
5458 }
5459 }
5460 return destination;
5461}
5462
5463
5464static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5465 static const signed char kHexValue['g'] = {
5466 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5467 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5470 -1, 10, 11, 12, 13, 14, 15, -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, 10, 11, 12, 13, 14, 15 };
5473
5474 if (character1 > 'f') return -1;
5475 int hi = kHexValue[character1];
5476 if (hi == -1) return -1;
5477 if (character2 > 'f') return -1;
5478 int lo = kHexValue[character2];
5479 if (lo == -1) return -1;
5480 return (hi << 4) + lo;
5481}
5482
5483
ager@chromium.org870a0b62008-11-04 11:43:05 +00005484static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005485 int i,
5486 int length,
5487 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005488 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 int32_t hi = 0;
5490 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 if (character == '%' &&
5492 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005493 source->Get(i + 1) == 'u' &&
5494 (hi = TwoDigitHex(source->Get(i + 2),
5495 source->Get(i + 3))) != -1 &&
5496 (lo = TwoDigitHex(source->Get(i + 4),
5497 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498 *step = 6;
5499 return (hi << 8) + lo;
5500 } else if (character == '%' &&
5501 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 (lo = TwoDigitHex(source->Get(i + 1),
5503 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 *step = 3;
5505 return lo;
5506 } else {
5507 *step = 1;
5508 return character;
5509 }
5510}
5511
5512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005513RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 NoHandleAllocation ha;
5515 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005516 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005518 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519
5520 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005521 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522
5523 int unescaped_length = 0;
5524 for (int i = 0; i < length; unescaped_length++) {
5525 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005526 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529 i += step;
5530 }
5531
5532 // No length change implies no change. Return original string if no change.
5533 if (unescaped_length == length)
5534 return source;
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005537 { MaybeObject* maybe_o =
5538 ascii ?
5539 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5540 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005541 if (!maybe_o->ToObject(&o)) return maybe_o;
5542 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 String* destination = String::cast(o);
5544
5545 int dest_position = 0;
5546 for (int i = 0; i < length; dest_position++) {
5547 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005548 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 i += step;
5550 }
5551 return destination;
5552}
5553
5554
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005555static const unsigned int kQuoteTableLength = 128u;
5556
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005557static const int kJsonQuotesCharactersPerEntry = 8;
5558static const char* const JsonQuotes =
5559 "\\u0000 \\u0001 \\u0002 \\u0003 "
5560 "\\u0004 \\u0005 \\u0006 \\u0007 "
5561 "\\b \\t \\n \\u000b "
5562 "\\f \\r \\u000e \\u000f "
5563 "\\u0010 \\u0011 \\u0012 \\u0013 "
5564 "\\u0014 \\u0015 \\u0016 \\u0017 "
5565 "\\u0018 \\u0019 \\u001a \\u001b "
5566 "\\u001c \\u001d \\u001e \\u001f "
5567 " ! \\\" # "
5568 "$ % & ' "
5569 "( ) * + "
5570 ", - . / "
5571 "0 1 2 3 "
5572 "4 5 6 7 "
5573 "8 9 : ; "
5574 "< = > ? "
5575 "@ A B C "
5576 "D E F G "
5577 "H I J K "
5578 "L M N O "
5579 "P Q R S "
5580 "T U V W "
5581 "X Y Z [ "
5582 "\\\\ ] ^ _ "
5583 "` a b c "
5584 "d e f g "
5585 "h i j k "
5586 "l m n o "
5587 "p q r s "
5588 "t u v w "
5589 "x y z { "
5590 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005591
5592
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005593// For a string that is less than 32k characters it should always be
5594// possible to allocate it in new space.
5595static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5596
5597
5598// Doing JSON quoting cannot make the string more than this many times larger.
5599static const int kJsonQuoteWorstCaseBlowup = 6;
5600
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005601static const int kSpaceForQuotesAndComma = 3;
5602static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005603
5604// Covers the entire ASCII range (all other characters are unchanged by JSON
5605// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005606static const byte JsonQuoteLengths[kQuoteTableLength] = {
5607 6, 6, 6, 6, 6, 6, 6, 6,
5608 2, 2, 2, 6, 2, 2, 6, 6,
5609 6, 6, 6, 6, 6, 6, 6, 6,
5610 6, 6, 6, 6, 6, 6, 6, 6,
5611 1, 1, 2, 1, 1, 1, 1, 1,
5612 1, 1, 1, 1, 1, 1, 1, 1,
5613 1, 1, 1, 1, 1, 1, 1, 1,
5614 1, 1, 1, 1, 1, 1, 1, 1,
5615 1, 1, 1, 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, 2, 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, 1, 1, 1, 1,
5623};
5624
5625
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005626template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005627MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628
5629
5630template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5632 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633}
5634
5635
5636template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005637MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5638 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639}
5640
5641
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005642template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5644 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 const Char* read_cursor = characters.start();
5647 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005648 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005649 int quoted_length = kSpaceForQuotes;
5650 while (read_cursor < end) {
5651 Char c = *(read_cursor++);
5652 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5653 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005654 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005655 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656 }
5657 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5659 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660 Object* new_object;
5661 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 return new_alloc;
5663 }
5664 StringType* new_string = StringType::cast(new_object);
5665
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005667 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005668 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005669 *(write_cursor++) = '"';
5670
5671 read_cursor = characters.start();
5672 while (read_cursor < end) {
5673 Char c = *(read_cursor++);
5674 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5675 *(write_cursor++) = c;
5676 } else {
5677 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5678 const char* replacement = JsonQuotes +
5679 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5680 for (int i = 0; i < len; i++) {
5681 *write_cursor++ = *replacement++;
5682 }
5683 }
5684 }
5685 *(write_cursor++) = '"';
5686 return new_string;
5687}
5688
5689
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005690template <typename SinkChar, typename SourceChar>
5691static inline SinkChar* WriteQuoteJsonString(
5692 Isolate* isolate,
5693 SinkChar* write_cursor,
5694 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005695 // SinkChar is only char if SourceChar is guaranteed to be char.
5696 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005697 const SourceChar* read_cursor = characters.start();
5698 const SourceChar* end = read_cursor + characters.length();
5699 *(write_cursor++) = '"';
5700 while (read_cursor < end) {
5701 SourceChar c = *(read_cursor++);
5702 if (sizeof(SourceChar) > 1u &&
5703 static_cast<unsigned>(c) >= kQuoteTableLength) {
5704 *(write_cursor++) = static_cast<SinkChar>(c);
5705 } else {
5706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5707 const char* replacement = JsonQuotes +
5708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5709 write_cursor[0] = replacement[0];
5710 if (len > 1) {
5711 write_cursor[1] = replacement[1];
5712 if (len > 2) {
5713 ASSERT(len == 6);
5714 write_cursor[2] = replacement[2];
5715 write_cursor[3] = replacement[3];
5716 write_cursor[4] = replacement[4];
5717 write_cursor[5] = replacement[5];
5718 }
5719 }
5720 write_cursor += len;
5721 }
5722 }
5723 *(write_cursor++) = '"';
5724 return write_cursor;
5725}
5726
5727
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005728template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729static MaybeObject* QuoteJsonString(Isolate* isolate,
5730 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005731 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 int worst_case_length =
5734 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005737 }
5738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005739 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5740 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005741 Object* new_object;
5742 if (!new_alloc->ToObject(&new_object)) {
5743 return new_alloc;
5744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005745 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005746 // Even if our string is small enough to fit in new space we still have to
5747 // handle it being allocated in old space as may happen in the third
5748 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5749 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005750 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005751 }
5752 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005754
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005756 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005757 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005758 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5759 write_cursor,
5760 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005761 int final_length = static_cast<int>(
5762 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005764 isolate->heap()->new_space()->
5765 template ShrinkStringAtAllocationBoundary<StringType>(
5766 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005767 return new_string;
5768}
5769
5770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005771RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005773 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005774 if (!str->IsFlat()) {
5775 MaybeObject* try_flatten = str->TryFlatten();
5776 Object* flat;
5777 if (!try_flatten->ToObject(&flat)) {
5778 return try_flatten;
5779 }
5780 str = String::cast(flat);
5781 ASSERT(str->IsFlat());
5782 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005783 String::FlatContent flat = str->GetFlatContent();
5784 ASSERT(flat.IsFlat());
5785 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005788 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005789 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005790 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005791 }
5792}
5793
5794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005795RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005796 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005797 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005798 if (!str->IsFlat()) {
5799 MaybeObject* try_flatten = str->TryFlatten();
5800 Object* flat;
5801 if (!try_flatten->ToObject(&flat)) {
5802 return try_flatten;
5803 }
5804 str = String::cast(flat);
5805 ASSERT(str->IsFlat());
5806 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005807 String::FlatContent flat = str->GetFlatContent();
5808 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005810 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005811 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005812 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005813 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005814 }
5815}
5816
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817
5818template <typename Char, typename StringType>
5819static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5820 FixedArray* array,
5821 int worst_case_length) {
5822 int length = array->length();
5823
5824 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5825 worst_case_length);
5826 Object* new_object;
5827 if (!new_alloc->ToObject(&new_object)) {
5828 return new_alloc;
5829 }
5830 if (!isolate->heap()->new_space()->Contains(new_object)) {
5831 // Even if our string is small enough to fit in new space we still have to
5832 // handle it being allocated in old space as may happen in the third
5833 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5834 // CEntryStub::GenerateCore.
5835 return isolate->heap()->undefined_value();
5836 }
5837 AssertNoAllocation no_gc;
5838 StringType* new_string = StringType::cast(new_object);
5839 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5840
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005841 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005842 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005843 *(write_cursor++) = '[';
5844 for (int i = 0; i < length; i++) {
5845 if (i != 0) *(write_cursor++) = ',';
5846 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent content = str->GetFlatContent();
5848 ASSERT(content.IsFlat());
5849 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5851 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005852 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005853 } else {
5854 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5855 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005856 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 }
5858 }
5859 *(write_cursor++) = ']';
5860
5861 int final_length = static_cast<int>(
5862 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005863 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005864 isolate->heap()->new_space()->
5865 template ShrinkStringAtAllocationBoundary<StringType>(
5866 new_string, final_length);
5867 return new_string;
5868}
5869
5870
5871RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5872 NoHandleAllocation ha;
5873 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005874 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005875
5876 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5877 FixedArray* elements = FixedArray::cast(array->elements());
5878 int n = elements->length();
5879 bool ascii = true;
5880 int total_length = 0;
5881
5882 for (int i = 0; i < n; i++) {
5883 Object* elt = elements->get(i);
5884 if (!elt->IsString()) return isolate->heap()->undefined_value();
5885 String* element = String::cast(elt);
5886 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5887 total_length += element->length();
5888 if (ascii && element->IsTwoByteRepresentation()) {
5889 ascii = false;
5890 }
5891 }
5892
5893 int worst_case_length =
5894 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5895 + total_length * kJsonQuoteWorstCaseBlowup;
5896
5897 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5898 return isolate->heap()->undefined_value();
5899 }
5900
5901 if (ascii) {
5902 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5903 elements,
5904 worst_case_length);
5905 } else {
5906 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5907 elements,
5908 worst_case_length);
5909 }
5910}
5911
5912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005913RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 NoHandleAllocation ha;
5915
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005916 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005917 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005919 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920
lrn@chromium.org25156de2010-04-06 13:10:27 +00005921 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005922 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005927RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005929 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930
5931 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005932 double value = StringToDouble(isolate->unicode_cache(),
5933 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 String* s,
5944 int length,
5945 int input_string_length,
5946 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005947 // We try this twice, once with the assumption that the result is no longer
5948 // than the input and, if that assumption breaks, again with the exact
5949 // length. This may not be pretty, but it is nicer than what was here before
5950 // and I hereby claim my vaffel-is.
5951 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 // Allocate the resulting string.
5953 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005954 // NOTE: This assumes that the upper/lower case of an ASCII
5955 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 // might break in the future if we implement more context and locale
5957 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958 Object* o;
5959 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 ? isolate->heap()->AllocateRawAsciiString(length)
5961 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962 if (!maybe_o->ToObject(&o)) return maybe_o;
5963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 String* result = String::cast(o);
5965 bool has_changed_character = false;
5966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 // Convert all characters to upper case, assuming that they will fit
5968 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 Access<StringInputBuffer> buffer(
5970 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005972 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 // We can assume that the string is not empty
5974 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005975 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005976 bool has_next = buffer->has_more();
5977 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 int char_length = mapping->get(current, next, chars);
5979 if (char_length == 0) {
5980 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005981 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 i++;
5983 } else if (char_length == 1) {
5984 // Common case: converting the letter resulted in one character.
5985 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005986 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 has_changed_character = true;
5988 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005989 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 // We've assumed that the result would be as long as the
5991 // input but here is a character that converts to several
5992 // characters. No matter, we calculate the exact length
5993 // of the result and try the whole thing again.
5994 //
5995 // Note that this leaves room for optimization. We could just
5996 // memcpy what we already have to the result string. Also,
5997 // the result string is the last object allocated we could
5998 // "realloc" it and probably, in the vast majority of cases,
5999 // extend the existing string to be able to hold the full
6000 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006001 int next_length = 0;
6002 if (has_next) {
6003 next_length = mapping->get(next, 0, chars);
6004 if (next_length == 0) next_length = 1;
6005 }
6006 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 while (buffer->has_more()) {
6008 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006009 // NOTE: we use 0 as the next character here because, while
6010 // the next character may affect what a character converts to,
6011 // it does not in any case affect the length of what it convert
6012 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 int char_length = mapping->get(current, 0, chars);
6014 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006015 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006016 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 return Failure::OutOfMemoryException();
6019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 // Try again with the real length.
6022 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 } else {
6024 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 i++;
6027 }
6028 has_changed_character = true;
6029 }
6030 current = next;
6031 }
6032 if (has_changed_character) {
6033 return result;
6034 } else {
6035 // If we didn't actually change anything in doing the conversion
6036 // we simple return the result and let the converted string
6037 // become garbage; there is no reason to keep two identical strings
6038 // alive.
6039 return s;
6040 }
6041}
6042
6043
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006044namespace {
6045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6047
6048
6049// Given a word and two range boundaries returns a word with high bit
6050// set in every byte iff the corresponding input byte was strictly in
6051// the range (m, n). All the other bits in the result are cleared.
6052// This function is only useful when it can be inlined and the
6053// boundaries are statically known.
6054// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006055// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006057 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006058 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6059 // Use strict inequalities since in edge cases the function could be
6060 // further simplified.
6061 ASSERT(0 < m && m < n && n < 0x7F);
6062 // Has high bit set in every w byte less than n.
6063 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6064 // Has high bit set in every w byte greater than m.
6065 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6066 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6067}
6068
6069
6070enum AsciiCaseConversion {
6071 ASCII_TO_LOWER,
6072 ASCII_TO_UPPER
6073};
6074
6075
6076template <AsciiCaseConversion dir>
6077struct FastAsciiConverter {
6078 static bool Convert(char* dst, char* src, int length) {
6079#ifdef DEBUG
6080 char* saved_dst = dst;
6081 char* saved_src = src;
6082#endif
6083 // We rely on the distance between upper and lower case letters
6084 // being a known power of 2.
6085 ASSERT('a' - 'A' == (1 << 5));
6086 // Boundaries for the range of input characters than require conversion.
6087 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6088 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6089 bool changed = false;
6090 char* const limit = src + length;
6091#ifdef V8_HOST_CAN_READ_UNALIGNED
6092 // Process the prefix of the input that requires no conversion one
6093 // (machine) word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 if (AsciiRangeMask(w, lo, hi) != 0) {
6097 changed = true;
6098 break;
6099 }
6100 *reinterpret_cast<uintptr_t*>(dst) = w;
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104 // Process the remainder of the input performing conversion when
6105 // required one word at a time.
6106 while (src <= limit - sizeof(uintptr_t)) {
6107 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6108 uintptr_t m = AsciiRangeMask(w, lo, hi);
6109 // The mask has high (7th) bit set in every byte that needs
6110 // conversion and we know that the distance between cases is
6111 // 1 << 5.
6112 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6113 src += sizeof(uintptr_t);
6114 dst += sizeof(uintptr_t);
6115 }
6116#endif
6117 // Process the last few bytes of the input (or the whole input if
6118 // unaligned access is not supported).
6119 while (src < limit) {
6120 char c = *src;
6121 if (lo < c && c < hi) {
6122 c ^= (1 << 5);
6123 changed = true;
6124 }
6125 *dst = c;
6126 ++src;
6127 ++dst;
6128 }
6129#ifdef DEBUG
6130 CheckConvert(saved_dst, saved_src, length, changed);
6131#endif
6132 return changed;
6133 }
6134
6135#ifdef DEBUG
6136 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6137 bool expected_changed = false;
6138 for (int i = 0; i < length; i++) {
6139 if (dst[i] == src[i]) continue;
6140 expected_changed = true;
6141 if (dir == ASCII_TO_LOWER) {
6142 ASSERT('A' <= src[i] && src[i] <= 'Z');
6143 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6144 } else {
6145 ASSERT(dir == ASCII_TO_UPPER);
6146 ASSERT('a' <= src[i] && src[i] <= 'z');
6147 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6148 }
6149 }
6150 ASSERT(expected_changed == changed);
6151 }
6152#endif
6153};
6154
6155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156struct ToLowerTraits {
6157 typedef unibrow::ToLowercase UnibrowConverter;
6158
lrn@chromium.org303ada72010-10-27 09:33:13 +00006159 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160};
6161
6162
6163struct ToUpperTraits {
6164 typedef unibrow::ToUppercase UnibrowConverter;
6165
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167};
6168
6169} // namespace
6170
6171
6172template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006175 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006176 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006177 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006178 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006181 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 if (length == 0) return s;
6184
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006185 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006187 // NOTE: This assumes that the upper/lower case of an ASCII
6188 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006189 // might break in the future if we implement more context and locale
6190 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006191 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006194 if (!maybe_o->ToObject(&o)) return maybe_o;
6195 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006197 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006198 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006199 return has_changed_character ? result : s;
6200 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006201
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006203 { MaybeObject* maybe_answer =
6204 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006205 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6206 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006207 if (answer->IsSmi()) {
6208 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 ConvertCaseHelper(isolate,
6211 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006214 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006215 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006216}
6217
6218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006220 return ConvertCase<ToLowerTraits>(
6221 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222}
6223
6224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006225RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return ConvertCase<ToUpperTraits>(
6227 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228}
6229
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006230
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006231static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006232 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233}
6234
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237 NoHandleAllocation ha;
6238 ASSERT(args.length() == 3);
6239
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006240 CONVERT_ARG_CHECKED(String, s, 0);
6241 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6242 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006245 int length = s->length();
6246
6247 int left = 0;
6248 if (trimLeft) {
6249 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6250 left++;
6251 }
6252 }
6253
6254 int right = length;
6255 if (trimRight) {
6256 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6257 right--;
6258 }
6259 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006260 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006261}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006264RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006265 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006267 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6268 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6270
6271 int subject_length = subject->length();
6272 int pattern_length = pattern->length();
6273 RUNTIME_ASSERT(pattern_length > 0);
6274
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006275 if (limit == 0xffffffffu) {
6276 Handle<Object> cached_answer(StringSplitCache::Lookup(
6277 isolate->heap()->string_split_cache(),
6278 *subject,
6279 *pattern));
6280 if (*cached_answer != Smi::FromInt(0)) {
6281 Handle<JSArray> result =
6282 isolate->factory()->NewJSArrayWithElements(
6283 Handle<FixedArray>::cast(cached_answer));
6284 return *result;
6285 }
6286 }
6287
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006288 // The limit can be very large (0xffffffffu), but since the pattern
6289 // isn't empty, we can never create more parts than ~half the length
6290 // of the subject.
6291
6292 if (!subject->IsFlat()) FlattenString(subject);
6293
6294 static const int kMaxInitialListCapacity = 16;
6295
danno@chromium.org40cb8782011-05-25 07:58:50 +00006296 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006297
6298 // Find (up to limit) indices of separator and end-of-string in subject
6299 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6300 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006301 if (!pattern->IsFlat()) FlattenString(pattern);
6302
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006303 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006304
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 if (static_cast<uint32_t>(indices.length()) < limit) {
6306 indices.Add(subject_length);
6307 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006308
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006309 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006310
6311 // Create JSArray of substrings separated by separator.
6312 int part_count = indices.length();
6313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006315 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006316 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006317 result->set_length(Smi::FromInt(part_count));
6318
6319 ASSERT(result->HasFastElements());
6320
6321 if (part_count == 1 && indices.at(0) == subject_length) {
6322 FixedArray::cast(result->elements())->set(0, *subject);
6323 return *result;
6324 }
6325
6326 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6327 int part_start = 0;
6328 for (int i = 0; i < part_count; i++) {
6329 HandleScope local_loop_handle;
6330 int part_end = indices.at(i);
6331 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006332 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006333 elements->set(i, *substring);
6334 part_start = part_end + pattern_length;
6335 }
6336
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006337 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006338 if (result->HasFastElements()) {
6339 StringSplitCache::Enter(isolate->heap(),
6340 isolate->heap()->string_split_cache(),
6341 *subject,
6342 *pattern,
6343 *elements);
6344 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006345 }
6346
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006347 return *result;
6348}
6349
6350
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006351// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006352// one-char strings in the cache. Gives up on the first char that is
6353// not in the cache and fills the remainder with smi zeros. Returns
6354// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355static int CopyCachedAsciiCharsToArray(Heap* heap,
6356 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006357 FixedArray* elements,
6358 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006359 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 FixedArray* ascii_cache = heap->single_character_string_cache();
6361 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006362 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006363 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364 for (i = 0; i < length; ++i) {
6365 Object* value = ascii_cache->get(chars[i]);
6366 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006367 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368 }
6369 if (i < length) {
6370 ASSERT(Smi::FromInt(0) == 0);
6371 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6372 }
6373#ifdef DEBUG
6374 for (int j = 0; j < length; ++j) {
6375 Object* element = elements->get(j);
6376 ASSERT(element == Smi::FromInt(0) ||
6377 (element->IsString() && String::cast(element)->LooksValid()));
6378 }
6379#endif
6380 return i;
6381}
6382
6383
6384// Converts a String to JSArray.
6385// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006386RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006387 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006388 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006389 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006390 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006392 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006393 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394
6395 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006398 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006399 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 { MaybeObject* maybe_obj =
6401 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006402 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006405 String::FlatContent content = s->GetFlatContent();
6406 if (content.IsAscii()) {
6407 Vector<const char> chars = content.ToAsciiVector();
6408 // Note, this will initialize all elements (not only the prefix)
6409 // to prevent GC from seeing partially initialized array.
6410 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6411 chars.start(),
6412 *elements,
6413 length);
6414 } else {
6415 MemsetPointer(elements->data_start(),
6416 isolate->heap()->undefined_value(),
6417 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006418 }
6419 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006421 }
6422 for (int i = position; i < length; ++i) {
6423 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6424 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006425 }
6426
6427#ifdef DEBUG
6428 for (int i = 0; i < length; ++i) {
6429 ASSERT(String::cast(elements->get(i))->length() == 1);
6430 }
6431#endif
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434}
6435
6436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006440 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006441 return value->ToObject();
6442}
6443
6444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006446 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006448 return char_length == 0;
6449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
6455
6456 Object* number = args[0];
6457 RUNTIME_ASSERT(number->IsNumber());
6458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
6467 Object* number = args[0];
6468 RUNTIME_ASSERT(number->IsNumber());
6469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006471}
6472
6473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006474RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475 NoHandleAllocation ha;
6476 ASSERT(args.length() == 1);
6477
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006478 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006479
6480 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6481 if (number > 0 && number <= Smi::kMaxValue) {
6482 return Smi::FromInt(static_cast<int>(number));
6483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485}
6486
6487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006492 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006493
6494 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6495 if (number > 0 && number <= Smi::kMaxValue) {
6496 return Smi::FromInt(static_cast<int>(number));
6497 }
6498
6499 double double_value = DoubleToInteger(number);
6500 // Map both -0 and +0 to +0.
6501 if (double_value == 0) double_value = 0;
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006504}
6505
6506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513}
6514
6515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006516RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
6519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006520 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006521
6522 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6523 if (number > 0 && number <= Smi::kMaxValue) {
6524 return Smi::FromInt(static_cast<int>(number));
6525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527}
6528
6529
ager@chromium.org870a0b62008-11-04 11:43:05 +00006530// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6531// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
6536 Object* obj = args[0];
6537 if (obj->IsSmi()) {
6538 return obj;
6539 }
6540 if (obj->IsHeapNumber()) {
6541 double value = HeapNumber::cast(obj)->value();
6542 int int_value = FastD2I(value);
6543 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6544 return Smi::FromInt(int_value);
6545 }
6546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006547 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006548}
6549
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006551RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006554 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006555}
6556
6557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006558RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006562 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6563 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565}
6566
6567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6573 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579 NoHandleAllocation ha;
6580 ASSERT(args.length() == 2);
6581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6583 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594}
6595
6596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 0);
6600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
6608
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006609 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6610 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612}
6613
6614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006615RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 NoHandleAllocation ha;
6617 ASSERT(args.length() == 2);
6618
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006619 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6620 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621
ager@chromium.org3811b432009-10-28 14:53:37 +00006622 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006623 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006631 CONVERT_ARG_CHECKED(String, str1, 0);
6632 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 isolate->counters()->string_add_runtime()->Increment();
6634 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006638template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639static inline void StringBuilderConcatHelper(String* special,
6640 sinkchar* sink,
6641 FixedArray* fixed_array,
6642 int array_length) {
6643 int position = 0;
6644 for (int i = 0; i < array_length; i++) {
6645 Object* element = fixed_array->get(i);
6646 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006647 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006648 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006649 int pos;
6650 int len;
6651 if (encoded_slice > 0) {
6652 // Position and length encoded in one smi.
6653 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6654 len = StringBuilderSubstringLength::decode(encoded_slice);
6655 } else {
6656 // Position and length encoded in two smis.
6657 Object* obj = fixed_array->get(++i);
6658 ASSERT(obj->IsSmi());
6659 pos = Smi::cast(obj)->value();
6660 len = -encoded_slice;
6661 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006662 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006663 sink + position,
6664 pos,
6665 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006666 position += len;
6667 } else {
6668 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006669 int element_length = string->length();
6670 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006671 position += element_length;
6672 }
6673 }
6674}
6675
6676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006677RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006679 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006680 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006681 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 return Failure::OutOfMemoryException();
6684 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006685 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006686 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687
6688 // This assumption is used by the slice encoding in one or two smis.
6689 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6690
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006691 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006692 if (maybe_result->IsFailure()) return maybe_result;
6693
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006694 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 }
6698 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006699 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702
6703 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 } else if (array_length == 1) {
6706 Object* first = fixed_array->get(0);
6707 if (first->IsString()) return first;
6708 }
6709
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006710 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 int position = 0;
6712 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006713 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 Object* elt = fixed_array->get(i);
6715 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006716 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 int smi_value = Smi::cast(elt)->value();
6718 int pos;
6719 int len;
6720 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006721 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006722 pos = StringBuilderSubstringPosition::decode(smi_value);
6723 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006724 } else {
6725 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 len = -smi_value;
6727 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 i++;
6729 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006731 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006732 Object* next_smi = fixed_array->get(i);
6733 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006735 }
6736 pos = Smi::cast(next_smi)->value();
6737 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006741 ASSERT(pos >= 0);
6742 ASSERT(len >= 0);
6743 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006745 }
6746 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 } else if (elt->IsString()) {
6748 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006749 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006750 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006751 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006755 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006758 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006760 return Failure::OutOfMemoryException();
6761 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006762 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 }
6764
6765 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 { MaybeObject* maybe_object =
6770 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006771 if (!maybe_object->ToObject(&object)) return maybe_object;
6772 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006773 SeqAsciiString* answer = SeqAsciiString::cast(object);
6774 StringBuilderConcatHelper(special,
6775 answer->GetChars(),
6776 fixed_array,
6777 array_length);
6778 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780 { MaybeObject* maybe_object =
6781 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006782 if (!maybe_object->ToObject(&object)) return maybe_object;
6783 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006784 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6785 StringBuilderConcatHelper(special,
6786 answer->GetChars(),
6787 fixed_array,
6788 array_length);
6789 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006791}
6792
6793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006794RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006795 NoHandleAllocation ha;
6796 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006797 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006798 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006800 return Failure::OutOfMemoryException();
6801 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006802 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006803 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804
6805 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 }
6808 FixedArray* fixed_array = FixedArray::cast(array->elements());
6809 if (fixed_array->length() < array_length) {
6810 array_length = fixed_array->length();
6811 }
6812
6813 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006815 } else if (array_length == 1) {
6816 Object* first = fixed_array->get(0);
6817 if (first->IsString()) return first;
6818 }
6819
6820 int separator_length = separator->length();
6821 int max_nof_separators =
6822 (String::kMaxLength + separator_length - 1) / separator_length;
6823 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006825 return Failure::OutOfMemoryException();
6826 }
6827 int length = (array_length - 1) * separator_length;
6828 for (int i = 0; i < array_length; i++) {
6829 Object* element_obj = fixed_array->get(i);
6830 if (!element_obj->IsString()) {
6831 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006833 }
6834 String* element = String::cast(element_obj);
6835 int increment = element->length();
6836 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006838 return Failure::OutOfMemoryException();
6839 }
6840 length += increment;
6841 }
6842
6843 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 { MaybeObject* maybe_object =
6845 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006846 if (!maybe_object->ToObject(&object)) return maybe_object;
6847 }
6848 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6849
6850 uc16* sink = answer->GetChars();
6851#ifdef DEBUG
6852 uc16* end = sink + length;
6853#endif
6854
6855 String* first = String::cast(fixed_array->get(0));
6856 int first_length = first->length();
6857 String::WriteToFlat(first, sink, 0, first_length);
6858 sink += first_length;
6859
6860 for (int i = 1; i < array_length; i++) {
6861 ASSERT(sink + separator_length <= end);
6862 String::WriteToFlat(separator, sink, 0, separator_length);
6863 sink += separator_length;
6864
6865 String* element = String::cast(fixed_array->get(i));
6866 int element_length = element->length();
6867 ASSERT(sink + element_length <= end);
6868 String::WriteToFlat(element, sink, 0, element_length);
6869 sink += element_length;
6870 }
6871 ASSERT(sink == end);
6872
6873 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6874 return answer;
6875}
6876
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006877template <typename Char>
6878static void JoinSparseArrayWithSeparator(FixedArray* elements,
6879 int elements_length,
6880 uint32_t array_length,
6881 String* separator,
6882 Vector<Char> buffer) {
6883 int previous_separator_position = 0;
6884 int separator_length = separator->length();
6885 int cursor = 0;
6886 for (int i = 0; i < elements_length; i += 2) {
6887 int position = NumberToInt32(elements->get(i));
6888 String* string = String::cast(elements->get(i + 1));
6889 int string_length = string->length();
6890 if (string->length() > 0) {
6891 while (previous_separator_position < position) {
6892 String::WriteToFlat<Char>(separator, &buffer[cursor],
6893 0, separator_length);
6894 cursor += separator_length;
6895 previous_separator_position++;
6896 }
6897 String::WriteToFlat<Char>(string, &buffer[cursor],
6898 0, string_length);
6899 cursor += string->length();
6900 }
6901 }
6902 if (separator_length > 0) {
6903 // Array length must be representable as a signed 32-bit number,
6904 // otherwise the total string length would have been too large.
6905 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6906 int last_array_index = static_cast<int>(array_length - 1);
6907 while (previous_separator_position < last_array_index) {
6908 String::WriteToFlat<Char>(separator, &buffer[cursor],
6909 0, separator_length);
6910 cursor += separator_length;
6911 previous_separator_position++;
6912 }
6913 }
6914 ASSERT(cursor <= buffer.length());
6915}
6916
6917
6918RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006921 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006922 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6923 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006924 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006925 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006926 // elements_array is fast-mode JSarray of alternating positions
6927 // (increasing order) and strings.
6928 // array_length is length of original array (used to add separators);
6929 // separator is string to put between elements. Assumed to be non-empty.
6930
6931 // Find total length of join result.
6932 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006933 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006934 int max_string_length;
6935 if (is_ascii) {
6936 max_string_length = SeqAsciiString::kMaxLength;
6937 } else {
6938 max_string_length = SeqTwoByteString::kMaxLength;
6939 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006940 bool overflow = false;
6941 CONVERT_NUMBER_CHECKED(int, elements_length,
6942 Int32, elements_array->length());
6943 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6944 FixedArray* elements = FixedArray::cast(elements_array->elements());
6945 for (int i = 0; i < elements_length; i += 2) {
6946 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006947 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6948 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006949 int length = string->length();
6950 if (is_ascii && !string->IsAsciiRepresentation()) {
6951 is_ascii = false;
6952 max_string_length = SeqTwoByteString::kMaxLength;
6953 }
6954 if (length > max_string_length ||
6955 max_string_length - length < string_length) {
6956 overflow = true;
6957 break;
6958 }
6959 string_length += length;
6960 }
6961 int separator_length = separator->length();
6962 if (!overflow && separator_length > 0) {
6963 if (array_length <= 0x7fffffffu) {
6964 int separator_count = static_cast<int>(array_length) - 1;
6965 int remaining_length = max_string_length - string_length;
6966 if ((remaining_length / separator_length) >= separator_count) {
6967 string_length += separator_length * (array_length - 1);
6968 } else {
6969 // Not room for the separators within the maximal string length.
6970 overflow = true;
6971 }
6972 } else {
6973 // Nonempty separator and at least 2^31-1 separators necessary
6974 // means that the string is too large to create.
6975 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6976 overflow = true;
6977 }
6978 }
6979 if (overflow) {
6980 // Throw OutOfMemory exception for creating too large a string.
6981 V8::FatalProcessOutOfMemory("Array join result too large.");
6982 }
6983
6984 if (is_ascii) {
6985 MaybeObject* result_allocation =
6986 isolate->heap()->AllocateRawAsciiString(string_length);
6987 if (result_allocation->IsFailure()) return result_allocation;
6988 SeqAsciiString* result_string =
6989 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6990 JoinSparseArrayWithSeparator<char>(elements,
6991 elements_length,
6992 array_length,
6993 separator,
6994 Vector<char>(result_string->GetChars(),
6995 string_length));
6996 return result_string;
6997 } else {
6998 MaybeObject* result_allocation =
6999 isolate->heap()->AllocateRawTwoByteString(string_length);
7000 if (result_allocation->IsFailure()) return result_allocation;
7001 SeqTwoByteString* result_string =
7002 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7003 JoinSparseArrayWithSeparator<uc16>(elements,
7004 elements_length,
7005 array_length,
7006 separator,
7007 Vector<uc16>(result_string->GetChars(),
7008 string_length));
7009 return result_string;
7010 }
7011}
7012
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 2);
7017
7018 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7019 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021}
7022
7023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007024RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025 NoHandleAllocation ha;
7026 ASSERT(args.length() == 2);
7027
7028 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7029 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007030 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031}
7032
7033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007034RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035 NoHandleAllocation ha;
7036 ASSERT(args.length() == 2);
7037
7038 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7039 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
7043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007044RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 1);
7047
7048 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050}
7051
7052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007053RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054 NoHandleAllocation ha;
7055 ASSERT(args.length() == 2);
7056
7057 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7058 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060}
7061
7062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007063RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 NoHandleAllocation ha;
7065 ASSERT(args.length() == 2);
7066
7067 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7068 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007069 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070}
7071
7072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007073RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 NoHandleAllocation ha;
7075 ASSERT(args.length() == 2);
7076
7077 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7078 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080}
7081
7082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007083RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 NoHandleAllocation ha;
7085 ASSERT(args.length() == 2);
7086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7088 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7090 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7091 if (x == y) return Smi::FromInt(EQUAL);
7092 Object* result;
7093 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7094 result = Smi::FromInt(EQUAL);
7095 } else {
7096 result = Smi::FromInt(NOT_EQUAL);
7097 }
7098 return result;
7099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 2);
7105
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007106 CONVERT_ARG_CHECKED(String, x, 0);
7107 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007109 bool not_equal = !x->Equals(y);
7110 // This is slightly convoluted because the value that signifies
7111 // equality is 0 and inequality is 1 so we have to negate the result
7112 // from String::Equals.
7113 ASSERT(not_equal == 0 || not_equal == 1);
7114 STATIC_CHECK(EQUAL == 0);
7115 STATIC_CHECK(NOT_EQUAL == 1);
7116 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117}
7118
7119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007120RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121 NoHandleAllocation ha;
7122 ASSERT(args.length() == 3);
7123
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007124 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7125 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126 if (isnan(x) || isnan(y)) return args[2];
7127 if (x == y) return Smi::FromInt(EQUAL);
7128 if (isless(x, y)) return Smi::FromInt(LESS);
7129 return Smi::FromInt(GREATER);
7130}
7131
7132
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007133// Compare two Smis as if they were converted to strings and then
7134// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007135RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007136 NoHandleAllocation ha;
7137 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007138 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7139 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140
7141 // If the integers are equal so are the string representations.
7142 if (x_value == y_value) return Smi::FromInt(EQUAL);
7143
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007144 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007145 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 if (x_value == 0 || y_value == 0)
7147 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007148
ager@chromium.org32912102009-01-16 10:38:43 +00007149 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007150 // smallest because the char code of '-' is less than the char code
7151 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007152
7153 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7154 // architectures using 32-bit Smis.
7155 uint32_t x_scaled = x_value;
7156 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007157 if (x_value < 0 || y_value < 0) {
7158 if (y_value >= 0) return Smi::FromInt(LESS);
7159 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007160 x_scaled = -x_value;
7161 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007162 }
7163
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007164 static const uint32_t kPowersOf10[] = {
7165 1, 10, 100, 1000, 10*1000, 100*1000,
7166 1000*1000, 10*1000*1000, 100*1000*1000,
7167 1000*1000*1000
7168 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007169
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007170 // If the integers have the same number of decimal digits they can be
7171 // compared directly as the numeric order is the same as the
7172 // lexicographic order. If one integer has fewer digits, it is scaled
7173 // by some power of 10 to have the same number of digits as the longer
7174 // integer. If the scaled integers are equal it means the shorter
7175 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007177 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7178 int x_log2 = IntegerLog2(x_scaled);
7179 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7180 x_log10 -= x_scaled < kPowersOf10[x_log10];
7181
7182 int y_log2 = IntegerLog2(y_scaled);
7183 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7184 y_log10 -= y_scaled < kPowersOf10[y_log10];
7185
7186 int tie = EQUAL;
7187
7188 if (x_log10 < y_log10) {
7189 // X has fewer digits. We would like to simply scale up X but that
7190 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7191 // be scaled up to 9_000_000_000. So we scale up by the next
7192 // smallest power and scale down Y to drop one digit. It is OK to
7193 // drop one digit from the longer integer since the final digit is
7194 // past the length of the shorter integer.
7195 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7196 y_scaled /= 10;
7197 tie = LESS;
7198 } else if (y_log10 < x_log10) {
7199 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7200 x_scaled /= 10;
7201 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007202 }
7203
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7205 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7206 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007207}
7208
7209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210static Object* StringInputBufferCompare(RuntimeState* state,
7211 String* x,
7212 String* y) {
7213 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7214 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007215 bufx.Reset(x);
7216 bufy.Reset(y);
7217 while (bufx.has_more() && bufy.has_more()) {
7218 int d = bufx.GetNext() - bufy.GetNext();
7219 if (d < 0) return Smi::FromInt(LESS);
7220 else if (d > 0) return Smi::FromInt(GREATER);
7221 }
7222
7223 // x is (non-trivial) prefix of y:
7224 if (bufy.has_more()) return Smi::FromInt(LESS);
7225 // y is prefix of x:
7226 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7227}
7228
7229
7230static Object* FlatStringCompare(String* x, String* y) {
7231 ASSERT(x->IsFlat());
7232 ASSERT(y->IsFlat());
7233 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7234 int prefix_length = x->length();
7235 if (y->length() < prefix_length) {
7236 prefix_length = y->length();
7237 equal_prefix_result = Smi::FromInt(GREATER);
7238 } else if (y->length() > prefix_length) {
7239 equal_prefix_result = Smi::FromInt(LESS);
7240 }
7241 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007242 String::FlatContent x_content = x->GetFlatContent();
7243 String::FlatContent y_content = y->GetFlatContent();
7244 if (x_content.IsAscii()) {
7245 Vector<const char> x_chars = x_content.ToAsciiVector();
7246 if (y_content.IsAscii()) {
7247 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007248 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007249 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007250 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007251 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7252 }
7253 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007254 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7255 if (y_content.IsAscii()) {
7256 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7258 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007259 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007260 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7261 }
7262 }
7263 Object* result;
7264 if (r == 0) {
7265 result = equal_prefix_result;
7266 } else {
7267 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007269 ASSERT(result ==
7270 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007271 return result;
7272}
7273
7274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007275RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 NoHandleAllocation ha;
7277 ASSERT(args.length() == 2);
7278
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007279 CONVERT_ARG_CHECKED(String, x, 0);
7280 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007282 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 // A few fast case tests before we flatten.
7285 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007286 if (y->length() == 0) {
7287 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007289 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 return Smi::FromInt(LESS);
7291 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007294 if (d < 0) return Smi::FromInt(LESS);
7295 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296
lrn@chromium.org303ada72010-10-27 09:33:13 +00007297 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007302 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007305 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307}
7308
7309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007310RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317}
7318
7319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327}
7328
7329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007330RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331 NoHandleAllocation ha;
7332 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007335 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337}
7338
7339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340static const double kPiDividedBy4 = 0.78539816339744830962;
7341
7342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007343RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 NoHandleAllocation ha;
7345 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007348 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7349 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 double result;
7351 if (isinf(x) && isinf(y)) {
7352 // Make sure that the result in case of two infinite arguments
7353 // is a multiple of Pi / 4. The sign of the result is determined
7354 // by the first argument (x) and the sign of the second argument
7355 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 int multiplier = (x < 0) ? -1 : 1;
7357 if (y < 0) multiplier *= 3;
7358 result = multiplier * kPiDividedBy4;
7359 } else {
7360 result = atan2(x, y);
7361 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363}
7364
7365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007366RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373}
7374
7375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
7384
7385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
7405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007406RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 NoHandleAllocation ha;
7408 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007411 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007412 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413}
7414
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007415// Slow version of Math.pow. We check for fast paths for special cases.
7416// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007417RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418 NoHandleAllocation ha;
7419 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007422 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007423
7424 // If the second argument is a smi, it is much faster to call the
7425 // custom powi() function than the generic pow().
7426 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007427 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007429 }
7430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007432 int y_int = static_cast<int>(y);
7433 double result;
7434 if (y == y_int) {
7435 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7436 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007437 result = (isinf(x)) ? V8_INFINITY
7438 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007439 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007440 result = (isinf(x)) ? 0
7441 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007442 } else {
7443 result = power_double_double(x, y);
7444 }
7445 if (isnan(result)) return isolate->heap()->nan_value();
7446 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447}
7448
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449// 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 +00007450// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007451RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007452 NoHandleAllocation ha;
7453 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007454 isolate->counters()->math_pow()->Increment();
7455
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007456 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7457 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007458 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007459 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007460 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007461 double result = power_double_double(x, y);
7462 if (isnan(result)) return isolate->heap()->nan_value();
7463 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 }
7465}
7466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007468RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469 NoHandleAllocation ha;
7470 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007473 if (!args[0]->IsHeapNumber()) {
7474 // Must be smi. Return the argument unchanged for all the other types
7475 // to make fuzz-natives test happy.
7476 return args[0];
7477 }
7478
7479 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7480
7481 double value = number->value();
7482 int exponent = number->get_exponent();
7483 int sign = number->get_sign();
7484
danno@chromium.org160a7b02011-04-18 15:51:38 +00007485 if (exponent < -1) {
7486 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7487 if (sign) return isolate->heap()->minus_zero_value();
7488 return Smi::FromInt(0);
7489 }
7490
7491 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7492 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007493 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007494 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007495 return Smi::FromInt(static_cast<int>(value + 0.5));
7496 }
7497
7498 // If the magnitude is big enough, there's no place for fraction part. If we
7499 // try to add 0.5 to this number, 1.0 will be added instead.
7500 if (exponent >= 52) {
7501 return number;
7502 }
7503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007504 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007505
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007506 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007507 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508}
7509
7510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007511RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 NoHandleAllocation ha;
7513 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007516 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007517 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007518}
7519
7520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007521RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522 NoHandleAllocation ha;
7523 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007526 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007527 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528}
7529
7530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 NoHandleAllocation ha;
7533 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007536 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007542 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007543 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007544
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007545 CONVERT_SMI_ARG_CHECKED(year, 0);
7546 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007547
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007548 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549}
7550
7551
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007552RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7553 HandleScope scope(isolate);
7554 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007555
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007556 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7557 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7558 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007560 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007562 Object* value = NULL;
7563 bool is_value_nan = false;
7564 if (isnan(time)) {
7565 value = isolate->heap()->nan_value();
7566 is_value_nan = true;
7567 } else if (!is_utc &&
7568 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7569 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7570 value = isolate->heap()->nan_value();
7571 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007573 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7574 if (time < -DateCache::kMaxTimeInMs ||
7575 time > DateCache::kMaxTimeInMs) {
7576 value = isolate->heap()->nan_value();
7577 is_value_nan = true;
7578 } else {
7579 MaybeObject* maybe_result =
7580 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7581 if (!maybe_result->ToObject(&value)) return maybe_result;
7582 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007583 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007584 date->SetValue(value, is_value_nan);
7585 return *date;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007586}
7587
7588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007589RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007590 HandleScope scope(isolate);
7591 ASSERT(args.length() == 3);
7592
7593 Handle<JSFunction> callee = args.at<JSFunction>(0);
7594 Object** parameters = reinterpret_cast<Object**>(args[1]);
7595 const int argument_count = Smi::cast(args[2])->value();
7596
7597 Handle<JSObject> result =
7598 isolate->factory()->NewArgumentsObject(callee, argument_count);
7599 // Allocate the elements if needed.
7600 int parameter_count = callee->shared()->formal_parameter_count();
7601 if (argument_count > 0) {
7602 if (parameter_count > 0) {
7603 int mapped_count = Min(argument_count, parameter_count);
7604 Handle<FixedArray> parameter_map =
7605 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7606 parameter_map->set_map(
7607 isolate->heap()->non_strict_arguments_elements_map());
7608
7609 Handle<Map> old_map(result->map());
7610 Handle<Map> new_map =
7611 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007612 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007613
7614 result->set_map(*new_map);
7615 result->set_elements(*parameter_map);
7616
7617 // Store the context and the arguments array at the beginning of the
7618 // parameter map.
7619 Handle<Context> context(isolate->context());
7620 Handle<FixedArray> arguments =
7621 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7622 parameter_map->set(0, *context);
7623 parameter_map->set(1, *arguments);
7624
7625 // Loop over the actual parameters backwards.
7626 int index = argument_count - 1;
7627 while (index >= mapped_count) {
7628 // These go directly in the arguments array and have no
7629 // corresponding slot in the parameter map.
7630 arguments->set(index, *(parameters - index - 1));
7631 --index;
7632 }
7633
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007634 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007635 while (index >= 0) {
7636 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007637 Handle<String> name(scope_info->ParameterName(index));
7638 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 bool duplicate = false;
7640 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007642 duplicate = true;
7643 break;
7644 }
7645 }
7646
7647 if (duplicate) {
7648 // This goes directly in the arguments array with a hole in the
7649 // parameter map.
7650 arguments->set(index, *(parameters - index - 1));
7651 parameter_map->set_the_hole(index + 2);
7652 } else {
7653 // The context index goes in the parameter map with a hole in the
7654 // arguments array.
7655 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007656 for (int j = 0; j < context_local_count; ++j) {
7657 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007658 context_index = j;
7659 break;
7660 }
7661 }
7662 ASSERT(context_index >= 0);
7663 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007664 parameter_map->set(index + 2, Smi::FromInt(
7665 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007666 }
7667
7668 --index;
7669 }
7670 } else {
7671 // If there is no aliasing, the arguments object elements are not
7672 // special in any way.
7673 Handle<FixedArray> elements =
7674 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7675 result->set_elements(*elements);
7676 for (int i = 0; i < argument_count; ++i) {
7677 elements->set(i, *(parameters - i - 1));
7678 }
7679 }
7680 }
7681 return *result;
7682}
7683
7684
7685RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007686 NoHandleAllocation ha;
7687 ASSERT(args.length() == 3);
7688
7689 JSFunction* callee = JSFunction::cast(args[0]);
7690 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007691 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007692
lrn@chromium.org303ada72010-10-27 09:33:13 +00007693 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 { MaybeObject* maybe_result =
7695 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007696 if (!maybe_result->ToObject(&result)) return maybe_result;
7697 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007698 // Allocate the elements if needed.
7699 if (length > 0) {
7700 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007701 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007702 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7704 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007705
7706 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007707 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007708 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007709 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007710
7711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007712 for (int i = 0; i < length; i++) {
7713 array->set(i, *--parameters, mode);
7714 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007715 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007716 }
7717 return result;
7718}
7719
7720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007721RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007723 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007724 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7725 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7726 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727
whesse@chromium.org7b260152011-06-20 15:33:18 +00007728 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007729 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007730 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7733 context,
7734 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 return *result;
7736}
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007739// Find the arguments of the JavaScript function invocation that called
7740// into C++ code. Collect these in a newly allocated array of handles (possibly
7741// prefixed by a number of empty handles).
7742static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7743 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007744 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007745 // Find frame containing arguments passed to the caller.
7746 JavaScriptFrameIterator it;
7747 JavaScriptFrame* frame = it.frame();
7748 List<JSFunction*> functions(2);
7749 frame->GetFunctions(&functions);
7750 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007751 int inlined_jsframe_index = functions.length() - 1;
7752 JSFunction* inlined_function = functions[inlined_jsframe_index];
7753 Vector<SlotRef> args_slots =
7754 SlotRef::ComputeSlotMappingForArguments(
7755 frame,
7756 inlined_jsframe_index,
7757 inlined_function->shared()->formal_parameter_count());
7758
7759 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007761 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007762 SmartArrayPointer<Handle<Object> > param_data(
7763 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764 for (int i = 0; i < args_count; i++) {
7765 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007766 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007767 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007768
7769 args_slots.Dispose();
7770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 return param_data;
7772 } else {
7773 it.AdvanceToArgumentsFrame();
7774 frame = it.frame();
7775 int args_count = frame->ComputeParametersCount();
7776
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007777 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007778 SmartArrayPointer<Handle<Object> > param_data(
7779 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007780 for (int i = 0; i < args_count; i++) {
7781 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007782 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007783 }
7784 return param_data;
7785 }
7786}
7787
7788
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007789RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7790 HandleScope scope(isolate);
7791 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007792 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007793 RUNTIME_ASSERT(args[3]->IsNumber());
7794 Handle<Object> bindee = args.at<Object>(1);
7795
7796 // TODO(lrn): Create bound function in C++ code from premade shared info.
7797 bound_function->shared()->set_bound(true);
7798 // Get all arguments of calling function (Function.prototype.bind).
7799 int argc = 0;
7800 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7801 // Don't count the this-arg.
7802 if (argc > 0) {
7803 ASSERT(*arguments[0] == args[2]);
7804 argc--;
7805 } else {
7806 ASSERT(args[2]->IsUndefined());
7807 }
7808 // Initialize array of bindings (function, this, and any existing arguments
7809 // if the function was already bound).
7810 Handle<FixedArray> new_bindings;
7811 int i;
7812 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7813 Handle<FixedArray> old_bindings(
7814 JSFunction::cast(*bindee)->function_bindings());
7815 new_bindings =
7816 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7817 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7818 i = 0;
7819 for (int n = old_bindings->length(); i < n; i++) {
7820 new_bindings->set(i, old_bindings->get(i));
7821 }
7822 } else {
7823 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7824 new_bindings = isolate->factory()->NewFixedArray(array_size);
7825 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7826 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7827 i = 2;
7828 }
7829 // Copy arguments, skipping the first which is "this_arg".
7830 for (int j = 0; j < argc; j++, i++) {
7831 new_bindings->set(i, *arguments[j + 1]);
7832 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007833 new_bindings->set_map_no_write_barrier(
7834 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007835 bound_function->set_function_bindings(*new_bindings);
7836
7837 // Update length.
7838 Handle<String> length_symbol = isolate->factory()->length_symbol();
7839 Handle<Object> new_length(args.at<Object>(3));
7840 PropertyAttributes attr =
7841 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7842 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7843 return *bound_function;
7844}
7845
7846
7847RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7848 HandleScope handles(isolate);
7849 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007850 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007851 if (callable->IsJSFunction()) {
7852 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7853 if (function->shared()->bound()) {
7854 Handle<FixedArray> bindings(function->function_bindings());
7855 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7856 return *isolate->factory()->NewJSArrayWithElements(bindings);
7857 }
7858 }
7859 return isolate->heap()->undefined_value();
7860}
7861
7862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007863RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007865 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007866 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007867 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007868 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007869
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007870 // The argument is a bound function. Extract its bound arguments
7871 // and callable.
7872 Handle<FixedArray> bound_args =
7873 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7874 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7875 Handle<Object> bound_function(
7876 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7877 ASSERT(!bound_function->IsJSFunction() ||
7878 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007880 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007881 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007882 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007883 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007884 param_data[i] = Handle<Object>(bound_args->get(
7885 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007886 }
7887
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007888 if (!bound_function->IsJSFunction()) {
7889 bool exception_thrown;
7890 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7891 &exception_thrown);
7892 if (exception_thrown) return Failure::Exception();
7893 }
7894 ASSERT(bound_function->IsJSFunction());
7895
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007896 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007897 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007898 Execution::New(Handle<JSFunction>::cast(bound_function),
7899 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007900 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007901 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007902 }
7903 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007904 return *result;
7905}
7906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007908static void TrySettingInlineConstructStub(Isolate* isolate,
7909 Handle<JSFunction> function) {
7910 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007911 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007913 }
7914 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007915 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007916 Handle<Code> code = compiler.CompileConstructStub(function);
7917 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007918 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007919}
7920
7921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007922RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924 ASSERT(args.length() == 1);
7925
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007926 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007928 // If the constructor isn't a proper function we throw a type error.
7929 if (!constructor->IsJSFunction()) {
7930 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7931 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007932 isolate->factory()->NewTypeError("not_constructor", arguments);
7933 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007934 }
7935
7936 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007937
7938 // If function should not have prototype, construction is not allowed. In this
7939 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007940 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007941 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7942 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007943 isolate->factory()->NewTypeError("not_constructor", arguments);
7944 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007945 }
7946
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007947#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007949 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007950 if (debug->StepInActive()) {
7951 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007952 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007953#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007955 if (function->has_initial_map()) {
7956 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957 // The 'Function' function ignores the receiver object when
7958 // called using 'new' and creates a new JSFunction object that
7959 // is returned. The receiver object is only used for error
7960 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007961 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007962 // allocate JSFunctions since it does not properly initialize
7963 // the shared part of the function. Since the receiver is
7964 // ignored anyway, we use the global object as the receiver
7965 // instead of a new JSFunction object. This way, errors are
7966 // reported the same way whether or not 'Function' is called
7967 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007968 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007970 }
7971
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007972 // The function should be compiled for the optimization hints to be
7973 // available. We cannot use EnsureCompiled because that forces a
7974 // compilation through the shared function info which makes it
7975 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007976 if (!function->is_compiled()) {
7977 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7978 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007979
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007980 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007981 if (!function->has_initial_map() &&
7982 shared->IsInobjectSlackTrackingInProgress()) {
7983 // The tracking is already in progress for another function. We can only
7984 // track one initial_map at a time, so we force the completion before the
7985 // function is called as a constructor for the first time.
7986 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007987 }
7988
7989 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7991 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007992 // Delay setting the stub if inobject slack tracking is in progress.
7993 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007995 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 isolate->counters()->constructed_objects()->Increment();
7998 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007999
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008000 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008006 ASSERT(args.length() == 1);
8007
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008009 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018 ASSERT(args.length() == 1);
8019
8020 Handle<JSFunction> function = args.at<JSFunction>(0);
8021#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008022 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008024 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 PrintF("]\n");
8026 }
8027#endif
8028
lrn@chromium.org34e60782011-09-15 07:25:40 +00008029 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008031 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 return Failure::Exception();
8033 }
8034
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008035 // All done. Return the compiled code.
8036 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 return function->code();
8038}
8039
8040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008041RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008043 ASSERT(args.length() == 1);
8044 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008045
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008046 function->shared()->set_profiler_ticks(0);
8047
lrn@chromium.org34e60782011-09-15 07:25:40 +00008048 // If the function is not compiled ignore the lazy
8049 // recompilation. This can happen if the debugger is activated and
8050 // the function is returned to the not compiled state.
8051 if (!function->shared()->is_compiled()) {
8052 function->ReplaceCode(function->shared()->code());
8053 return function->code();
8054 }
8055
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008056 // If the function is not optimizable or debugger is active continue using the
8057 // code from the full compiler.
8058 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008059 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008060 if (FLAG_trace_opt) {
8061 PrintF("[failed to optimize ");
8062 function->PrintName();
8063 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8064 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008065 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008066 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008067 function->ReplaceCode(function->shared()->code());
8068 return function->code();
8069 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008070 if (JSFunction::CompileOptimized(function,
8071 AstNode::kNoNumber,
8072 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008073 return function->code();
8074 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008075 if (FLAG_trace_opt) {
8076 PrintF("[failed to optimize ");
8077 function->PrintName();
8078 PrintF(": optimized compilation failed]\n");
8079 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008080 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008081 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008082}
8083
8084
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008085class ActivationsFinder : public ThreadVisitor {
8086 public:
8087 explicit ActivationsFinder(JSFunction* function)
8088 : function_(function), has_activations_(false) {}
8089
8090 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8091 if (has_activations_) return;
8092
8093 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8094 JavaScriptFrame* frame = it.frame();
8095 if (frame->is_optimized() && frame->function() == function_) {
8096 has_activations_ = true;
8097 return;
8098 }
8099 }
8100 }
8101
8102 bool has_activations() { return has_activations_; }
8103
8104 private:
8105 JSFunction* function_;
8106 bool has_activations_;
8107};
8108
8109
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008110static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8111 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008112 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008113 Handle<Object> arguments;
8114 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 if (arguments.is_null()) {
8117 // FunctionGetArguments can't throw an exception, so cast away the
8118 // doubt with an assert.
8119 arguments = Handle<Object>(
8120 Accessors::FunctionGetArguments(*function,
8121 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008122 ASSERT(*arguments != isolate->heap()->null_value());
8123 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008124 }
8125 frame->SetExpression(i, *arguments);
danno@chromium.org88aa0582012-03-23 15:11:57 +00008126 if (FLAG_trace_deopt) {
8127 PrintF("Materializing arguments object for frame %p - %p: %p ",
8128 reinterpret_cast<void*>(frame->sp()),
8129 reinterpret_cast<void*>(frame->fp()),
8130 reinterpret_cast<void*>(*arguments));
8131 arguments->ShortPrint();
8132 PrintF("\n");
8133 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008134 }
8135 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008136}
8137
8138
8139RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8140 HandleScope scope(isolate);
8141 ASSERT(args.length() == 1);
8142 RUNTIME_ASSERT(args[0]->IsSmi());
8143 Deoptimizer::BailoutType type =
8144 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8145 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8146 ASSERT(isolate->heap()->IsAllocationAllowed());
8147 int jsframes = deoptimizer->jsframe_count();
8148
8149 deoptimizer->MaterializeHeapNumbers();
8150 delete deoptimizer;
8151
8152 JavaScriptFrameIterator it(isolate);
8153 for (int i = 0; i < jsframes - 1; i++) {
8154 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8155 it.Advance();
8156 }
8157
8158 JavaScriptFrame* frame = it.frame();
8159 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8160 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8161 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008162
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008163 if (type == Deoptimizer::EAGER) {
8164 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008165 }
8166
8167 // Avoid doing too much work when running with --always-opt and keep
8168 // the optimized code around.
8169 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008170 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 }
8172
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008173 // Find other optimized activations of the function.
8174 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008175 while (!it.done()) {
8176 JavaScriptFrame* frame = it.frame();
8177 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008178 has_other_activations = true;
8179 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008180 }
8181 it.Advance();
8182 }
8183
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008184 if (!has_other_activations) {
8185 ActivationsFinder activations_finder(*function);
8186 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8187 has_other_activations = activations_finder.has_activations();
8188 }
8189
8190 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008191 if (FLAG_trace_deopt) {
8192 PrintF("[removing optimized code for: ");
8193 function->PrintName();
8194 PrintF("]\n");
8195 }
8196 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008197 } else {
8198 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008199 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008201}
8202
8203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008204RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008205 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008206 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208}
8209
8210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008211RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008213 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008214 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216
8217 Deoptimizer::DeoptimizeFunction(*function);
8218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008220}
8221
8222
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008223RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8224#if defined(USE_SIMULATOR)
8225 return isolate->heap()->true_value();
8226#else
8227 return isolate->heap()->false_value();
8228#endif
8229}
8230
8231
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008232RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8233 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008234 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008235 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008236
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008237 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8238 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008239
8240 Code* unoptimized = function->shared()->code();
8241 if (args.length() == 2 &&
8242 unoptimized->kind() == Code::FUNCTION) {
8243 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8244 CHECK(type->IsEqualTo(CStrVector("osr")));
8245 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8246 unoptimized->set_allow_osr_at_loop_nesting_level(
8247 Code::kMaxLoopNestingMarker);
8248 }
8249
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008250 return isolate->heap()->undefined_value();
8251}
8252
8253
lrn@chromium.org1c092762011-05-09 09:42:16 +00008254RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8255 HandleScope scope(isolate);
8256 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008257 // The least significant bit (after untagging) indicates whether the
8258 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008259 if (!V8::UseCrankshaft()) {
8260 return Smi::FromInt(4); // 4 == "never".
8261 }
8262 if (FLAG_always_opt) {
8263 return Smi::FromInt(3); // 3 == "always".
8264 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008265 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008266 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8267 : Smi::FromInt(2); // 2 == "no".
8268}
8269
8270
8271RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8272 HandleScope scope(isolate);
8273 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008274 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008275 return Smi::FromInt(function->shared()->opt_count());
8276}
8277
8278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008279RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008280 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008281 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008282 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008283
8284 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008285 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008286
8287 // We have hit a back edge in an unoptimized frame for a function that was
8288 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008290 // Keep track of whether we've succeeded in optimizing.
8291 bool succeeded = unoptimized->optimizable();
8292 if (succeeded) {
8293 // If we are trying to do OSR when there are already optimized
8294 // activations of the function, it means (a) the function is directly or
8295 // indirectly recursive and (b) an optimized invocation has been
8296 // deoptimized so that we are currently in an unoptimized activation.
8297 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008298 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008299 while (succeeded && !it.done()) {
8300 JavaScriptFrame* frame = it.frame();
8301 succeeded = !frame->is_optimized() || frame->function() != *function;
8302 it.Advance();
8303 }
8304 }
8305
8306 int ast_id = AstNode::kNoNumber;
8307 if (succeeded) {
8308 // The top JS function is this one, the PC is somewhere in the
8309 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008310 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008311 JavaScriptFrame* frame = it.frame();
8312 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008313 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008314 ASSERT(unoptimized->contains(frame->pc()));
8315
8316 // Use linear search of the unoptimized code's stack check table to find
8317 // the AST id matching the PC.
8318 Address start = unoptimized->instruction_start();
8319 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008320 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008321 uint32_t table_length = Memory::uint32_at(table_cursor);
8322 table_cursor += kIntSize;
8323 for (unsigned i = 0; i < table_length; ++i) {
8324 // Table entries are (AST id, pc offset) pairs.
8325 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8326 if (pc_offset == target_pc_offset) {
8327 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8328 break;
8329 }
8330 table_cursor += 2 * kIntSize;
8331 }
8332 ASSERT(ast_id != AstNode::kNoNumber);
8333 if (FLAG_trace_osr) {
8334 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8335 function->PrintName();
8336 PrintF("]\n");
8337 }
8338
8339 // Try to compile the optimized code. A true return value from
8340 // CompileOptimized means that compilation succeeded, not necessarily
8341 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008342 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008343 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008344 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8345 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008346 if (data->OsrPcOffset()->value() >= 0) {
8347 if (FLAG_trace_osr) {
8348 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008349 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008350 }
8351 ASSERT(data->OsrAstId()->value() == ast_id);
8352 } else {
8353 // We may never generate the desired OSR entry if we emit an
8354 // early deoptimize.
8355 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008356 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357 } else {
8358 succeeded = false;
8359 }
8360 }
8361
8362 // Revert to the original stack checks in the original unoptimized code.
8363 if (FLAG_trace_osr) {
8364 PrintF("[restoring original stack checks in ");
8365 function->PrintName();
8366 PrintF("]\n");
8367 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008368 Handle<Code> check_code;
danno@chromium.org88aa0582012-03-23 15:11:57 +00008369#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_ARM)
yangguo@chromium.org56454712012-02-16 15:33:53 +00008370 if (FLAG_count_based_interrupts) {
8371 InterruptStub interrupt_stub;
8372 check_code = interrupt_stub.GetCode();
8373 } else // NOLINT
8374#endif
8375 { // NOLINT
8376 StackCheckStub check_stub;
8377 check_code = check_stub.GetCode();
8378 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008379 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008380 Deoptimizer::RevertStackCheckCode(*unoptimized,
8381 *check_code,
8382 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008383
8384 // Allow OSR only at nesting level zero again.
8385 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8386
8387 // If the optimization attempt succeeded, return the AST id tagged as a
8388 // smi. This tells the builtin that we need to translate the unoptimized
8389 // frame to an optimized one.
8390 if (succeeded) {
8391 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8392 return Smi::FromInt(ast_id);
8393 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008394 if (function->IsMarkedForLazyRecompilation()) {
8395 function->ReplaceCode(function->shared()->code());
8396 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008397 return Smi::FromInt(-1);
8398 }
8399}
8400
8401
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008402RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8403 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8404 return isolate->heap()->undefined_value();
8405}
8406
8407
danno@chromium.orgc612e022011-11-10 11:38:15 +00008408RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8409 HandleScope scope(isolate);
8410 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008411 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008412 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8413 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008414
8415 // If there are too many arguments, allocate argv via malloc.
8416 const int argv_small_size = 10;
8417 Handle<Object> argv_small_buffer[argv_small_size];
8418 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8419 Handle<Object>* argv = argv_small_buffer;
8420 if (argc > argv_small_size) {
8421 argv = new Handle<Object>[argc];
8422 if (argv == NULL) return isolate->StackOverflow();
8423 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8424 }
8425
8426 for (int i = 0; i < argc; ++i) {
8427 MaybeObject* maybe = args[1 + i];
8428 Object* object;
8429 if (!maybe->To<Object>(&object)) return maybe;
8430 argv[i] = Handle<Object>(object);
8431 }
8432
8433 bool threw;
8434 Handle<JSReceiver> hfun(fun);
8435 Handle<Object> hreceiver(receiver);
8436 Handle<Object> result =
8437 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8438
8439 if (threw) return Failure::Exception();
8440 return *result;
8441}
8442
8443
lrn@chromium.org34e60782011-09-15 07:25:40 +00008444RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8445 HandleScope scope(isolate);
8446 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008447 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008448 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008449 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008450 CONVERT_SMI_ARG_CHECKED(offset, 3);
8451 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008452 ASSERT(offset >= 0);
8453 ASSERT(argc >= 0);
8454
8455 // If there are too many arguments, allocate argv via malloc.
8456 const int argv_small_size = 10;
8457 Handle<Object> argv_small_buffer[argv_small_size];
8458 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8459 Handle<Object>* argv = argv_small_buffer;
8460 if (argc > argv_small_size) {
8461 argv = new Handle<Object>[argc];
8462 if (argv == NULL) return isolate->StackOverflow();
8463 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8464 }
8465
8466 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008467 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008468 }
8469
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008470 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008471 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008472 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008473
8474 if (threw) return Failure::Exception();
8475 return *result;
8476}
8477
8478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008479RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008481 ASSERT(args.length() == 1);
8482 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8483 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8484}
8485
8486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008487RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008489 ASSERT(args.length() == 1);
8490 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8491 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8492}
8493
8494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008495RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008497 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008498
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008499 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008500 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008501 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008502 { MaybeObject* maybe_result =
8503 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008504 if (!maybe_result->ToObject(&result)) return maybe_result;
8505 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008507 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508
kasper.lund7276f142008-07-30 08:49:36 +00008509 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008510}
8511
lrn@chromium.org303ada72010-10-27 09:33:13 +00008512
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008513RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8514 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008515 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008516 JSObject* extension_object;
8517 if (args[0]->IsJSObject()) {
8518 extension_object = JSObject::cast(args[0]);
8519 } else {
8520 // Convert the object to a proper JavaScript object.
8521 MaybeObject* maybe_js_object = args[0]->ToObject();
8522 if (!maybe_js_object->To(&extension_object)) {
8523 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8524 HandleScope scope(isolate);
8525 Handle<Object> handle = args.at<Object>(0);
8526 Handle<Object> result =
8527 isolate->factory()->NewTypeError("with_expression",
8528 HandleVector(&handle, 1));
8529 return isolate->Throw(*result);
8530 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008531 return maybe_js_object;
8532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533 }
8534 }
8535
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008536 JSFunction* function;
8537 if (args[1]->IsSmi()) {
8538 // A smi sentinel indicates a context nested inside global code rather
8539 // than some function. There is a canonical empty function that can be
8540 // gotten from the global context.
8541 function = isolate->context()->global_context()->closure();
8542 } else {
8543 function = JSFunction::cast(args[1]);
8544 }
8545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008546 Context* context;
8547 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008548 isolate->heap()->AllocateWithContext(function,
8549 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008550 extension_object);
8551 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008553 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008554}
8555
8556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008557RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008558 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008559 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008560 String* name = String::cast(args[0]);
8561 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008562 JSFunction* function;
8563 if (args[2]->IsSmi()) {
8564 // A smi sentinel indicates a context nested inside global code rather
8565 // than some function. There is a canonical empty function that can be
8566 // gotten from the global context.
8567 function = isolate->context()->global_context()->closure();
8568 } else {
8569 function = JSFunction::cast(args[2]);
8570 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008571 Context* context;
8572 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008573 isolate->heap()->AllocateCatchContext(function,
8574 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008575 name,
8576 thrown_object);
8577 if (!maybe_context->To(&context)) return maybe_context;
8578 isolate->set_context(context);
8579 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008580}
8581
8582
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008583RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8584 NoHandleAllocation ha;
8585 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008586 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008587 JSFunction* function;
8588 if (args[1]->IsSmi()) {
8589 // A smi sentinel indicates a context nested inside global code rather
8590 // than some function. There is a canonical empty function that can be
8591 // gotten from the global context.
8592 function = isolate->context()->global_context()->closure();
8593 } else {
8594 function = JSFunction::cast(args[1]);
8595 }
8596 Context* context;
8597 MaybeObject* maybe_context =
8598 isolate->heap()->AllocateBlockContext(function,
8599 isolate->context(),
8600 scope_info);
8601 if (!maybe_context->To(&context)) return maybe_context;
8602 isolate->set_context(context);
8603 return context;
8604}
8605
8606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008607RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008608 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609 ASSERT(args.length() == 2);
8610
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008611 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8612 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613
8614 int index;
8615 PropertyAttributes attributes;
8616 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008617 BindingFlags binding_flags;
8618 Handle<Object> holder = context->Lookup(name,
8619 flags,
8620 &index,
8621 &attributes,
8622 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008624 // If the slot was not found the result is true.
8625 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008626 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627 }
8628
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008629 // If the slot was found in a context, it should be DONT_DELETE.
8630 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008631 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008632 }
8633
8634 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008635 // the global object, or the subject of a with. Try to delete it
8636 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008637 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008638 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639}
8640
8641
ager@chromium.orga1645e22009-09-09 19:27:10 +00008642// A mechanism to return a pair of Object pointers in registers (if possible).
8643// How this is achieved is calling convention-dependent.
8644// All currently supported x86 compiles uses calling conventions that are cdecl
8645// variants where a 64-bit value is returned in two 32-bit registers
8646// (edx:eax on ia32, r1:r0 on ARM).
8647// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8648// In Win64 calling convention, a struct of two pointers is returned in memory,
8649// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008650#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008651struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008652 MaybeObject* x;
8653 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008654};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008655
lrn@chromium.org303ada72010-10-27 09:33:13 +00008656static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008657 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008658 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8659 // In Win64 they are assigned to a hidden first argument.
8660 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008661}
8662#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008663typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008664static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008666 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008668#endif
8669
8670
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008671static inline MaybeObject* Unhole(Heap* heap,
8672 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008673 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8675 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008676 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677}
8678
8679
danno@chromium.org40cb8782011-05-25 07:58:50 +00008680static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8681 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008682 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008684 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008685 JSFunction* context_extension_function =
8686 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008687 // If the holder isn't a context extension object, we just return it
8688 // as the receiver. This allows arguments objects to be used as
8689 // receivers, but only if they are put in the context scope chain
8690 // explicitly via a with-statement.
8691 Object* constructor = holder->map()->constructor();
8692 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008693 // Fall back to using the global object as the implicit receiver if
8694 // the property turns out to be a local variable allocated in a
8695 // context extension object - introduced via eval. Implicit global
8696 // receivers are indicated with the hole value.
8697 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008698}
8699
8700
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008701static ObjectPair LoadContextSlotHelper(Arguments args,
8702 Isolate* isolate,
8703 bool throw_error) {
8704 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008705 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008707 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008708 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008710 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008711 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712
8713 int index;
8714 PropertyAttributes attributes;
8715 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008716 BindingFlags binding_flags;
8717 Handle<Object> holder = context->Lookup(name,
8718 flags,
8719 &index,
8720 &attributes,
8721 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008722
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008723 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008724 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008725 ASSERT(holder->IsContext());
8726 // If the "property" we were looking for is a local variable, the
8727 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008728 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008729 // Use the hole as the receiver to signal that the receiver is implicit
8730 // and that the global receiver should be used (as distinguished from an
8731 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008732 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008733 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008734 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008735 switch (binding_flags) {
8736 case MUTABLE_CHECK_INITIALIZED:
8737 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8738 if (value->IsTheHole()) {
8739 Handle<Object> reference_error =
8740 isolate->factory()->NewReferenceError("not_defined",
8741 HandleVector(&name, 1));
8742 return MakePair(isolate->Throw(*reference_error), NULL);
8743 }
8744 // FALLTHROUGH
8745 case MUTABLE_IS_INITIALIZED:
8746 case IMMUTABLE_IS_INITIALIZED:
8747 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8748 ASSERT(!value->IsTheHole());
8749 return MakePair(value, *receiver);
8750 case IMMUTABLE_CHECK_INITIALIZED:
8751 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8752 case MISSING_BINDING:
8753 UNREACHABLE();
8754 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756 }
8757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008758 // Otherwise, if the slot was found the holder is a context extension
8759 // object, subject of a with, or a global object. We read the named
8760 // property from it.
8761 if (!holder.is_null()) {
8762 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8763 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008764 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008765 Handle<Object> receiver_handle(object->IsGlobalObject()
8766 ? GlobalObject::cast(*object)->global_receiver()
8767 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008768
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008769 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008770 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008771 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008772 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773 }
8774
8775 if (throw_error) {
8776 // The property doesn't exist - throw exception.
8777 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 isolate->factory()->NewReferenceError("not_defined",
8779 HandleVector(&name, 1));
8780 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008782 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 return MakePair(isolate->heap()->undefined_value(),
8784 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785 }
8786}
8787
8788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008789RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791}
8792
8793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008794RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796}
8797
8798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008799RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008800 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008801 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008804 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8805 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008806 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8807 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8808 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809
8810 int index;
8811 PropertyAttributes attributes;
8812 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008813 BindingFlags binding_flags;
8814 Handle<Object> holder = context->Lookup(name,
8815 flags,
8816 &index,
8817 &attributes,
8818 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819
8820 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008821 // The property was found in a context slot.
8822 Handle<Context> context = Handle<Context>::cast(holder);
8823 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8824 context->get(index)->IsTheHole()) {
8825 Handle<Object> error =
8826 isolate->factory()->NewReferenceError("not_defined",
8827 HandleVector(&name, 1));
8828 return isolate->Throw(*error);
8829 }
8830 // Ignore if read_only variable.
8831 if ((attributes & READ_ONLY) == 0) {
8832 // Context is a fixed array and set cannot fail.
8833 context->set(index, *value);
8834 } else if (strict_mode == kStrictMode) {
8835 // Setting read only property in strict mode.
8836 Handle<Object> error =
8837 isolate->factory()->NewTypeError("strict_cannot_assign",
8838 HandleVector(&name, 1));
8839 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 }
8841 return *value;
8842 }
8843
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008844 // Slow case: The property is not in a context slot. It is either in a
8845 // context extension object, a property of the subject of a with, or a
8846 // property of the global object.
8847 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008849 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008850 // The property exists on the holder.
8851 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008853 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008855
8856 if (strict_mode == kStrictMode) {
8857 // Throw in strict mode (assignment to undefined variable).
8858 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008859 isolate->factory()->NewReferenceError(
8860 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008861 return isolate->Throw(*error);
8862 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008863 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008865 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 }
8867
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008868 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008869 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008870 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008871 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008873 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008874 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008875 // Setting read only property in strict mode.
8876 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008877 isolate->factory()->NewTypeError(
8878 "strict_cannot_assign", HandleVector(&name, 1));
8879 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 }
8881 return *value;
8882}
8883
8884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008885RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887 ASSERT(args.length() == 1);
8888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008890}
8891
8892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008893RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895 ASSERT(args.length() == 1);
8896
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898}
8899
8900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008901RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008902 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008903 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008904}
8905
8906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008907RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008908 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909 ASSERT(args.length() == 1);
8910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008911 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008913 isolate->factory()->NewReferenceError("not_defined",
8914 HandleVector(&name, 1));
8915 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916}
8917
8918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008919RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008920 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921
8922 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008923 if (isolate->stack_guard()->IsStackOverflow()) {
8924 NoHandleAllocation na;
8925 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927
ulan@chromium.org812308e2012-02-29 15:58:45 +00008928 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008929}
8930
8931
yangguo@chromium.org56454712012-02-16 15:33:53 +00008932RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8933 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008934 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008935}
8936
8937
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938static int StackSize() {
8939 int n = 0;
8940 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8941 return n;
8942}
8943
8944
8945static void PrintTransition(Object* result) {
8946 // indentation
8947 { const int nmax = 80;
8948 int n = StackSize();
8949 if (n <= nmax)
8950 PrintF("%4d:%*s", n, n, "");
8951 else
8952 PrintF("%4d:%*s", n, nmax, "...");
8953 }
8954
8955 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008956 JavaScriptFrame::PrintTop(stdout, true, false);
8957 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 } else {
8959 // function result
8960 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008961 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962 PrintF("\n");
8963 }
8964}
8965
8966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008967RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008968 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 NoHandleAllocation ha;
8970 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008971 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972}
8973
8974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008975RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 NoHandleAllocation ha;
8977 PrintTransition(args[0]);
8978 return args[0]; // return TOS
8979}
8980
8981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008982RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 NoHandleAllocation ha;
8984 ASSERT(args.length() == 1);
8985
8986#ifdef DEBUG
8987 if (args[0]->IsString()) {
8988 // If we have a string, assume it's a code "marker"
8989 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008990 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008992 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8993 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994 } else {
8995 PrintF("DebugPrint: ");
8996 }
8997 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008998 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008999 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009000 HeapObject::cast(args[0])->map()->Print();
9001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009002#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009003 // ShortPrint is available in release mode. Print is not.
9004 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005#endif
9006 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009007 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008
9009 return args[0]; // return TOS
9010}
9011
9012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009013RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009014 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016 isolate->PrintStack();
9017 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009018}
9019
9020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009021RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009022 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009023 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024
9025 // According to ECMA-262, section 15.9.1, page 117, the precision of
9026 // the number in a Date object representing a particular instant in
9027 // time is milliseconds. Therefore, we floor the result of getting
9028 // the OS time.
9029 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009030 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031}
9032
9033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009034RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009035 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009036 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009038 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009039 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009041 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009042
9043 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009044 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009045 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009046 RUNTIME_ASSERT(output->HasFastElements());
9047
9048 AssertNoAllocation no_allocation;
9049
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009050 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009051 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9052 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009053 String::FlatContent str_content = str->GetFlatContent();
9054 if (str_content.IsAscii()) {
9055 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009056 output_array,
9057 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009059 ASSERT(str_content.IsTwoByte());
9060 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009061 output_array,
9062 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009063 }
9064
9065 if (result) {
9066 return *output;
9067 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 }
9070}
9071
9072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009073RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 NoHandleAllocation ha;
9075 ASSERT(args.length() == 1);
9076
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009077 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009078 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9079 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009080 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081}
9082
9083
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009084RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 NoHandleAllocation ha;
9086 ASSERT(args.length() == 1);
9087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009088 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009089 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9090
9091 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092}
9093
9094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009095RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009096 ASSERT(args.length() == 1);
9097 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009098 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009099 return JSGlobalObject::cast(global)->global_receiver();
9100}
9101
9102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009103RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009105 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009106 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009107
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009108 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009109 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009110 Handle<Object> result;
9111 if (source->IsSeqAsciiString()) {
9112 result = JsonParser<true>::Parse(source);
9113 } else {
9114 result = JsonParser<false>::Parse(source);
9115 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009116 if (result.is_null()) {
9117 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009119 return Failure::Exception();
9120 }
9121 return *result;
9122}
9123
9124
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009125bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9126 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009127 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9128 // Check with callback if set.
9129 AllowCodeGenerationFromStringsCallback callback =
9130 isolate->allow_code_gen_callback();
9131 if (callback == NULL) {
9132 // No callback set and code generation disallowed.
9133 return false;
9134 } else {
9135 // Callback set. Let it decide if code generation is allowed.
9136 VMState state(isolate, EXTERNAL);
9137 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009138 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009139}
9140
9141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009142RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009143 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009144 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009145 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009146
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009147 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009149
9150 // Check if global context allows code generation from
9151 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009152 if (context->allow_code_gen_from_strings()->IsFalse() &&
9153 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009154 return isolate->Throw(*isolate->factory()->NewError(
9155 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9156 }
9157
9158 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009159 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009160 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009161 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9164 context,
9165 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 return *fun;
9167}
9168
9169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170static ObjectPair CompileGlobalEval(Isolate* isolate,
9171 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009172 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009173 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009174 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009175 Handle<Context> context = Handle<Context>(isolate->context());
9176 Handle<Context> global_context = Handle<Context>(context->global_context());
9177
9178 // Check if global context allows code generation from
9179 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009180 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9181 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009182 isolate->Throw(*isolate->factory()->NewError(
9183 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9184 return MakePair(Failure::Exception(), NULL);
9185 }
9186
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009187 // Deal with a normal eval call with a string argument. Compile it
9188 // and return the compiled function bound in the local context.
9189 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9190 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009191 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009192 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009193 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009194 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009195 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 Handle<JSFunction> compiled =
9197 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009198 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009199 return MakePair(*compiled, *receiver);
9200}
9201
9202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009203RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009204 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009207 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009208
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009209 // If "eval" didn't refer to the original GlobalEval, it's not a
9210 // direct call to eval.
9211 // (And even if it is, but the first argument isn't a string, just let
9212 // execution default to an indirect call to eval, which will also return
9213 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009214 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009215 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009216 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009217 }
9218
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009219 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009220 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009221 return CompileGlobalEval(isolate,
9222 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009223 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009224 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009225 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009226}
9227
9228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009229RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009230 // This utility adjusts the property attributes for newly created Function
9231 // object ("new Function(...)") by changing the map.
9232 // All it does is changing the prototype property to enumerable
9233 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009236 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009237
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009238 Handle<Map> map = func->shared()->is_classic_mode()
9239 ? isolate->function_instance_map()
9240 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241
9242 ASSERT(func->map()->instance_type() == map->instance_type());
9243 ASSERT(func->map()->instance_size() == map->instance_size());
9244 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 return *func;
9246}
9247
9248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009249RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009250 // Allocate a block of memory in NewSpace (filled with a filler).
9251 // Use as fallback for allocation in generated code when NewSpace
9252 // is full.
9253 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009254 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009255 int size = size_smi->value();
9256 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9257 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258 Heap* heap = isolate->heap();
9259 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009260 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009261 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009262 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009263 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009265 }
9266 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009267 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009268}
9269
9270
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009271// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009272// array. Returns true if the element was pushed on the stack and
9273// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009274RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009275 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009276 CONVERT_ARG_CHECKED(JSArray, array, 0);
9277 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009278 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009279 int length = Smi::cast(array->length())->value();
9280 FixedArray* elements = FixedArray::cast(array->elements());
9281 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009282 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009283 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009284 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009285 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009286 { MaybeObject* maybe_obj =
9287 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009288 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9289 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009290 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009291}
9292
9293
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009294/**
9295 * A simple visitor visits every element of Array's.
9296 * The backend storage can be a fixed array for fast elements case,
9297 * or a dictionary for sparse array. Since Dictionary is a subtype
9298 * of FixedArray, the class can be used by both fast and slow cases.
9299 * The second parameter of the constructor, fast_elements, specifies
9300 * whether the storage is a FixedArray or Dictionary.
9301 *
9302 * An index limit is used to deal with the situation that a result array
9303 * length overflows 32-bit non-negative integer.
9304 */
9305class ArrayConcatVisitor {
9306 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 ArrayConcatVisitor(Isolate* isolate,
9308 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009309 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 isolate_(isolate),
9311 storage_(Handle<FixedArray>::cast(
9312 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009313 index_offset_(0u),
9314 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009315
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009316 ~ArrayConcatVisitor() {
9317 clear_storage();
9318 }
9319
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009320 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009321 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009322 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009323
9324 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009325 if (index < static_cast<uint32_t>(storage_->length())) {
9326 storage_->set(index, *elm);
9327 return;
9328 }
9329 // Our initial estimate of length was foiled, possibly by
9330 // getters on the arrays increasing the length of later arrays
9331 // during iteration.
9332 // This shouldn't happen in anything but pathological cases.
9333 SetDictionaryMode(index);
9334 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009335 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009336 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009337 Handle<SeededNumberDictionary> dict(
9338 SeededNumberDictionary::cast(*storage_));
9339 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009341 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009342 // Dictionary needed to grow.
9343 clear_storage();
9344 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 }
9346}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009347
9348 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009349 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9350 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009351 } else {
9352 index_offset_ += delta;
9353 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009354 }
9355
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009356 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009358 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 Handle<Map> map;
9361 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009362 map = isolate_->factory()->GetElementsTransitionMap(array,
9363 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009364 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009365 map = isolate_->factory()->GetElementsTransitionMap(array,
9366 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009367 }
9368 array->set_map(*map);
9369 array->set_length(*length);
9370 array->set_elements(*storage_);
9371 return array;
9372 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009373
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009374 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009375 // Convert storage to dictionary mode.
9376 void SetDictionaryMode(uint32_t index) {
9377 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009378 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009379 Handle<SeededNumberDictionary> slow_storage(
9380 isolate_->factory()->NewSeededNumberDictionary(
9381 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009382 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9383 for (uint32_t i = 0; i < current_length; i++) {
9384 HandleScope loop_scope;
9385 Handle<Object> element(current_storage->get(i));
9386 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009387 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009389 if (!new_storage.is_identical_to(slow_storage)) {
9390 slow_storage = loop_scope.CloseAndEscape(new_storage);
9391 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009392 }
9393 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009394 clear_storage();
9395 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 fast_elements_ = false;
9397 }
9398
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009399 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009400 isolate_->global_handles()->Destroy(
9401 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009402 }
9403
9404 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009405 storage_ = Handle<FixedArray>::cast(
9406 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009407 }
9408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009410 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009411 // Index after last seen index. Always less than or equal to
9412 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009413 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009414 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009415};
9416
9417
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009418static uint32_t EstimateElementCount(Handle<JSArray> array) {
9419 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9420 int element_count = 0;
9421 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009422 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009423 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009424 // Fast elements can't have lengths that are not representable by
9425 // a 32-bit signed integer.
9426 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9427 int fast_length = static_cast<int>(length);
9428 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9429 for (int i = 0; i < fast_length; i++) {
9430 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009431 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009432 break;
9433 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009434 case FAST_DOUBLE_ELEMENTS:
9435 // TODO(1810): Decide if it's worthwhile to implement this.
9436 UNREACHABLE();
9437 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009438 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009439 Handle<SeededNumberDictionary> dictionary(
9440 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009441 int capacity = dictionary->Capacity();
9442 for (int i = 0; i < capacity; i++) {
9443 Handle<Object> key(dictionary->KeyAt(i));
9444 if (dictionary->IsKey(*key)) {
9445 element_count++;
9446 }
9447 }
9448 break;
9449 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009450 case NON_STRICT_ARGUMENTS_ELEMENTS:
9451 case EXTERNAL_BYTE_ELEMENTS:
9452 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9453 case EXTERNAL_SHORT_ELEMENTS:
9454 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9455 case EXTERNAL_INT_ELEMENTS:
9456 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9457 case EXTERNAL_FLOAT_ELEMENTS:
9458 case EXTERNAL_DOUBLE_ELEMENTS:
9459 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009460 // External arrays are always dense.
9461 return length;
9462 }
9463 // As an estimate, we assume that the prototype doesn't contain any
9464 // inherited elements.
9465 return element_count;
9466}
9467
9468
9469
9470template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471static void IterateExternalArrayElements(Isolate* isolate,
9472 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 bool elements_are_ints,
9474 bool elements_are_guaranteed_smis,
9475 ArrayConcatVisitor* visitor) {
9476 Handle<ExternalArrayClass> array(
9477 ExternalArrayClass::cast(receiver->elements()));
9478 uint32_t len = static_cast<uint32_t>(array->length());
9479
9480 ASSERT(visitor != NULL);
9481 if (elements_are_ints) {
9482 if (elements_are_guaranteed_smis) {
9483 for (uint32_t j = 0; j < len; j++) {
9484 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009485 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 visitor->visit(j, e);
9487 }
9488 } else {
9489 for (uint32_t j = 0; j < len; j++) {
9490 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009491 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009492 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9493 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9494 visitor->visit(j, e);
9495 } else {
9496 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009497 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009498 visitor->visit(j, e);
9499 }
9500 }
9501 }
9502 } else {
9503 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009504 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009505 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009506 visitor->visit(j, e);
9507 }
9508 }
9509}
9510
9511
9512// Used for sorting indices in a List<uint32_t>.
9513static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9514 uint32_t a = *ap;
9515 uint32_t b = *bp;
9516 return (a == b) ? 0 : (a < b) ? -1 : 1;
9517}
9518
9519
9520static void CollectElementIndices(Handle<JSObject> object,
9521 uint32_t range,
9522 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009523 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009524 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009525 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009526 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009527 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9528 uint32_t length = static_cast<uint32_t>(elements->length());
9529 if (range < length) length = range;
9530 for (uint32_t i = 0; i < length; i++) {
9531 if (!elements->get(i)->IsTheHole()) {
9532 indices->Add(i);
9533 }
9534 }
9535 break;
9536 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009537 case FAST_DOUBLE_ELEMENTS: {
9538 // TODO(1810): Decide if it's worthwhile to implement this.
9539 UNREACHABLE();
9540 break;
9541 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009542 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009543 Handle<SeededNumberDictionary> dict(
9544 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009545 uint32_t capacity = dict->Capacity();
9546 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009547 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009548 Handle<Object> k(dict->KeyAt(j));
9549 if (dict->IsKey(*k)) {
9550 ASSERT(k->IsNumber());
9551 uint32_t index = static_cast<uint32_t>(k->Number());
9552 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009553 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009554 }
9555 }
9556 }
9557 break;
9558 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009559 default: {
9560 int dense_elements_length;
9561 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009562 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009563 dense_elements_length =
9564 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009565 break;
9566 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009567 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009568 dense_elements_length =
9569 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009570 break;
9571 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009572 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009573 dense_elements_length =
9574 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009575 break;
9576 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009577 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009578 dense_elements_length =
9579 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009580 break;
9581 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009582 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009583 dense_elements_length =
9584 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009585 break;
9586 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009587 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009588 dense_elements_length =
9589 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 break;
9591 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009592 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009593 dense_elements_length =
9594 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009595 break;
9596 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009597 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009598 dense_elements_length =
9599 ExternalFloatArray::cast(object->elements())->length();
9600 break;
9601 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009602 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009603 dense_elements_length =
9604 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 break;
9606 }
9607 default:
9608 UNREACHABLE();
9609 dense_elements_length = 0;
9610 break;
9611 }
9612 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9613 if (range <= length) {
9614 length = range;
9615 // We will add all indices, so we might as well clear it first
9616 // and avoid duplicates.
9617 indices->Clear();
9618 }
9619 for (uint32_t i = 0; i < length; i++) {
9620 indices->Add(i);
9621 }
9622 if (length == range) return; // All indices accounted for already.
9623 break;
9624 }
9625 }
9626
9627 Handle<Object> prototype(object->GetPrototype());
9628 if (prototype->IsJSObject()) {
9629 // The prototype will usually have no inherited element indices,
9630 // but we have to check.
9631 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9632 }
9633}
9634
9635
9636/**
9637 * A helper function that visits elements of a JSArray in numerical
9638 * order.
9639 *
9640 * The visitor argument called for each existing element in the array
9641 * with the element index and the element's value.
9642 * Afterwards it increments the base-index of the visitor by the array
9643 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009644 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646static bool IterateElements(Isolate* isolate,
9647 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 ArrayConcatVisitor* visitor) {
9649 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9650 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009651 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009652 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 // Run through the elements FixedArray and use HasElement and GetElement
9654 // to check the prototype for missing elements.
9655 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9656 int fast_length = static_cast<int>(length);
9657 ASSERT(fast_length <= elements->length());
9658 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 HandleScope loop_scope(isolate);
9660 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 if (!element_value->IsTheHole()) {
9662 visitor->visit(j, element_value);
9663 } else if (receiver->HasElement(j)) {
9664 // Call GetElement on receiver, not its prototype, or getters won't
9665 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009666 element_value = Object::GetElement(receiver, j);
9667 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 visitor->visit(j, element_value);
9669 }
9670 }
9671 break;
9672 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009673 case FAST_DOUBLE_ELEMENTS: {
9674 // TODO(1810): Decide if it's worthwhile to implement this.
9675 UNREACHABLE();
9676 break;
9677 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009678 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009679 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 List<uint32_t> indices(dict->Capacity() / 2);
9681 // Collect all indices in the object and the prototypes less
9682 // than length. This might introduce duplicates in the indices list.
9683 CollectElementIndices(receiver, length, &indices);
9684 indices.Sort(&compareUInt32);
9685 int j = 0;
9686 int n = indices.length();
9687 while (j < n) {
9688 HandleScope loop_scope;
9689 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009690 Handle<Object> element = Object::GetElement(receiver, index);
9691 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 visitor->visit(index, element);
9693 // Skip to next different index (i.e., omit duplicates).
9694 do {
9695 j++;
9696 } while (j < n && indices[j] == index);
9697 }
9698 break;
9699 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009700 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009701 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9702 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009704 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 visitor->visit(j, e);
9706 }
9707 break;
9708 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009709 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 break;
9713 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009714 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009715 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009716 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009717 break;
9718 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009719 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009720 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009721 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009722 break;
9723 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009724 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009726 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009727 break;
9728 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009729 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009732 break;
9733 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009734 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009736 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009737 break;
9738 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009739 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009740 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009741 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009742 break;
9743 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009744 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009745 IterateExternalArrayElements<ExternalDoubleArray, double>(
9746 isolate, receiver, false, false, visitor);
9747 break;
9748 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009749 default:
9750 UNREACHABLE();
9751 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009752 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009754 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009755}
9756
9757
9758/**
9759 * Array::concat implementation.
9760 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009762 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009763 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009764RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009765 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009767
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009768 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009769 int argument_count = static_cast<int>(arguments->length()->Number());
9770 RUNTIME_ASSERT(arguments->HasFastElements());
9771 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009772
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 // Pass 1: estimate the length and number of elements of the result.
9774 // The actual length can be larger if any of the arguments have getters
9775 // that mutate other arguments (but will otherwise be precise).
9776 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009777
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 uint32_t estimate_result_length = 0;
9779 uint32_t estimate_nof_elements = 0;
9780 {
9781 for (int i = 0; i < argument_count; i++) {
9782 HandleScope loop_scope;
9783 Handle<Object> obj(elements->get(i));
9784 uint32_t length_estimate;
9785 uint32_t element_estimate;
9786 if (obj->IsJSArray()) {
9787 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009788 // TODO(1810): Find out if it's worthwhile to properly support
9789 // arbitrary ElementsKinds. For now, pessimistically transition to
9790 // FAST_ELEMENTS.
9791 if (array->HasFastDoubleElements()) {
9792 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009793 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009794 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009795 length_estimate =
9796 static_cast<uint32_t>(array->length()->Number());
9797 element_estimate =
9798 EstimateElementCount(array);
9799 } else {
9800 length_estimate = 1;
9801 element_estimate = 1;
9802 }
9803 // Avoid overflows by capping at kMaxElementCount.
9804 if (JSObject::kMaxElementCount - estimate_result_length <
9805 length_estimate) {
9806 estimate_result_length = JSObject::kMaxElementCount;
9807 } else {
9808 estimate_result_length += length_estimate;
9809 }
9810 if (JSObject::kMaxElementCount - estimate_nof_elements <
9811 element_estimate) {
9812 estimate_nof_elements = JSObject::kMaxElementCount;
9813 } else {
9814 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009815 }
9816 }
9817 }
9818
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009819 // If estimated number of elements is more than half of length, a
9820 // fixed array (fast case) is more time and space-efficient than a
9821 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009822 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009823
9824 Handle<FixedArray> storage;
9825 if (fast_case) {
9826 // The backing storage array must have non-existing elements to
9827 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009828 storage = isolate->factory()->NewFixedArrayWithHoles(
9829 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009830 } else {
9831 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9832 uint32_t at_least_space_for = estimate_nof_elements +
9833 (estimate_nof_elements >> 2);
9834 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009835 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009836 }
9837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009838 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009839
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 for (int i = 0; i < argument_count; i++) {
9841 Handle<Object> obj(elements->get(i));
9842 if (obj->IsJSArray()) {
9843 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009845 return Failure::Exception();
9846 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 } else {
9848 visitor.visit(0, obj);
9849 visitor.increase_index_offset(1);
9850 }
9851 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009852
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009853 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009854}
9855
9856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857// This will not allocate (flatten the string), but it may run
9858// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009859RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860 NoHandleAllocation ha;
9861 ASSERT(args.length() == 1);
9862
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009863 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009864 StringInputBuffer buffer(string);
9865 while (buffer.has_more()) {
9866 uint16_t character = buffer.GetNext();
9867 PrintF("%c", character);
9868 }
9869 return string;
9870}
9871
ager@chromium.org5ec48922009-05-05 07:25:34 +00009872// Moves all own elements of an object, that are below a limit, to positions
9873// starting at zero. All undefined values are placed after non-undefined values,
9874// and are followed by non-existing element. Does not change the length
9875// property.
9876// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009877RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009878 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009879 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009880 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9881 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882}
9883
9884
9885// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009886RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009888 CONVERT_ARG_CHECKED(JSArray, from, 0);
9889 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009890 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009891 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009892 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009893 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9894 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009895 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009896 } else if (new_elements->map() ==
9897 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009898 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009899 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009900 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009901 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009902 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009903 Object* new_map;
9904 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009905 to->set_map(Map::cast(new_map));
9906 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009908 Object* obj;
9909 { MaybeObject* maybe_obj = from->ResetElements();
9910 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9911 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009912 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009913 return to;
9914}
9915
9916
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009917// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009918RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009919 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009920 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009921 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009923 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9924 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009925 } else if (object->IsJSArray()) {
9926 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009927 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009928 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009929 }
9930}
9931
9932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009933RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009935
9936 ASSERT_EQ(3, args.length());
9937
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009938 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009939 Handle<Object> key1 = args.at<Object>(1);
9940 Handle<Object> key2 = args.at<Object>(2);
9941
9942 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009943 if (!key1->ToArrayIndex(&index1)
9944 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009946 }
9947
ager@chromium.orgac091b72010-05-05 07:34:42 +00009948 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009949 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009951 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009953
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009954 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009955 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009956 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009957 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009960}
9961
9962
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009964// might have elements. Can either return keys (positive integers) or
9965// intervals (pair of a negative integer (-start-1) followed by a
9966// positive (length)) or undefined values.
9967// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009968RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009969 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009971 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009972 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009973 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 // Create an array and get all the keys into it, then remove all the
9975 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009976 bool threw = false;
9977 Handle<FixedArray> keys =
9978 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9979 if (threw) return Failure::Exception();
9980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 int keys_length = keys->length();
9982 for (int i = 0; i < keys_length; i++) {
9983 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009984 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009985 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986 // Zap invalid keys.
9987 keys->set_undefined(i);
9988 }
9989 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009992 ASSERT(array->HasFastElements() ||
9993 array->HasFastSmiOnlyElements() ||
9994 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009997 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009998 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009999 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010000 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010001 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010003 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010006 }
10007}
10008
10009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010010RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010011 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010012 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10013 CONVERT_ARG_CHECKED(String, name, 1);
10014 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010015 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10016 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017}
10018
10019
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010020#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010021RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010022 ASSERT(args.length() == 0);
10023 return Execution::DebugBreakHelper();
10024}
10025
10026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027// Helper functions for wrapping and unwrapping stack frame ids.
10028static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010029 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030 return Smi::FromInt(id >> 2);
10031}
10032
10033
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010034static StackFrame::Id UnwrapFrameId(int wrapped) {
10035 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010036}
10037
10038
10039// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010040// args[0]: debug event listener function to set or null or undefined for
10041// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010043RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010044 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010045 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10046 args[0]->IsUndefined() ||
10047 args[0]->IsNull());
10048 Handle<Object> callback = args.at<Object>(0);
10049 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010050 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053}
10054
10055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010056RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010057 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 isolate->stack_guard()->DebugBreak();
10059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010060}
10061
10062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063static MaybeObject* DebugLookupResultValue(Heap* heap,
10064 Object* receiver,
10065 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010066 LookupResult* result,
10067 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010068 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010070 case NORMAL:
10071 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010072 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 }
10075 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010076 case FIELD:
10077 value =
10078 JSObject::cast(
10079 result->holder())->FastPropertyAt(result->GetFieldIndex());
10080 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010081 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010082 }
10083 return value;
10084 case CONSTANT_FUNCTION:
10085 return result->GetConstantFunction();
10086 case CALLBACKS: {
10087 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010088 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010089 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10090 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010091 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010092 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010093 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 maybe_value = heap->isolate()->pending_exception();
10095 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010096 if (caught_exception != NULL) {
10097 *caught_exception = true;
10098 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010099 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010100 }
10101 return value;
10102 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010104 }
10105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010107 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010108 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010109 case CONSTANT_TRANSITION:
10110 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010112 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010113 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010114 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010116 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010117 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010118}
10119
10120
ager@chromium.org32912102009-01-16 10:38:43 +000010121// Get debugger related details for an object property.
10122// args[0]: object holding property
10123// args[1]: name of the property
10124//
10125// The array returned contains the following information:
10126// 0: Property value
10127// 1: Property details
10128// 2: Property value is exception
10129// 3: Getter function if defined
10130// 4: Setter function if defined
10131// Items 2-4 are only filled if the property has either a getter or a setter
10132// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010133RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010134 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135
10136 ASSERT(args.length() == 2);
10137
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010138 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10139 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010141 // Make sure to set the current context to the context before the debugger was
10142 // entered (if the debugger is entered). The reason for switching context here
10143 // is that for some property lookups (accessors and interceptors) callbacks
10144 // into the embedding application can occour, and the embedding application
10145 // could have the assumption that its own global context is the current
10146 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010147 SaveContext save(isolate);
10148 if (isolate->debug()->InDebugger()) {
10149 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010150 }
10151
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010152 // Skip the global proxy as it has no properties and always delegates to the
10153 // real global object.
10154 if (obj->IsJSGlobalProxy()) {
10155 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10156 }
10157
10158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 // Check if the name is trivially convertible to an index and get the element
10160 // if so.
10161 uint32_t index;
10162 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010163 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010164 Object* element_or_char;
10165 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010167 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10168 return maybe_element_or_char;
10169 }
10170 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010171 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174 }
10175
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010176 // Find the number of objects making up this.
10177 int length = LocalPrototypeChainLength(*obj);
10178
10179 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010180 Handle<JSObject> jsproto = obj;
10181 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010182 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010183 jsproto->LocalLookup(*name, &result);
10184 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010185 // LookupResult is not GC safe as it holds raw object pointers.
10186 // GC can happen later in this code so put the required fields into
10187 // local variables using handles when required for later use.
10188 PropertyType result_type = result.type();
10189 Handle<Object> result_callback_obj;
10190 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010191 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10192 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010193 }
10194 Smi* property_details = result.GetPropertyDetails().AsSmi();
10195 // DebugLookupResultValue can cause GC so details from LookupResult needs
10196 // to be copied to handles before this.
10197 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010198 Object* raw_value;
10199 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010200 DebugLookupResultValue(isolate->heap(), *obj, *name,
10201 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010202 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10203 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010205
10206 // If the callback object is a fixed array then it contains JavaScript
10207 // getter and/or setter.
10208 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010209 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010210 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010211 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010212 details->set(0, *value);
10213 details->set(1, property_details);
10214 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010215 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010216 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010217 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10218 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010219 }
10220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010222 }
10223 if (i < length - 1) {
10224 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10225 }
10226 }
10227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229}
10230
10231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010232RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234
10235 ASSERT(args.length() == 2);
10236
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010237 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10238 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010240 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 obj->Lookup(*name, &result);
10242 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010246}
10247
10248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249// Return the property type calculated from the property details.
10250// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010251RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010253 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10254 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255}
10256
10257
10258// Return the property attribute calculated from the property details.
10259// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010260RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010262 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10263 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264}
10265
10266
10267// Return the property insertion index calculated from the property details.
10268// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010269RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010271 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10272 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273}
10274
10275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276// Return property value from named interceptor.
10277// args[0]: object
10278// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010279RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010280 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010282 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010284 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285
10286 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010287 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288}
10289
10290
10291// Return element value from indexed interceptor.
10292// args[0]: object
10293// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010294RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010297 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10299 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10300
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010301 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302}
10303
10304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010305RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306 ASSERT(args.length() >= 1);
10307 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010308 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010309 if (isolate->debug()->break_id() == 0 ||
10310 break_id != isolate->debug()->break_id()) {
10311 return isolate->Throw(
10312 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 }
10314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316}
10317
10318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010319RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 ASSERT(args.length() == 1);
10322
10323 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010324 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010325 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10326 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010327 if (!maybe_result->ToObject(&result)) return maybe_result;
10328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329
10330 // Count all frames which are relevant to debugging stack trace.
10331 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010333 if (id == StackFrame::NO_ID) {
10334 // If there is no JavaScript stack frame count is 0.
10335 return Smi::FromInt(0);
10336 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010337
10338 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10339 n += it.frame()->GetInlineCount();
10340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 return Smi::FromInt(n);
10342}
10343
10344
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010345class FrameInspector {
10346 public:
10347 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010348 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010349 Isolate* isolate)
10350 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10351 // Calculate the deoptimized frame.
10352 if (frame->is_optimized()) {
10353 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010354 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010355 }
10356 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010357 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010358 is_optimized_ = frame_->is_optimized();
10359 }
10360
10361 ~FrameInspector() {
10362 // Get rid of the calculated deoptimized frame if any.
10363 if (deoptimized_frame_ != NULL) {
10364 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10365 isolate_);
10366 }
10367 }
10368
10369 int GetParametersCount() {
10370 return is_optimized_
10371 ? deoptimized_frame_->parameters_count()
10372 : frame_->ComputeParametersCount();
10373 }
10374 int expression_count() { return deoptimized_frame_->expression_count(); }
10375 Object* GetFunction() {
10376 return is_optimized_
10377 ? deoptimized_frame_->GetFunction()
10378 : frame_->function();
10379 }
10380 Object* GetParameter(int index) {
10381 return is_optimized_
10382 ? deoptimized_frame_->GetParameter(index)
10383 : frame_->GetParameter(index);
10384 }
10385 Object* GetExpression(int index) {
10386 return is_optimized_
10387 ? deoptimized_frame_->GetExpression(index)
10388 : frame_->GetExpression(index);
10389 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010390 int GetSourcePosition() {
10391 return is_optimized_
10392 ? deoptimized_frame_->GetSourcePosition()
10393 : frame_->LookupCode()->SourcePosition(frame_->pc());
10394 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010395 bool IsConstructor() {
10396 return is_optimized_ && !is_bottommost_
10397 ? deoptimized_frame_->HasConstructStub()
10398 : frame_->IsConstructor();
10399 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010400
10401 // To inspect all the provided arguments the frame might need to be
10402 // replaced with the arguments frame.
10403 void SetArgumentsFrame(JavaScriptFrame* frame) {
10404 ASSERT(has_adapted_arguments_);
10405 frame_ = frame;
10406 is_optimized_ = frame_->is_optimized();
10407 ASSERT(!is_optimized_);
10408 }
10409
10410 private:
10411 JavaScriptFrame* frame_;
10412 DeoptimizedFrameInfo* deoptimized_frame_;
10413 Isolate* isolate_;
10414 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010415 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010416 bool has_adapted_arguments_;
10417
10418 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10419};
10420
10421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010422static const int kFrameDetailsFrameIdIndex = 0;
10423static const int kFrameDetailsReceiverIndex = 1;
10424static const int kFrameDetailsFunctionIndex = 2;
10425static const int kFrameDetailsArgumentCountIndex = 3;
10426static const int kFrameDetailsLocalCountIndex = 4;
10427static const int kFrameDetailsSourcePositionIndex = 5;
10428static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010429static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010430static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010431static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010433
10434static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10435 JavaScriptFrame* frame) {
10436 SaveContext* save = isolate->save_context();
10437 while (save != NULL && !save->IsBelowFrame(frame)) {
10438 save = save->prev();
10439 }
10440 ASSERT(save != NULL);
10441 return save;
10442}
10443
10444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445// Return an array with frame details
10446// args[0]: number: break id
10447// args[1]: number: frame index
10448//
10449// The array returned contains the following information:
10450// 0: Frame id
10451// 1: Receiver
10452// 2: Function
10453// 3: Argument count
10454// 4: Local count
10455// 5: Source position
10456// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010457// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010458// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459// Arguments name, value
10460// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010461// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010462RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 ASSERT(args.length() == 2);
10465
10466 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010467 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010468 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10469 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010470 if (!maybe_check->ToObject(&check)) return maybe_check;
10471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474
10475 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010477 if (id == StackFrame::NO_ID) {
10478 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010480 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010481
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010482 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010483 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010484 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010485 if (index < count + it.frame()->GetInlineCount()) break;
10486 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010487 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010488 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010489
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010490 bool is_optimized = it.frame()->is_optimized();
10491
10492 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10493 if (is_optimized) {
10494 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010495 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010496 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010497 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010498
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010499 // Traverse the saved contexts chain to find the active context for the
10500 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010501 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010502
10503 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010504 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010506 // Find source position in unoptimized code.
10507 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508
ulan@chromium.org967e2702012-02-28 09:49:15 +000010509 // Check for constructor frame.
10510 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010512 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010513 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010514 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010515 Handle<ScopeInfo> scope_info(shared->scope_info());
10516 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 // Get the locals names and values into a temporary array.
10519 //
10520 // TODO(1240907): Hide compiler-introduced stack variables
10521 // (e.g. .result)? For users of the debugger, they will probably be
10522 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010524 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010526 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010527 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010528 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010529 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010530 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010531 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010532 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010533 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010534 // Get the context containing declarations.
10535 Handle<Context> context(
10536 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010537 for (; i < scope_info->LocalCount(); ++i) {
10538 Handle<String> name(scope_info->LocalName(i));
10539 VariableMode mode;
10540 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010541 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010542 locals->set(i * 2 + 1, context->get(
10543 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544 }
10545 }
10546
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010547 // Check whether this frame is positioned at return. If not top
10548 // frame or if the frame is optimized it cannot be at a return.
10549 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010550 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010551 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010552 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010553
10554 // If positioned just before return find the value to be returned and add it
10555 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010556 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010557 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010558 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010559 Address internal_frame_sp = NULL;
10560 while (!it2.done()) {
10561 if (it2.frame()->is_internal()) {
10562 internal_frame_sp = it2.frame()->sp();
10563 } else {
10564 if (it2.frame()->is_java_script()) {
10565 if (it2.frame()->id() == it.frame()->id()) {
10566 // The internal frame just before the JavaScript frame contains the
10567 // value to return on top. A debug break at return will create an
10568 // internal frame to store the return value (eax/rax/r0) before
10569 // entering the debug break exit frame.
10570 if (internal_frame_sp != NULL) {
10571 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 Handle<Object>(Memory::Object_at(internal_frame_sp),
10573 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010574 break;
10575 }
10576 }
10577 }
10578
10579 // Indicate that the previous frame was not an internal frame.
10580 internal_frame_sp = NULL;
10581 }
10582 it2.Advance();
10583 }
10584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585
10586 // Now advance to the arguments adapter frame (if any). It contains all
10587 // the provided parameters whereas the function frame always have the number
10588 // of arguments matching the functions parameters. The rest of the
10589 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010590 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010591 it.AdvanceToArgumentsFrame();
10592 frame_inspector.SetArgumentsFrame(it.frame());
10593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
10595 // Find the number of arguments to fill. At least fill the number of
10596 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010597 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010598 if (argument_count < frame_inspector.GetParametersCount()) {
10599 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 }
10601
10602 // Calculate the size of the result.
10603 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010604 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010605 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010606 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
10608 // Add the frame id.
10609 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10610
10611 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010612 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613
10614 // Add the arguments count.
10615 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10616
10617 // Add the locals count
10618 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010619 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620
10621 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010622 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10624 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 }
10627
10628 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010629 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010631 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010633
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010634 // Add flags to indicate information on whether this frame is
10635 // bit 0: invoked in the debugger context.
10636 // bit 1: optimized frame.
10637 // bit 2: inlined in optimized frame
10638 int flags = 0;
10639 if (*save->context() == *isolate->debug()->debug_context()) {
10640 flags |= 1 << 0;
10641 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010642 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010643 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010644 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010645 }
10646 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647
10648 // Fill the dynamic part.
10649 int details_index = kFrameDetailsFirstDynamicIndex;
10650
10651 // Add arguments name and value.
10652 for (int i = 0; i < argument_count; i++) {
10653 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010654 if (i < scope_info->ParameterCount()) {
10655 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658 }
10659
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010660 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010661 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010662 // Get the value from the stack.
10663 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010665 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010666 }
10667 }
10668
10669 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010670 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 details->set(details_index++, locals->get(i));
10672 }
10673
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010674 // Add the value being returned.
10675 if (at_return) {
10676 details->set(details_index++, *return_value);
10677 }
10678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 // Add the receiver (same as in function frame).
10680 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10681 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010683 if (!receiver->IsJSObject() &&
10684 shared->is_classic_mode() &&
10685 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010686 // If the receiver is not a JSObject and the function is not a
10687 // builtin or strict-mode we have hit an optimization where a
10688 // value object is not converted into a wrapped JS objects. To
10689 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690 // by creating correct wrapper object based on the calling frame's
10691 // global context.
10692 it.Advance();
10693 Handle<Context> calling_frames_global_context(
10694 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 receiver =
10696 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010697 }
10698 details->set(kFrameDetailsReceiverIndex, *receiver);
10699
10700 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010701 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702}
10703
10704
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010705// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010706static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010707 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010708 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010709 Handle<Context> context,
10710 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010711 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010712 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10713 VariableMode mode;
10714 InitializationFlag init_flag;
10715 int context_index = scope_info->ContextSlotIndex(
10716 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010717
whesse@chromium.org7b260152011-06-20 15:33:18 +000010718 RETURN_IF_EMPTY_HANDLE_VALUE(
10719 isolate,
10720 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010721 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010722 Handle<Object>(context->get(context_index), isolate),
10723 NONE,
10724 kNonStrictMode),
10725 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010726 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010727
10728 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729}
10730
10731
10732// Create a plain JSObject which materializes the local scope for the specified
10733// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010734static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010735 Isolate* isolate,
10736 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010737 FrameInspector* frame_inspector) {
10738 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010739 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010740 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010741
10742 // Allocate and initialize a JSObject with all the arguments, stack locals
10743 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010744 Handle<JSObject> local_scope =
10745 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010746
10747 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010748 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010749 Handle<Object> value(
10750 i < frame_inspector->GetParametersCount() ?
10751 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10752
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010753 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010754 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010755 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010756 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010757 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010758 NONE,
10759 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010760 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010761 }
10762
10763 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010764 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010765 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010767 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010768 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010769 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010770 NONE,
10771 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010772 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010773 }
10774
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010775 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010776 // Third fill all context locals.
10777 Handle<Context> frame_context(Context::cast(frame->context()));
10778 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010779 if (!CopyContextLocalsToScopeObject(
10780 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010781 return Handle<JSObject>();
10782 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010783
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010784 // Finally copy any properties from the function context extension.
10785 // These will be variables introduced by eval.
10786 if (function_context->closure() == *function) {
10787 if (function_context->has_extension() &&
10788 !function_context->IsGlobalContext()) {
10789 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010790 bool threw = false;
10791 Handle<FixedArray> keys =
10792 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10793 if (threw) return Handle<JSObject>();
10794
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010795 for (int i = 0; i < keys->length(); i++) {
10796 // Names of variables introduced by eval are strings.
10797 ASSERT(keys->get(i)->IsString());
10798 Handle<String> key(String::cast(keys->get(i)));
10799 RETURN_IF_EMPTY_HANDLE_VALUE(
10800 isolate,
10801 SetProperty(local_scope,
10802 key,
10803 GetProperty(ext, key),
10804 NONE,
10805 kNonStrictMode),
10806 Handle<JSObject>());
10807 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010808 }
10809 }
10810 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010811
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010812 return local_scope;
10813}
10814
10815
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010816static Handle<JSObject> MaterializeLocalScope(
10817 Isolate* isolate,
10818 JavaScriptFrame* frame,
10819 int inlined_jsframe_index) {
10820 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10821 return MaterializeLocalScopeWithFrameInspector(isolate,
10822 frame,
10823 &frame_inspector);
10824}
10825
10826
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010827// Create a plain JSObject which materializes the closure content for the
10828// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010829static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10830 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010831 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010832
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010833 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010834 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010835
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010836 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010837 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 Handle<JSObject> closure_scope =
10839 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010840
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010841 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010842 if (!CopyContextLocalsToScopeObject(
10843 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010844 return Handle<JSObject>();
10845 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010846
10847 // Finally copy any properties from the function context extension. This will
10848 // be variables introduced by eval.
10849 if (context->has_extension()) {
10850 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010851 bool threw = false;
10852 Handle<FixedArray> keys =
10853 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10854 if (threw) return Handle<JSObject>();
10855
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010856 for (int i = 0; i < keys->length(); i++) {
10857 // Names of variables introduced by eval are strings.
10858 ASSERT(keys->get(i)->IsString());
10859 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 RETURN_IF_EMPTY_HANDLE_VALUE(
10861 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010862 SetProperty(closure_scope,
10863 key,
10864 GetProperty(ext, key),
10865 NONE,
10866 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010867 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010868 }
10869 }
10870
10871 return closure_scope;
10872}
10873
10874
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010875// Create a plain JSObject which materializes the scope for the specified
10876// catch context.
10877static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10878 Handle<Context> context) {
10879 ASSERT(context->IsCatchContext());
10880 Handle<String> name(String::cast(context->extension()));
10881 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10882 Handle<JSObject> catch_scope =
10883 isolate->factory()->NewJSObject(isolate->object_function());
10884 RETURN_IF_EMPTY_HANDLE_VALUE(
10885 isolate,
10886 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10887 Handle<JSObject>());
10888 return catch_scope;
10889}
10890
10891
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010892// Create a plain JSObject which materializes the block scope for the specified
10893// block context.
10894static Handle<JSObject> MaterializeBlockScope(
10895 Isolate* isolate,
10896 Handle<Context> context) {
10897 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010898 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010899
10900 // Allocate and initialize a JSObject with all the arguments, stack locals
10901 // heap locals and extension properties of the debugged function.
10902 Handle<JSObject> block_scope =
10903 isolate->factory()->NewJSObject(isolate->object_function());
10904
10905 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010906 if (!CopyContextLocalsToScopeObject(
10907 isolate, scope_info, context, block_scope)) {
10908 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010909 }
10910
10911 return block_scope;
10912}
10913
10914
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010915// Create a plain JSObject which materializes the module scope for the specified
10916// module context.
10917static Handle<JSObject> MaterializeModuleScope(
10918 Isolate* isolate,
10919 Handle<Context> context) {
10920 ASSERT(context->IsModuleContext());
10921 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10922
10923 // Allocate and initialize a JSObject with all the members of the debugged
10924 // module.
10925 Handle<JSObject> module_scope =
10926 isolate->factory()->NewJSObject(isolate->object_function());
10927
10928 // Fill all context locals.
10929 if (!CopyContextLocalsToScopeObject(
10930 isolate, scope_info, context, module_scope)) {
10931 return Handle<JSObject>();
10932 }
10933
10934 return module_scope;
10935}
10936
10937
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010938// Iterate over the actual scopes visible from a stack frame. The iteration
10939// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010940// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010941// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010942class ScopeIterator {
10943 public:
10944 enum ScopeType {
10945 ScopeTypeGlobal = 0,
10946 ScopeTypeLocal,
10947 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010948 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010949 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010950 ScopeTypeBlock,
10951 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010952 };
10953
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010954 ScopeIterator(Isolate* isolate,
10955 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010956 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010957 : isolate_(isolate),
10958 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010959 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010960 function_(JSFunction::cast(frame->function())),
10961 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010962 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010963
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010964 // Catch the case when the debugger stops in an internal function.
10965 Handle<SharedFunctionInfo> shared_info(function_->shared());
10966 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10967 if (shared_info->script() == isolate->heap()->undefined_value()) {
10968 while (context_->closure() == *function_) {
10969 context_ = Handle<Context>(context_->previous(), isolate_);
10970 }
10971 return;
10972 }
10973
10974 // Get the debug info (create it if it does not exist).
10975 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10976 // Return if ensuring debug info failed.
10977 return;
10978 }
10979 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10980
10981 // Find the break point where execution has stopped.
10982 BreakLocationIterator break_location_iterator(debug_info,
10983 ALL_BREAK_LOCATIONS);
10984 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10985 if (break_location_iterator.IsExit()) {
10986 // We are within the return sequence. At the momemt it is not possible to
10987 // get a source position which is consistent with the current scope chain.
10988 // Thus all nested with, catch and block contexts are skipped and we only
10989 // provide the function scope.
10990 if (scope_info->HasContext()) {
10991 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10992 } else {
10993 while (context_->closure() == *function_) {
10994 context_ = Handle<Context>(context_->previous(), isolate_);
10995 }
10996 }
10997 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10998 } else {
10999 // Reparse the code and analyze the scopes.
11000 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11001 Handle<Script> script(Script::cast(shared_info->script()));
11002 Scope* scope = NULL;
11003
11004 // Check whether we are in global, eval or function code.
11005 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11006 if (scope_info->Type() != FUNCTION_SCOPE) {
11007 // Global or eval code.
11008 CompilationInfo info(script);
11009 if (scope_info->Type() == GLOBAL_SCOPE) {
11010 info.MarkAsGlobal();
11011 } else {
11012 ASSERT(scope_info->Type() == EVAL_SCOPE);
11013 info.MarkAsEval();
11014 info.SetCallingContext(Handle<Context>(function_->context()));
11015 }
11016 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11017 scope = info.function()->scope();
11018 }
11019 } else {
11020 // Function code
11021 CompilationInfo info(shared_info);
11022 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11023 scope = info.function()->scope();
11024 }
11025 }
11026
11027 // Retrieve the scope chain for the current position.
11028 if (scope != NULL) {
11029 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11030 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11031 } else {
11032 // A failed reparse indicates that the preparser has diverged from the
11033 // parser or that the preparse data given to the initial parse has been
11034 // faulty. We fail in debug mode but in release mode we only provide the
11035 // information we get from the context chain but nothing about
11036 // completely stack allocated scopes or stack allocated locals.
11037 UNREACHABLE();
11038 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011039 }
11040 }
11041
11042 // More scopes?
11043 bool Done() { return context_.is_null(); }
11044
11045 // Move to the next scope.
11046 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011047 ScopeType scope_type = Type();
11048 if (scope_type == ScopeTypeGlobal) {
11049 // The global scope is always the last in the chain.
11050 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011051 context_ = Handle<Context>();
11052 return;
11053 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011054 if (nested_scope_chain_.is_empty()) {
11055 context_ = Handle<Context>(context_->previous(), isolate_);
11056 } else {
11057 if (nested_scope_chain_.last()->HasContext()) {
11058 ASSERT(context_->previous() != NULL);
11059 context_ = Handle<Context>(context_->previous(), isolate_);
11060 }
11061 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011062 }
11063 }
11064
11065 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011066 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011067 if (!nested_scope_chain_.is_empty()) {
11068 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11069 switch (scope_info->Type()) {
11070 case FUNCTION_SCOPE:
11071 ASSERT(context_->IsFunctionContext() ||
11072 !scope_info->HasContext());
11073 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011074 case MODULE_SCOPE:
11075 ASSERT(context_->IsModuleContext());
11076 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011077 case GLOBAL_SCOPE:
11078 ASSERT(context_->IsGlobalContext());
11079 return ScopeTypeGlobal;
11080 case WITH_SCOPE:
11081 ASSERT(context_->IsWithContext());
11082 return ScopeTypeWith;
11083 case CATCH_SCOPE:
11084 ASSERT(context_->IsCatchContext());
11085 return ScopeTypeCatch;
11086 case BLOCK_SCOPE:
11087 ASSERT(!scope_info->HasContext() ||
11088 context_->IsBlockContext());
11089 return ScopeTypeBlock;
11090 case EVAL_SCOPE:
11091 UNREACHABLE();
11092 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011093 }
11094 if (context_->IsGlobalContext()) {
11095 ASSERT(context_->global()->IsGlobalObject());
11096 return ScopeTypeGlobal;
11097 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011098 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011099 return ScopeTypeClosure;
11100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011101 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011102 return ScopeTypeCatch;
11103 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011104 if (context_->IsBlockContext()) {
11105 return ScopeTypeBlock;
11106 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011107 if (context_->IsModuleContext()) {
11108 return ScopeTypeModule;
11109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011110 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011111 return ScopeTypeWith;
11112 }
11113
11114 // Return the JavaScript object with the content of the current scope.
11115 Handle<JSObject> ScopeObject() {
11116 switch (Type()) {
11117 case ScopeIterator::ScopeTypeGlobal:
11118 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011119 case ScopeIterator::ScopeTypeLocal:
11120 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011121 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011122 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123 case ScopeIterator::ScopeTypeWith:
11124 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011125 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11126 case ScopeIterator::ScopeTypeCatch:
11127 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128 case ScopeIterator::ScopeTypeClosure:
11129 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011131 case ScopeIterator::ScopeTypeBlock:
11132 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011133 case ScopeIterator::ScopeTypeModule:
11134 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011135 }
11136 UNREACHABLE();
11137 return Handle<JSObject>();
11138 }
11139
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011140 Handle<ScopeInfo> CurrentScopeInfo() {
11141 if (!nested_scope_chain_.is_empty()) {
11142 return nested_scope_chain_.last();
11143 } else if (context_->IsBlockContext()) {
11144 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11145 } else if (context_->IsFunctionContext()) {
11146 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11147 }
11148 return Handle<ScopeInfo>::null();
11149 }
11150
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011151 // Return the context for this scope. For the local context there might not
11152 // be an actual context.
11153 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011154 if (Type() == ScopeTypeGlobal ||
11155 nested_scope_chain_.is_empty()) {
11156 return context_;
11157 } else if (nested_scope_chain_.last()->HasContext()) {
11158 return context_;
11159 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011160 return Handle<Context>();
11161 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011162 }
11163
11164#ifdef DEBUG
11165 // Debug print of the content of the current scope.
11166 void DebugPrint() {
11167 switch (Type()) {
11168 case ScopeIterator::ScopeTypeGlobal:
11169 PrintF("Global:\n");
11170 CurrentContext()->Print();
11171 break;
11172
11173 case ScopeIterator::ScopeTypeLocal: {
11174 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011175 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011176 if (!CurrentContext().is_null()) {
11177 CurrentContext()->Print();
11178 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011179 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 if (extension->IsJSContextExtensionObject()) {
11181 extension->Print();
11182 }
11183 }
11184 }
11185 break;
11186 }
11187
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011188 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011190 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011191 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011193 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011194 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011195 CurrentContext()->extension()->Print();
11196 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011197 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011198
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011199 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011200 PrintF("Closure:\n");
11201 CurrentContext()->Print();
11202 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011203 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011204 if (extension->IsJSContextExtensionObject()) {
11205 extension->Print();
11206 }
11207 }
11208 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209
11210 default:
11211 UNREACHABLE();
11212 }
11213 PrintF("\n");
11214 }
11215#endif
11216
11217 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011219 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011220 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011221 Handle<JSFunction> function_;
11222 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011223 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011224
11225 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11226};
11227
11228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011229RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011230 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011231 ASSERT(args.length() == 2);
11232
11233 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011234 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011235 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11236 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011237 if (!maybe_check->ToObject(&check)) return maybe_check;
11238 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011239 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240
11241 // Get the frame where the debugging is performed.
11242 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011243 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011244 JavaScriptFrame* frame = it.frame();
11245
11246 // Count the visible scopes.
11247 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011248 for (ScopeIterator it(isolate, frame, 0);
11249 !it.Done();
11250 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011251 n++;
11252 }
11253
11254 return Smi::FromInt(n);
11255}
11256
11257
11258static const int kScopeDetailsTypeIndex = 0;
11259static const int kScopeDetailsObjectIndex = 1;
11260static const int kScopeDetailsSize = 2;
11261
11262// Return an array with scope details
11263// args[0]: number: break id
11264// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011265// args[2]: number: inlined frame index
11266// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011267//
11268// The array returned contains the following information:
11269// 0: Scope type
11270// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011271RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011273 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011274
11275 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011276 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011277 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11278 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011279 if (!maybe_check->ToObject(&check)) return maybe_check;
11280 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011281 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011282 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011283 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011284
11285 // Get the frame where the debugging is performed.
11286 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011287 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011288 JavaScriptFrame* frame = frame_it.frame();
11289
11290 // Find the requested scope.
11291 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011292 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011293 for (; !it.Done() && n < index; it.Next()) {
11294 n++;
11295 }
11296 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011297 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011298 }
11299
11300 // Calculate the size of the result.
11301 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011303
11304 // Fill in scope details.
11305 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011306 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011308 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011311}
11312
11313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011316 ASSERT(args.length() == 0);
11317
11318#ifdef DEBUG
11319 // Print the scopes for the top frame.
11320 StackFrameLocator locator;
11321 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011322 for (ScopeIterator it(isolate, frame, 0);
11323 !it.Done();
11324 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011325 it.DebugPrint();
11326 }
11327#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011329}
11330
11331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011332RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011334 ASSERT(args.length() == 1);
11335
11336 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011337 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011338 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11339 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011340 if (!maybe_result->ToObject(&result)) return maybe_result;
11341 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011342
11343 // Count all archived V8 threads.
11344 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 for (ThreadState* thread =
11346 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011347 thread != NULL;
11348 thread = thread->Next()) {
11349 n++;
11350 }
11351
11352 // Total number of threads is current thread and archived threads.
11353 return Smi::FromInt(n + 1);
11354}
11355
11356
11357static const int kThreadDetailsCurrentThreadIndex = 0;
11358static const int kThreadDetailsThreadIdIndex = 1;
11359static const int kThreadDetailsSize = 2;
11360
11361// Return an array with thread details
11362// args[0]: number: break id
11363// args[1]: number: thread index
11364//
11365// The array returned contains the following information:
11366// 0: Is current thread?
11367// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011368RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011369 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011370 ASSERT(args.length() == 2);
11371
11372 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011373 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011374 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11375 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011376 if (!maybe_check->ToObject(&check)) return maybe_check;
11377 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011378 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11379
11380 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 Handle<FixedArray> details =
11382 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011383
11384 // Thread index 0 is current thread.
11385 if (index == 0) {
11386 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011387 details->set(kThreadDetailsCurrentThreadIndex,
11388 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011389 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011390 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011391 } else {
11392 // Find the thread with the requested index.
11393 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 ThreadState* thread =
11395 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011396 while (index != n && thread != NULL) {
11397 thread = thread->Next();
11398 n++;
11399 }
11400 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011402 }
11403
11404 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 details->set(kThreadDetailsCurrentThreadIndex,
11406 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011407 details->set(kThreadDetailsThreadIdIndex,
11408 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011409 }
11410
11411 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011413}
11414
11415
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011416// Sets the disable break state
11417// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011418RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011419 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011420 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011421 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011422 isolate->debug()->set_disable_break(disable_break);
11423 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011424}
11425
11426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011427RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011428 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011429 ASSERT(args.length() == 1);
11430
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011431 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011432 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433 // Find the number of break points
11434 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011435 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011438 Handle<FixedArray>::cast(break_locations));
11439}
11440
11441
11442// Set a break point in a function
11443// args[0]: function
11444// args[1]: number: break source position (within the function source)
11445// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011446RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011447 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011448 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011449 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011450 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011451 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11452 RUNTIME_ASSERT(source_position >= 0);
11453 Handle<Object> break_point_object_arg = args.at<Object>(2);
11454
11455 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11457 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011459 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011460}
11461
11462
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11464 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011465 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 // Iterate the heap looking for SharedFunctionInfo generated from the
11467 // script. The inner most SharedFunctionInfo containing the source position
11468 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011469 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011470 // which is found is not compiled it is compiled and the heap is iterated
11471 // again as the compilation might create inner functions from the newly
11472 // compiled function and the actual requested break point might be in one of
11473 // these functions.
11474 bool done = false;
11475 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011476 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011477 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011479 { // Extra scope for iterator and no-allocation.
11480 isolate->heap()->EnsureHeapIsIterable();
11481 AssertNoAllocation no_alloc_during_heap_iteration;
11482 HeapIterator iterator;
11483 for (HeapObject* obj = iterator.next();
11484 obj != NULL; obj = iterator.next()) {
11485 if (obj->IsSharedFunctionInfo()) {
11486 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11487 if (shared->script() == *script) {
11488 // If the SharedFunctionInfo found has the requested script data and
11489 // contains the source position it is a candidate.
11490 int start_position = shared->function_token_position();
11491 if (start_position == RelocInfo::kNoPosition) {
11492 start_position = shared->start_position();
11493 }
11494 if (start_position <= position &&
11495 position <= shared->end_position()) {
11496 // If there is no candidate or this function is within the current
11497 // candidate this is the new candidate.
11498 if (target.is_null()) {
11499 target_start_position = start_position;
11500 target = shared;
11501 } else {
11502 if (target_start_position == start_position &&
11503 shared->end_position() == target->end_position()) {
11504 // If a top-level function contain only one function
11505 // declartion the source for the top-level and the
11506 // function is the same. In that case prefer the non
11507 // top-level function.
11508 if (!shared->is_toplevel()) {
11509 target_start_position = start_position;
11510 target = shared;
11511 }
11512 } else if (target_start_position <= start_position &&
11513 shared->end_position() <= target->end_position()) {
11514 // This containment check includes equality as a function
11515 // inside a top-level function can share either start or end
11516 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011517 target_start_position = start_position;
11518 target = shared;
11519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011520 }
11521 }
11522 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011523 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011524 } // End for loop.
11525 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011528 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 }
11530
11531 // If the candidate found is compiled we are done. NOTE: when lazy
11532 // compilation of inner functions is introduced some additional checking
11533 // needs to be done here to compile inner functions.
11534 done = target->is_compiled();
11535 if (!done) {
11536 // If the candidate is not compiled compile it to reveal any inner
11537 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011538 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011539 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011540 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541
11542 return *target;
11543}
11544
11545
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011546// Changes the state of a break point in a script and returns source position
11547// where break point was set. NOTE: Regarding performance see the NOTE for
11548// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549// args[0]: script to set break point in
11550// args[1]: number: break source position (within the script source)
11551// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011552RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011555 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011556 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11557 RUNTIME_ASSERT(source_position >= 0);
11558 Handle<Object> break_point_object_arg = args.at<Object>(2);
11559
11560 // Get the script from the script wrapper.
11561 RUNTIME_ASSERT(wrapper->value()->IsScript());
11562 Handle<Script> script(Script::cast(wrapper->value()));
11563
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011564 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011566 if (!result->IsUndefined()) {
11567 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11568 // Find position within function. The script position might be before the
11569 // source position of the first function.
11570 int position;
11571 if (shared->start_position() > source_position) {
11572 position = 0;
11573 } else {
11574 position = source_position - shared->start_position();
11575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011577 position += shared->start_position();
11578 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581}
11582
11583
11584// Clear a break point
11585// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011586RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588 ASSERT(args.length() == 1);
11589 Handle<Object> break_point_object_arg = args.at<Object>(0);
11590
11591 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011592 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011595}
11596
11597
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011598// Change the state of break on exceptions.
11599// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11600// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011601RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011603 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011604 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011605 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011606
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011607 // If the number doesn't match an enum value, the ChangeBreakOnException
11608 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011609 ExceptionBreakType type =
11610 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011611 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 isolate->debug()->ChangeBreakOnException(type, enable);
11613 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011614}
11615
11616
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011617// Returns the state of break on exceptions
11618// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011619RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011621 ASSERT(args.length() == 1);
11622 RUNTIME_ASSERT(args[0]->IsNumber());
11623
11624 ExceptionBreakType type =
11625 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011627 return Smi::FromInt(result);
11628}
11629
11630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631// Prepare for stepping
11632// args[0]: break id for checking execution state
11633// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011634// args[2]: number of times to perform the step, for step out it is the number
11635// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011636RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011638 ASSERT(args.length() == 3);
11639 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011640 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011641 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11642 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011643 if (!maybe_check->ToObject(&check)) return maybe_check;
11644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 }
11648
11649 // Get the step action and check validity.
11650 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11651 if (step_action != StepIn &&
11652 step_action != StepNext &&
11653 step_action != StepOut &&
11654 step_action != StepInMin &&
11655 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657 }
11658
11659 // Get the number of steps.
11660 int step_count = NumberToInt32(args[2]);
11661 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011663 }
11664
ager@chromium.orga1645e22009-09-09 19:27:10 +000011665 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011666 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011668 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11670 step_count);
11671 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672}
11673
11674
11675// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011677 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011678 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 isolate->debug()->ClearStepping();
11680 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681}
11682
11683
11684// Creates a copy of the with context chain. The copy of the context chain is
11685// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011686static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11687 Handle<JSFunction> function,
11688 Handle<Context> base,
11689 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011690 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011691 HandleScope scope(isolate);
11692 List<Handle<ScopeInfo> > scope_chain;
11693 List<Handle<Context> > context_chain;
11694
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011695 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011696 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11697 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11698 ASSERT(!it.Done());
11699 scope_chain.Add(it.CurrentScopeInfo());
11700 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011701 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011702
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011703 // At the end of the chain. Return the base context to link to.
11704 Handle<Context> context = base;
11705
11706 // Iteratively copy and or materialize the nested contexts.
11707 while (!scope_chain.is_empty()) {
11708 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11709 Handle<Context> current = context_chain.RemoveLast();
11710 ASSERT(!(scope_info->HasContext() & current.is_null()));
11711
11712 if (scope_info->Type() == CATCH_SCOPE) {
11713 Handle<String> name(String::cast(current->extension()));
11714 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11715 context =
11716 isolate->factory()->NewCatchContext(function,
11717 context,
11718 name,
11719 thrown_object);
11720 } else if (scope_info->Type() == BLOCK_SCOPE) {
11721 // Materialize the contents of the block scope into a JSObject.
11722 Handle<JSObject> block_scope_object =
11723 MaterializeBlockScope(isolate, current);
11724 if (block_scope_object.is_null()) {
11725 return Handle<Context>::null();
11726 }
11727 // Allocate a new function context for the debug evaluation and set the
11728 // extension object.
11729 Handle<Context> new_context =
11730 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11731 function);
11732 new_context->set_extension(*block_scope_object);
11733 new_context->set_previous(*context);
11734 context = new_context;
11735 } else {
11736 ASSERT(scope_info->Type() == WITH_SCOPE);
11737 ASSERT(current->IsWithContext());
11738 Handle<JSObject> extension(JSObject::cast(current->extension()));
11739 context =
11740 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011741 }
erikcorry0ad885c2011-11-21 13:51:57 +000011742 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011743
11744 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745}
11746
11747
11748// Helper function to find or create the arguments object for
11749// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011750static Handle<Object> GetArgumentsObject(Isolate* isolate,
11751 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011752 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011753 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 Handle<Context> function_context) {
11755 // Try to find the value of 'arguments' to pass as parameter. If it is not
11756 // found (that is the debugged function does not reference 'arguments' and
11757 // does not support eval) then create an 'arguments' object.
11758 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011759 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011761 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011762 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 }
11764 }
11765
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011766 if (scope_info->HasHeapAllocatedLocals()) {
11767 VariableMode mode;
11768 InitializationFlag init_flag;
11769 index = scope_info->ContextSlotIndex(
11770 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011772 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011773 }
11774 }
11775
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011776 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11777 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011778 Handle<JSObject> arguments =
11779 isolate->factory()->NewArgumentsObject(function, length);
11780 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011781
11782 AssertNoAllocation no_gc;
11783 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011785 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011787 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011788 return arguments;
11789}
11790
11791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011792static const char kSourceStr[] =
11793 "(function(arguments,__source__){return eval(__source__);})";
11794
11795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011796// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011797// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798// extension part has all the parameters and locals of the function on the
11799// stack frame. A function which calls eval with the code to evaluate is then
11800// compiled in this context and called in this context. As this context
11801// replaces the context of the function on the stack frame a new (empty)
11802// function is created as well to be used as the closure for the context.
11803// This function and the context acts as replacements for the function on the
11804// stack frame presenting the same view of the values of parameters and
11805// local variables as if the piece of JavaScript was evaluated at the point
11806// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011807RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011808 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809
11810 // Check the execution state and decode arguments frame and source to be
11811 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011812 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011813 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011814 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11815 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011816 if (!maybe_check_result->ToObject(&check_result)) {
11817 return maybe_check_result;
11818 }
11819 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011820 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011821 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011822 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11823 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011824 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011825
11826 // Handle the processing of break.
11827 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828
11829 // Get the frame where the debugging is performed.
11830 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011831 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011832 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011833 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11834 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011835 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836
11837 // Traverse the saved contexts chain to find the active context for the
11838 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011839 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11840
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011841 SaveContext savex(isolate);
11842 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843
11844 // Create the (empty) function replacing the function on the stack frame for
11845 // the purpose of evaluating in the context created below. It is important
11846 // that this function does not describe any parameters and local variables
11847 // in the context. If it does then this will cause problems with the lookup
11848 // in Context::Lookup, where context slots for parameters and local variables
11849 // are looked at before the extension object.
11850 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11852 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853 go_between->set_context(function->context());
11854#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011855 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11856 ASSERT(go_between_scope_info->ParameterCount() == 0);
11857 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858#endif
11859
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011860 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011861 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11862 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864
11865 // Allocate a new context for the debug evaluation and set the extension
11866 // object build.
11867 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011868 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11869 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011870 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011872 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011873 Handle<Context> function_context;
11874 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011875 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011876 function_context = Handle<Context>(frame_context->declaration_context());
11877 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011878 context = CopyNestedScopeContextChain(isolate,
11879 go_between,
11880 context,
11881 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011882 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011884 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011885 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011886 context =
11887 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011888 }
11889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 // Wrap the evaluation statement in a new function compiled in the newly
11891 // created context. The function has one parameter which has to be called
11892 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011893 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011897 isolate->factory()->NewStringFromAscii(
11898 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011899
11900 // Currently, the eval code will be executed in non-strict mode,
11901 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011902 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011903 Compiler::CompileEval(function_source,
11904 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011905 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011906 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011907 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011908 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911
11912 // Invoke the result of the compilation to get the evaluation function.
11913 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 Handle<Object> evaluation_function =
11916 Execution::Call(compiled_function, receiver, 0, NULL,
11917 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011918 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011919
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011920 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011921 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011922 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011923 scope_info,
11924 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925
11926 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011927 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011929 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11930 receiver,
11931 ARRAY_SIZE(argv),
11932 argv,
11933 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011934 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011935
11936 // Skip the global proxy as it has no properties and always delegates to the
11937 // real global object.
11938 if (result->IsJSGlobalProxy()) {
11939 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11940 }
11941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 return *result;
11943}
11944
11945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011946RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948
11949 // Check the execution state and decode arguments frame and source to be
11950 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011951 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011952 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011953 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11954 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011955 if (!maybe_check_result->ToObject(&check_result)) {
11956 return maybe_check_result;
11957 }
11958 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011959 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11960 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011961 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011962
11963 // Handle the processing of break.
11964 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011965
11966 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011969 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 top = top->prev();
11971 }
11972 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974 }
11975
11976 // Get the global context now set to the top context from before the
11977 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011978 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011980 bool is_global = true;
11981
11982 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011983 // Create a new with context with the additional context information between
11984 // the context of the debugged function and the eval code to be executed.
11985 context = isolate->factory()->NewWithContext(
11986 Handle<JSFunction>(context->closure()),
11987 context,
11988 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011989 is_global = false;
11990 }
11991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011993 // Currently, the eval code will be executed in non-strict mode,
11994 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011995 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011996 Compiler::CompileEval(source,
11997 context,
11998 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011999 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012000 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012001 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003 Handle<JSFunction>(
12004 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12005 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012006
12007 // Invoke the result of the compilation to get the evaluation function.
12008 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012010 Handle<Object> result =
12011 Execution::Call(compiled_function, receiver, 0, NULL,
12012 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012013 // Clear the oneshot breakpoints so that the debugger does not step further.
12014 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012015 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012016 return *result;
12017}
12018
12019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012020RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012021 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012025 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012026
12027 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012028 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012029 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12030 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12031 // because using
12032 // instances->set(i, *GetScriptWrapper(script))
12033 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012034 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012035 Handle<JSValue> wrapper = GetScriptWrapper(script);
12036 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012037 }
12038
12039 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040 Handle<JSObject> result =
12041 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012042 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043 return *result;
12044}
12045
12046
12047// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012048static int DebugReferencedBy(HeapIterator* iterator,
12049 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 Object* instance_filter, int max_references,
12051 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052 JSFunction* arguments_function) {
12053 NoHandleAllocation ha;
12054 AssertNoAllocation no_alloc;
12055
12056 // Iterate the heap.
12057 int count = 0;
12058 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012059 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012060 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 (max_references == 0 || count < max_references)) {
12062 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 if (heap_obj->IsJSObject()) {
12064 // Skip context extension objects and argument arrays as these are
12065 // checked in the context of functions using them.
12066 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012067 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068 obj->map()->constructor() == arguments_function) {
12069 continue;
12070 }
12071
12072 // Check if the JS object has a reference to the object looked for.
12073 if (obj->ReferencesObject(target)) {
12074 // Check instance filter if supplied. This is normally used to avoid
12075 // references from mirror objects (see Runtime_IsInPrototypeChain).
12076 if (!instance_filter->IsUndefined()) {
12077 Object* V = obj;
12078 while (true) {
12079 Object* prototype = V->GetPrototype();
12080 if (prototype->IsNull()) {
12081 break;
12082 }
12083 if (instance_filter == prototype) {
12084 obj = NULL; // Don't add this object.
12085 break;
12086 }
12087 V = prototype;
12088 }
12089 }
12090
12091 if (obj != NULL) {
12092 // Valid reference found add to instance array if supplied an update
12093 // count.
12094 if (instances != NULL && count < instances_size) {
12095 instances->set(count, obj);
12096 }
12097 last = obj;
12098 count++;
12099 }
12100 }
12101 }
12102 }
12103
12104 // Check for circular reference only. This can happen when the object is only
12105 // referenced from mirrors and has a circular reference in which case the
12106 // object is not really alive and would have been garbage collected if not
12107 // referenced from the mirror.
12108 if (count == 1 && last == target) {
12109 count = 0;
12110 }
12111
12112 // Return the number of referencing objects found.
12113 return count;
12114}
12115
12116
12117// Scan the heap for objects with direct references to an object
12118// args[0]: the object to find references to
12119// args[1]: constructor function for instances to exclude (Mirror)
12120// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012121RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 ASSERT(args.length() == 3);
12123
12124 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012125 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12126 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012127 // The heap iterator reserves the right to do a GC to make the heap iterable.
12128 // Due to the GC above we know it won't need to do that, but it seems cleaner
12129 // to get the heap iterator constructed before we start having unprotected
12130 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131
12132 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012133 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 Object* instance_filter = args[1];
12135 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12136 instance_filter->IsJSObject());
12137 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12138 RUNTIME_ASSERT(max_references >= 0);
12139
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144 JSFunction* arguments_function =
12145 JSFunction::cast(arguments_boilerplate->map()->constructor());
12146
12147 // Get the number of referencing objects.
12148 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012149 HeapIterator heap_iterator;
12150 count = DebugReferencedBy(&heap_iterator,
12151 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012152 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153
12154 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012155 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012157 if (!maybe_object->ToObject(&object)) return maybe_object;
12158 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159 FixedArray* instances = FixedArray::cast(object);
12160
12161 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012162 // AllocateFixedArray above does not make the heap non-iterable.
12163 ASSERT(HEAP->IsHeapIterable());
12164 HeapIterator heap_iterator2;
12165 count = DebugReferencedBy(&heap_iterator2,
12166 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012167 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168
12169 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012170 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012171 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012173 if (!maybe_result->ToObject(&result)) return maybe_result;
12174 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175}
12176
12177
12178// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012179static int DebugConstructedBy(HeapIterator* iterator,
12180 JSFunction* constructor,
12181 int max_references,
12182 FixedArray* instances,
12183 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 AssertNoAllocation no_alloc;
12185
12186 // Iterate the heap.
12187 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012188 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012189 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012190 (max_references == 0 || count < max_references)) {
12191 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012192 if (heap_obj->IsJSObject()) {
12193 JSObject* obj = JSObject::cast(heap_obj);
12194 if (obj->map()->constructor() == constructor) {
12195 // Valid reference found add to instance array if supplied an update
12196 // count.
12197 if (instances != NULL && count < instances_size) {
12198 instances->set(count, obj);
12199 }
12200 count++;
12201 }
12202 }
12203 }
12204
12205 // Return the number of referencing objects found.
12206 return count;
12207}
12208
12209
12210// Scan the heap for objects constructed by a specific function.
12211// args[0]: the constructor to find instances of
12212// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012213RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012214 ASSERT(args.length() == 2);
12215
12216 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012217 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12218 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219
12220 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012221 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12223 RUNTIME_ASSERT(max_references >= 0);
12224
12225 // Get the number of referencing objects.
12226 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012227 HeapIterator heap_iterator;
12228 count = DebugConstructedBy(&heap_iterator,
12229 constructor,
12230 max_references,
12231 NULL,
12232 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233
12234 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012235 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012236 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012237 if (!maybe_object->ToObject(&object)) return maybe_object;
12238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012239 FixedArray* instances = FixedArray::cast(object);
12240
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012241 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012243 HeapIterator heap_iterator2;
12244 count = DebugConstructedBy(&heap_iterator2,
12245 constructor,
12246 max_references,
12247 instances,
12248 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249
12250 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012251 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12253 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012254 if (!maybe_result->ToObject(&result)) return maybe_result;
12255 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012256 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012257}
12258
12259
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012260// Find the effective prototype object as returned by __proto__.
12261// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012262RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 ASSERT(args.length() == 1);
12264
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012265 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012266
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012267 // Use the __proto__ accessor.
12268 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269}
12270
12271
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012272// Patches script source (should be called upon BeforeCompile event).
12273RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12274 HandleScope scope(isolate);
12275 ASSERT(args.length() == 2);
12276
12277 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12278 Handle<String> source(String::cast(args[1]));
12279
12280 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12281 Handle<Script> script(Script::cast(script_wrapper->value()));
12282
12283 int compilation_state = Smi::cast(script->compilation_state())->value();
12284 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12285 script->set_source(*source);
12286
12287 return isolate->heap()->undefined_value();
12288}
12289
12290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012291RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012292 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012293 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012294 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012295}
12296
12297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012298RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012299#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012300 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012301 ASSERT(args.length() == 1);
12302 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012303 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012304 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012305 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012306 return Failure::Exception();
12307 }
12308 func->code()->PrintLn();
12309#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012311}
ager@chromium.org9085a012009-05-11 19:22:57 +000012312
12313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012315#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012316 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012317 ASSERT(args.length() == 1);
12318 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012319 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012320 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012321 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012322 return Failure::Exception();
12323 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012324 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012325#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012326 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012327}
12328
12329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012330RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012331 NoHandleAllocation ha;
12332 ASSERT(args.length() == 1);
12333
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012334 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012335 return f->shared()->inferred_name();
12336}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012337
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012338
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012339static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12340 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012341 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012342 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012343 int counter = 0;
12344 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012345 for (HeapObject* obj = iterator->next();
12346 obj != NULL;
12347 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012348 ASSERT(obj != NULL);
12349 if (!obj->IsSharedFunctionInfo()) {
12350 continue;
12351 }
12352 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12353 if (shared->script() != script) {
12354 continue;
12355 }
12356 if (counter < buffer_size) {
12357 buffer->set(counter, shared);
12358 }
12359 counter++;
12360 }
12361 return counter;
12362}
12363
12364// For a script finds all SharedFunctionInfo's in the heap that points
12365// to this script. Returns JSArray of SharedFunctionInfo wrapped
12366// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012367RUNTIME_FUNCTION(MaybeObject*,
12368 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012369 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012371 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012372
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012373
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012374 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12375
12376 const int kBufferSize = 32;
12377
12378 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012380 int number;
12381 {
12382 isolate->heap()->EnsureHeapIsIterable();
12383 AssertNoAllocation no_allocations;
12384 HeapIterator heap_iterator;
12385 Script* scr = *script;
12386 FixedArray* arr = *array;
12387 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12388 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012389 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012390 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012391 isolate->heap()->EnsureHeapIsIterable();
12392 AssertNoAllocation no_allocations;
12393 HeapIterator heap_iterator;
12394 Script* scr = *script;
12395 FixedArray* arr = *array;
12396 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012397 }
12398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012400 result->set_length(Smi::FromInt(number));
12401
12402 LiveEdit::WrapSharedFunctionInfos(result);
12403
12404 return *result;
12405}
12406
12407// For a script calculates compilation information about all its functions.
12408// The script source is explicitly specified by the second argument.
12409// The source of the actual script is not used, however it is important that
12410// all generated code keeps references to this particular instance of script.
12411// Returns a JSArray of compilation infos. The array is ordered so that
12412// each function with all its descendant is always stored in a continues range
12413// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012414RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012415 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012417 CONVERT_ARG_CHECKED(JSValue, script, 0);
12418 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012419 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12420
12421 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012423 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424 return Failure::Exception();
12425 }
12426
12427 return result;
12428}
12429
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012430// Changes the source of the script to a new_source.
12431// If old_script_name is provided (i.e. is a String), also creates a copy of
12432// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012433RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012434 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012435 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012436 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12437 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012440 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12441 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012442
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012443 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12444 new_source,
12445 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012446
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012447 if (old_script->IsScript()) {
12448 Handle<Script> script_handle(Script::cast(old_script));
12449 return *(GetScriptWrapper(script_handle));
12450 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012452 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012453}
12454
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012456RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012457 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012458 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012459 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012460 return LiveEdit::FunctionSourceUpdated(shared_info);
12461}
12462
12463
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012464// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012465RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012466 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012468 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12469 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012470
ager@chromium.orgac091b72010-05-05 07:34:42 +000012471 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012472}
12473
12474// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012475RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012476 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012477 HandleScope scope(isolate);
12478 Handle<Object> function_object(args[0], isolate);
12479 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012480
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012481 if (function_object->IsJSValue()) {
12482 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12483 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012484 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12485 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012486 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012487 }
12488
12489 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12490 } else {
12491 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12492 // and we check it in this function.
12493 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012496}
12497
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012498
12499// In a code of a parent function replaces original function as embedded object
12500// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012501RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012502 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012503 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012504
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012505 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12506 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12507 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012508
12509 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12510 subst_wrapper);
12511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012513}
12514
12515
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012516// Updates positions of a shared function info (first parameter) according
12517// to script source change. Text change is described in second parameter as
12518// array of groups of 3 numbers:
12519// (change_begin, change_end, change_end_new_position).
12520// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012521RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012522 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012523 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012524 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12525 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012526
ager@chromium.orgac091b72010-05-05 07:34:42 +000012527 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012528}
12529
12530
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012531// For array of SharedFunctionInfo's (each wrapped in JSValue)
12532// checks that none of them have activations on stacks (of any thread).
12533// Returns array of the same length with corresponding results of
12534// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012535RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012536 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012537 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012538 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12539 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012540
ager@chromium.org357bf652010-04-12 11:30:10 +000012541 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012542}
12543
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012544// Compares 2 strings line-by-line, then token-wise and returns diff in form
12545// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12546// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012547RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012548 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012550 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12551 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012552
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012553 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012554}
12555
12556
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012557// A testing entry. Returns statement position which is the closest to
12558// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012559RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012560 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012562 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012563 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012565 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012566
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012567 if (code->kind() != Code::FUNCTION &&
12568 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012570 }
12571
12572 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012573 int closest_pc = 0;
12574 int distance = kMaxInt;
12575 while (!it.done()) {
12576 int statement_position = static_cast<int>(it.rinfo()->data());
12577 // Check if this break point is closer that what was previously found.
12578 if (source_position <= statement_position &&
12579 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012580 closest_pc =
12581 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012582 distance = statement_position - source_position;
12583 // Check whether we can't get any closer.
12584 if (distance == 0) break;
12585 }
12586 it.next();
12587 }
12588
12589 return Smi::FromInt(closest_pc);
12590}
12591
12592
ager@chromium.org357bf652010-04-12 11:30:10 +000012593// Calls specified function with or without entering the debugger.
12594// This is used in unit tests to run code as if debugger is entered or simply
12595// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012596RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012597 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012598 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012599 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12600 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012601
12602 Handle<Object> result;
12603 bool pending_exception;
12604 {
12605 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012606 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012607 &pending_exception);
12608 } else {
12609 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012611 &pending_exception);
12612 }
12613 }
12614 if (!pending_exception) {
12615 return *result;
12616 } else {
12617 return Failure::Exception();
12618 }
12619}
12620
12621
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012622// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012623RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012624 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012625 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012626 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12627 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012629}
12630
12631
12632// Performs a GC.
12633// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012634RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012635 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012637}
12638
12639
12640// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012641RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012642 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012643 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012644 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012645 }
12646 return Smi::FromInt(usage);
12647}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012648
12649
12650// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012651RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012652#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012653 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012654#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012655 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012656#endif
12657}
12658
12659
12660// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012661RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012662#ifdef LIVE_OBJECT_LIST
12663 return LiveObjectList::Capture();
12664#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012665 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012666#endif
12667}
12668
12669
12670// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012671RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012672#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012673 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012674 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012675 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012676#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012677 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012678#endif
12679}
12680
12681
12682// Generates the response to a debugger request for a dump of the objects
12683// contained in the difference between the captured live object lists
12684// specified by id1 and id2.
12685// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12686// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012687RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012688#ifdef LIVE_OBJECT_LIST
12689 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012690 CONVERT_SMI_ARG_CHECKED(id1, 0);
12691 CONVERT_SMI_ARG_CHECKED(id2, 1);
12692 CONVERT_SMI_ARG_CHECKED(start, 2);
12693 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012694 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012695 EnterDebugger enter_debugger;
12696 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12697#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012698 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012699#endif
12700}
12701
12702
12703// Gets the specified object as requested by the debugger.
12704// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012705RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012706#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012707 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708 Object* result = LiveObjectList::GetObj(obj_id);
12709 return result;
12710#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012711 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#endif
12713}
12714
12715
12716// Gets the obj id for the specified address if valid.
12717// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012718RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012719#ifdef LIVE_OBJECT_LIST
12720 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012721 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012722 Object* result = LiveObjectList::GetObjId(address);
12723 return result;
12724#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012725 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012726#endif
12727}
12728
12729
12730// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012731RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012732#ifdef LIVE_OBJECT_LIST
12733 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012734 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012735 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12736 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12737 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12738 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012739 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012740
12741 Handle<JSObject> instance_filter;
12742 if (args[1]->IsJSObject()) {
12743 instance_filter = args.at<JSObject>(1);
12744 }
12745 bool verbose = false;
12746 if (args[2]->IsBoolean()) {
12747 verbose = args[2]->IsTrue();
12748 }
12749 int start = 0;
12750 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012751 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012752 }
12753 int limit = Smi::kMaxValue;
12754 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012755 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012756 }
12757
12758 return LiveObjectList::GetObjRetainers(obj_id,
12759 instance_filter,
12760 verbose,
12761 start,
12762 limit,
12763 filter_obj);
12764#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012765 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012766#endif
12767}
12768
12769
12770// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012772#ifdef LIVE_OBJECT_LIST
12773 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012774 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12775 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012776 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12777
12778 Handle<JSObject> instance_filter;
12779 if (args[2]->IsJSObject()) {
12780 instance_filter = args.at<JSObject>(2);
12781 }
12782
12783 Object* result =
12784 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12785 return result;
12786#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012787 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012788#endif
12789}
12790
12791
12792// Generates the response to a debugger request for a list of all
12793// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012794RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012795#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012796 CONVERT_SMI_ARG_CHECKED(start, 0);
12797 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012798 return LiveObjectList::Info(start, count);
12799#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012801#endif
12802}
12803
12804
12805// Gets a dump of the specified object as requested by the debugger.
12806// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012807RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012808#ifdef LIVE_OBJECT_LIST
12809 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012810 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012811 Object* result = LiveObjectList::PrintObj(obj_id);
12812 return result;
12813#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012815#endif
12816}
12817
12818
12819// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012821#ifdef LIVE_OBJECT_LIST
12822 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012824#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012826#endif
12827}
12828
12829
12830// Generates the response to a debugger request for a summary of the types
12831// of objects in the difference between the captured live object lists
12832// specified by id1 and id2.
12833// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12834// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012835RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012836#ifdef LIVE_OBJECT_LIST
12837 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012838 CONVERT_SMI_ARG_CHECKED(id1, 0);
12839 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012840 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012841
12842 EnterDebugger enter_debugger;
12843 return LiveObjectList::Summarize(id1, id2, filter_obj);
12844#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012845 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012846#endif
12847}
12848
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012849#endif // ENABLE_DEBUGGER_SUPPORT
12850
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012852RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012853 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012854 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012855 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012856}
12857
12858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012859RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012860 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012861 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012862 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012863}
12864
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012866// Finds the script object from the script data. NOTE: This operation uses
12867// heap traversal to find the function generated for the source position
12868// for the requested break point. For lazily compiled functions several heap
12869// traversals might be required rendering this operation as a rather slow
12870// operation. However for setting break points which is normally done through
12871// some kind of user interaction the performance is not crucial.
12872static Handle<Object> Runtime_GetScriptFromScriptName(
12873 Handle<String> script_name) {
12874 // Scan the heap for Script objects to find the script with the requested
12875 // script data.
12876 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012877 script_name->GetHeap()->EnsureHeapIsIterable();
12878 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012880 HeapObject* obj = NULL;
12881 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012882 // If a script is found check if it has the script data requested.
12883 if (obj->IsScript()) {
12884 if (Script::cast(obj)->name()->IsString()) {
12885 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12886 script = Handle<Script>(Script::cast(obj));
12887 }
12888 }
12889 }
12890 }
12891
12892 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012894
12895 // Return the script found.
12896 return GetScriptWrapper(script);
12897}
12898
12899
12900// Get the script object from script data. NOTE: Regarding performance
12901// see the NOTE for GetScriptFromScriptData.
12902// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012903RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012904 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012905
12906 ASSERT(args.length() == 1);
12907
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012908 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012909
12910 // Find the requested script.
12911 Handle<Object> result =
12912 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12913 return *result;
12914}
12915
12916
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012917// Determines whether the given stack frame should be displayed in
12918// a stack trace. The caller is the error constructor that asked
12919// for the stack trace to be collected. The first time a construct
12920// call to this function is encountered it is skipped. The seen_caller
12921// in/out parameter is used to remember if the caller has been seen
12922// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012923static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12924 Object* caller,
12925 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012926 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012927 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012928 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012929 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012930 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12931 Object* raw_fun = frame->function();
12932 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012933 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012934 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012935 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012936 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012937 *seen_caller = true;
12938 return false;
12939 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012940 // Skip all frames until we've seen the caller.
12941 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012942 // Also, skip non-visible built-in functions and any call with the builtins
12943 // object as receiver, so as to not reveal either the builtins object or
12944 // an internal function.
12945 // The --builtins-in-stack-traces command line flag allows including
12946 // internal call sites in the stack trace for debugging purposes.
12947 if (!FLAG_builtins_in_stack_traces) {
12948 JSFunction* fun = JSFunction::cast(raw_fun);
12949 if (frame->receiver()->IsJSBuiltinsObject() ||
12950 (fun->IsBuiltin() && !fun->shared()->native())) {
12951 return false;
12952 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012953 }
12954 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012955}
12956
12957
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012958// Collect the raw data for a stack trace. Returns an array of 4
12959// element segments each containing a receiver, function, code and
12960// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012961RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012962 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012963 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012964 Handle<Object> caller = args.at<Object>(1);
12965 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012966
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012967 HandleScope scope(isolate);
12968 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012969
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012970 limit = Max(limit, 0); // Ensure that limit is not negative.
12971 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012972 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012973 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012974
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012975 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012976 // If the caller parameter is a function we skip frames until we're
12977 // under it before starting to collect.
12978 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012979 int cursor = 0;
12980 int frames_seen = 0;
12981 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012982 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012983 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012984 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012985 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012986 // Set initial size to the maximum inlining level + 1 for the outermost
12987 // function.
12988 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012989 frame->Summarize(&frames);
12990 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012991 if (cursor + 4 > elements->length()) {
12992 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12993 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012994 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012995 for (int i = 0; i < cursor; i++) {
12996 new_elements->set(i, elements->get(i));
12997 }
12998 elements = new_elements;
12999 }
13000 ASSERT(cursor + 4 <= elements->length());
13001
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013002 Handle<Object> recv = frames[i].receiver();
13003 Handle<JSFunction> fun = frames[i].function();
13004 Handle<Code> code = frames[i].code();
13005 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013006 elements->set(cursor++, *recv);
13007 elements->set(cursor++, *fun);
13008 elements->set(cursor++, *code);
13009 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013010 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013011 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013012 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013013 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013014 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013015 // Capture and attach a more detailed stack trace if necessary.
13016 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013017 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013018 return *result;
13019}
13020
13021
ager@chromium.org3811b432009-10-28 14:53:37 +000013022// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013023RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013024 ASSERT_EQ(args.length(), 0);
13025
13026 NoHandleAllocation ha;
13027
13028 const char* version_string = v8::V8::GetVersion();
13029
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013030 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13031 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013032}
13033
13034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013035RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013036 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013037 OS::PrintError("abort: %s\n",
13038 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013039 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013040 OS::Abort();
13041 UNREACHABLE();
13042 return NULL;
13043}
13044
13045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013046RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013047 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013048 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013049 Object* key = args[1];
13050
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013051 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013052 Object* o = cache->get(finger_index);
13053 if (o == key) {
13054 // The fastest case: hit the same place again.
13055 return cache->get(finger_index + 1);
13056 }
13057
13058 for (int i = finger_index - 2;
13059 i >= JSFunctionResultCache::kEntriesIndex;
13060 i -= 2) {
13061 o = cache->get(i);
13062 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013063 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013064 return cache->get(i + 1);
13065 }
13066 }
13067
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013068 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013069 ASSERT(size <= cache->length());
13070
13071 for (int i = size - 2; i > finger_index; i -= 2) {
13072 o = cache->get(i);
13073 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013074 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013075 return cache->get(i + 1);
13076 }
13077 }
13078
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013079 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013080 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013081
13082 Handle<JSFunctionResultCache> cache_handle(cache);
13083 Handle<Object> key_handle(key);
13084 Handle<Object> value;
13085 {
13086 Handle<JSFunction> factory(JSFunction::cast(
13087 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13088 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013089 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013090 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013091 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013092 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013093 value = Execution::Call(factory,
13094 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013095 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013096 argv,
13097 &pending_exception);
13098 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013099 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013100
13101#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013102 if (FLAG_verify_heap) {
13103 cache_handle->JSFunctionResultCacheVerify();
13104 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013105#endif
13106
13107 // Function invocation may have cleared the cache. Reread all the data.
13108 finger_index = cache_handle->finger_index();
13109 size = cache_handle->size();
13110
13111 // If we have spare room, put new data into it, otherwise evict post finger
13112 // entry which is likely to be the least recently used.
13113 int index = -1;
13114 if (size < cache_handle->length()) {
13115 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13116 index = size;
13117 } else {
13118 index = finger_index + JSFunctionResultCache::kEntrySize;
13119 if (index == cache_handle->length()) {
13120 index = JSFunctionResultCache::kEntriesIndex;
13121 }
13122 }
13123
13124 ASSERT(index % 2 == 0);
13125 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13126 ASSERT(index < cache_handle->length());
13127
13128 cache_handle->set(index, *key_handle);
13129 cache_handle->set(index + 1, *value);
13130 cache_handle->set_finger_index(index);
13131
13132#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013133 if (FLAG_verify_heap) {
13134 cache_handle->JSFunctionResultCacheVerify();
13135 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013136#endif
13137
13138 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013139}
13140
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013142RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013143 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013144 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13145 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013146 return *isolate->factory()->NewJSMessageObject(
13147 type,
13148 arguments,
13149 0,
13150 0,
13151 isolate->factory()->undefined_value(),
13152 isolate->factory()->undefined_value(),
13153 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013154}
13155
13156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013157RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013158 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013159 return message->type();
13160}
13161
13162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013163RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013164 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013165 return message->arguments();
13166}
13167
13168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013169RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013170 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013171 return Smi::FromInt(message->start_position());
13172}
13173
13174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013175RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013176 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013177 return message->script();
13178}
13179
13180
kasper.lund44510672008-07-25 07:37:58 +000013181#ifdef DEBUG
13182// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13183// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013184RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013185 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013186 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013187#define COUNT_ENTRY(Name, argc, ressize) + 1
13188 int entry_count = 0
13189 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13190 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13191 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13192#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013193 Factory* factory = isolate->factory();
13194 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013195 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013196 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013197#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013198 { \
13199 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013200 Handle<String> name; \
13201 /* Inline runtime functions have an underscore in front of the name. */ \
13202 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013203 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013204 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13205 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013206 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013207 Vector<const char>(#Name, StrLength(#Name))); \
13208 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013209 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013210 pair_elements->set(0, *name); \
13211 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013212 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013213 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013214 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013215 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013216 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013217 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013218 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013219 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013220#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013221 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013222 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013223 return *result;
13224}
kasper.lund44510672008-07-25 07:37:58 +000013225#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013226
13227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013228RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013229 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013230 CONVERT_ARG_CHECKED(String, format, 0);
13231 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013232 String::FlatContent format_content = format->GetFlatContent();
13233 RUNTIME_ASSERT(format_content.IsAscii());
13234 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013235 LOGGER->LogRuntime(chars, elms);
13236 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013237}
13238
13239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013240RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013241 UNREACHABLE(); // implemented as macro in the parser
13242 return NULL;
13243}
13244
13245
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013246#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13247 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013248 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013249 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13250 }
13251
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013252ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013253ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13254ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13255ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13256ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13257ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13258ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13259ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13260ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13261ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13262ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13263ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13264ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13265ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13266
13267#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13268
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013269
13270RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13271 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013272 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13273 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013274 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13275}
13276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013277// ----------------------------------------------------------------------------
13278// Implementation of Runtime
13279
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013280#define F(name, number_of_args, result_size) \
13281 { Runtime::k##name, Runtime::RUNTIME, #name, \
13282 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013283
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013284
13285#define I(name, number_of_args, result_size) \
13286 { Runtime::kInline##name, Runtime::INLINE, \
13287 "_" #name, NULL, number_of_args, result_size },
13288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013289static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013290 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013291 INLINE_FUNCTION_LIST(I)
13292 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013293};
13294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013296MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13297 Object* dictionary) {
13298 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013299 ASSERT(dictionary != NULL);
13300 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13301 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013302 Object* name_symbol;
13303 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013304 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013305 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13306 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013307 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013308 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13309 String::cast(name_symbol),
13310 Smi::FromInt(i),
13311 PropertyDetails(NONE, NORMAL));
13312 if (!maybe_dictionary->ToObject(&dictionary)) {
13313 // Non-recoverable failure. Calling code must restart heap
13314 // initialization.
13315 return maybe_dictionary;
13316 }
13317 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013318 }
13319 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013320}
13321
13322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013323const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13324 Heap* heap = name->GetHeap();
13325 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013326 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013327 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013328 int function_index = Smi::cast(smi_index)->value();
13329 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013330 }
13331 return NULL;
13332}
13333
13334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013335const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013336 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13337}
13338
13339
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013340void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013341 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013342 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013343 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013344 if (isolate->heap()->new_space()->AddFreshPage()) {
13345 return;
13346 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013347
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013348 // Try to do a garbage collection; ignore it if it fails. The C
13349 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013350 isolate->heap()->CollectGarbage(failure->allocation_space(),
13351 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013352 } else {
13353 // Handle last resort GC and make sure to allow future allocations
13354 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013355 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013356 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13357 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013358 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013359}
13360
13361
13362} } // namespace v8::internal